Decompiled source of Stavebound v1.2.1

plugins\Stavebound.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Splatform;
using Stavebound.Compat;
using Stavebound.Config;
using Stavebound.Portals;
using Stavebound.Staves;
using Stavebound.Tiers;
using Stavebound.Travel;
using Stavebound.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("recognizerHD")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 recognizerHD")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1+e2296992736910d3a3f115da5a61f1ce3e934cf4")]
[assembly: AssemblyProduct("Stavebound")]
[assembly: AssemblyTitle("Stavebound")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/recognizerHD/stave-bound")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: AssemblyVersion("1.2.1.0")]
namespace Stavebound
{
	internal static class BuildInfo
	{
		internal const string Guid = "com.recognizerhd.stavebound";

		internal const string Name = "Stavebound";

		internal const string Version = "1.2.1";
	}
	[BepInPlugin("com.recognizerhd.stavebound", "Stavebound", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal sealed class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			Instance = this;
			StaveboundConfig.Bind(((BaseUnityPlugin)this).Config);
			SelectorKeys.Bind(((BaseUnityPlugin)this).Config);
			Translations.Add();
			StavePieces.Register();
			PortalRegistry.Register();
			_harmony = new Harmony("com.recognizerhd.stavebound");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			Logger.LogInfo((object)"Stavebound 1.2.1 loaded.");
		}

		private void Start()
		{
			ConflictDetector.WarnAboutKnownConflicts();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			Instance = null;
		}
	}
}
namespace Stavebound.UI
{
	internal static class DestinationSelector
	{
		private enum SortOrder
		{
			Distance,
			Name
		}

		internal sealed class RowView
		{
			internal GameObject Root;

			internal Button Button;

			internal Text Name;

			internal Text Chips;

			internal int Candidate = -1;
		}

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

		private static readonly List<PinData> Pins = new List<PinData>();

		private const int VisibleRows = 9;

		private static ZDOID _sourceId;

		private static long _sourcePid;

		private static Vector3 _sourcePosition;

		private static string _sourceName;

		private static SortOrder _order = SortOrder.Distance;

		private static bool _onlyWhatAcceptsMyCargo;

		private static int _highlight;

		private static Clearance _carrying;

		private static Clearance _sourceMask;

		private static GameObject _panel;

		private static Text _title;

		private static Text _status;

		private static Dropdown _picker;

		private static Text _moreAbove;

		private static Text _moreBelow;

		private static readonly List<RowView> Rows = new List<RowView>();

		private static readonly List<Selectable> NeedsCandidates = new List<Selectable>();

		private static bool _pickerStale;

		private static float _wheel;

		private static int _wheelFrame = -1;

		private static float _lastWheelStep;

		private const float WheelInterval = 0.06f;

		private static long _homePid = 0L;

		private static PinData _homePin;

		private static readonly Color HomeColour = new Color(0.5f, 0.83f, 1f);

		private const string HomeHex = "#7FD4FF";

		private static RowView _hovered;

		private static bool _previewing;

		private static bool _updateSeen;

		private static readonly FieldRef<Dropdown, GameObject> PickerBlocker = AccessTools.FieldRefAccess<Dropdown, GameObject>("m_Blocker");

		private const float PanelHeight = 530f;

		private const float RowHeight = 28f;

		private const float ChipsWidth = 132f;

		private const float BaseInner = 400f;

		private const float PanelPadding = 40f;

		private const float PerNameCharacter = 3f;

		private const float MostExtraWidth = 70f;

		private static float Inner = 400f;

		private static float PanelWidth = 440f;

		internal static bool IsOpen { get; private set; }

		internal static void Open(TeleportWorld portal, Humanoid who)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			ZDO val = PortalTarget.ZdoOf(portal);
			if (val == null || (Object)(object)Minimap.instance == (Object)null)
			{
				return;
			}
			if (!ReaimGuard.MayReaim(((Component)portal).transform.position, out var refusal))
			{
				if (who != null)
				{
					((Character)who).Message((MessageType)2, refusal, 0, (Sprite)null, false);
				}
				return;
			}
			_sourceId = val.m_uid;
			long pid = PortalTarget.GetPid(val);
			string text = val.GetString(ZDOVars.s_tag, string.Empty);
			_sourceName = (string.IsNullOrEmpty(text) ? "this portal" : ("\"" + text + "\""));
			_sourcePosition = ((Component)portal).transform.position;
			_sourcePid = pid;
			_sourceMask = ClearanceGate.MaskOf(val);
			_carrying = CarriedTiers((Player)(object)((who is Player) ? who : null));
			_homePid = NearestToHome();
			_onlyWhatAcceptsMyCargo = false;
			Rebuild(0L);
			if (Candidates.Count == 0)
			{
				if (who != null)
				{
					((Character)who).Message((MessageType)2, Translations.Get("stave_sel_nowhere"), 0, (Sprite)null, false);
				}
				return;
			}
			long current = PortalTarget.GetDestination(val);
			_highlight = Candidates.FindIndex((PortalRecord p) => p.Pid == current);
			if (_highlight < 0)
			{
				_highlight = 0;
			}
			AddPins();
			BuildPanel();
			IsOpen = true;
			_updateSeen = false;
			Minimap.instance.SetMapMode((MapMode)2);
			ShowHighlight();
			Logger.LogInfo((object)$"Selector opened for {_sourceName} with {Candidates.Count} destination(s).");
		}

		internal static void Update()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen)
			{
				return;
			}
			if (!_updateSeen)
			{
				_updateSeen = true;
				Logger.LogInfo((object)"Selector is receiving frames.");
			}
			if ((Object)(object)Minimap.instance == (Object)null || (int)Minimap.instance.m_mode != 2)
			{
				Close();
				return;
			}
			TintPins();
			if (PickerIsOpen())
			{
				if (Cancelled())
				{
					_picker.Hide();
				}
				return;
			}
			GameObject val = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
			if ((Object)(object)val != (Object)null && (Object)(object)_panel != (Object)null && val.transform.IsChildOf(_panel.transform))
			{
				Unfocus();
			}
			if (_previewing && _hovered == null)
			{
				_previewing = false;
				if (Candidates.Count > 0)
				{
					Minimap instance = Minimap.instance;
					if (instance != null)
					{
						instance.ShowPointOnMap(Candidates[_highlight].Position);
					}
				}
			}
			if (Cancelled())
			{
				Close();
				return;
			}
			if (Confirmed())
			{
				Commit();
				return;
			}
			if (SelectorKeys.Pressed("stave_filter"))
			{
				ToggleFilter();
				return;
			}
			if (SelectorKeys.Pressed("stave_sort"))
			{
				ToggleSort();
				return;
			}
			int num = Stepped();
			if (num != 0)
			{
				Step(num);
			}
			else
			{
				ScrollFromWheel();
			}
		}

		internal static bool OwnsWheel()
		{
			if (IsOpen && (Object)(object)_panel != (Object)null)
			{
				if (!PickerIsOpen())
				{
					if (StaveboundConfig.WheelScrollsList.Value)
					{
						return PointerOverPanel();
					}
					return false;
				}
				return true;
			}
			return false;
		}

		internal static void ReceiveWheel(float delta)
		{
			_wheel = delta;
			_wheelFrame = Time.frameCount;
		}

		private static void ScrollFromWheel()
		{
			if (StaveboundConfig.WheelScrollsList.Value && _wheelFrame == Time.frameCount && _wheel != 0f && Candidates.Count != 0 && !(Time.unscaledTime - _lastWheelStep < 0.06f) && PointerOverPanel())
			{
				_lastWheelStep = Time.unscaledTime;
				int num = Mathf.Clamp(_highlight + ((!(_wheel > 0f)) ? 1 : (-1)), 0, Candidates.Count - 1);
				if (num != _highlight)
				{
					_highlight = num;
					ShowHighlight();
				}
			}
		}

		private static bool PointerOverPanel()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panel == (Object)null)
			{
				return false;
			}
			Canvas componentInParent = _panel.GetComponentInParent<Canvas>();
			Canvas val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.rootCanvas : null);
			Camera val2 = (((Object)(object)val == (Object)null || (int)val.renderMode == 0) ? null : val.worldCamera);
			return RectTransformUtility.RectangleContainsScreenPoint(_panel.GetComponent<RectTransform>(), Vector2.op_Implicit(ZInput.pointerPosition), val2);
		}

		internal static void HoverEntered(RowView row)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen && StaveboundConfig.HoverPreviewsOnMap.Value && row != null && row.Candidate >= 0 && row.Candidate < Candidates.Count)
			{
				_hovered = row;
				_previewing = true;
				Minimap instance = Minimap.instance;
				if (instance != null)
				{
					instance.ShowPointOnMap(Candidates[row.Candidate].Position);
				}
			}
		}

		internal static void HoverLeft(RowView row)
		{
			if (_hovered == row)
			{
				_hovered = null;
			}
		}

		private static void Step(int step)
		{
			if (Candidates.Count != 0)
			{
				_highlight = (_highlight + step + Candidates.Count) % Candidates.Count;
				ShowHighlight();
			}
		}

		private static void ToggleFilter()
		{
			_onlyWhatAcceptsMyCargo = !_onlyWhatAcceptsMyCargo;
			Rebuild(Held());
			AddPins();
			ShowHighlight();
		}

		private static void ToggleSort()
		{
			_order = ((_order == SortOrder.Distance) ? SortOrder.Name : SortOrder.Distance);
			Rebuild(Held());
			ShowHighlight();
		}

		private static long Held()
		{
			if (_highlight < 0 || _highlight >= Candidates.Count)
			{
				return 0L;
			}
			return Candidates[_highlight].Pid;
		}

		private static void Rebuild(long keep)
		{
			Candidates.Clear();
			Candidates.AddRange(PortalRegistry.All.Where((PortalRecord p) => p.Pid != _sourcePid));
			if (_onlyWhatAcceptsMyCargo && _carrying != Clearance.None)
			{
				Candidates.RemoveAll((PortalRecord p) => !Accepts(p));
			}
			Sort();
			_pickerStale = true;
			_highlight = ((keep != 0L) ? Candidates.FindIndex((PortalRecord p) => p.Pid == keep) : 0);
			if (_highlight < 0)
			{
				_highlight = 0;
			}
		}

		private static void Sort()
		{
			if (_order == SortOrder.Name)
			{
				Candidates.Sort((PortalRecord a, PortalRecord b) => string.Compare(Describe(a), Describe(b), StringComparison.CurrentCultureIgnoreCase));
			}
			else
			{
				Candidates.Sort((PortalRecord a, PortalRecord b) => Vector3.Distance(_sourcePosition, a.Position).CompareTo(Vector3.Distance(_sourcePosition, b.Position)));
			}
		}

		internal static void SelectNear(Vector3 worldPoint, float radius)
		{
			//IL_002d: 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_0033: 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)
			if (!IsOpen || Candidates.Count == 0)
			{
				return;
			}
			int num = -1;
			float num2 = radius * radius;
			for (int i = 0; i < Candidates.Count; i++)
			{
				Vector3 val = Candidates[i].Position - worldPoint;
				val.y = 0f;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude <= num2)
				{
					num2 = sqrMagnitude;
					num = i;
				}
			}
			if (num >= 0)
			{
				_highlight = num;
				if (StaveboundConfig.MapClickPicksPortal.Value)
				{
					Commit();
				}
				else
				{
					ShowHighlight();
				}
			}
		}

		private static void Commit()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (Candidates.Count == 0)
			{
				return;
			}
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(_sourceId) : null);
			if (val == null)
			{
				Close();
				return;
			}
			PortalRecord portal = Candidates[_highlight];
			PortalTarget.Set(val, portal.Pid);
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, Translations.Format("stave_sel_aimed", _sourceName, Describe(portal)), 0, (Sprite)null, false);
			}
			Close();
		}

		internal static void Reset()
		{
			Close();
		}

		private static void Close()
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Invalid comparison between Unknown and I4
			IsOpen = false;
			RemovePins();
			if ((Object)(object)_panel != (Object)null)
			{
				Object.Destroy((Object)(object)_panel);
				_panel = null;
			}
			_title = null;
			_status = null;
			_picker = null;
			_moreAbove = null;
			_moreBelow = null;
			Rows.Clear();
			NeedsCandidates.Clear();
			_hovered = null;
			_previewing = false;
			_homePid = 0L;
			Candidates.Clear();
			if ((Object)(object)Minimap.instance != (Object)null && (int)Minimap.instance.m_mode == 2)
			{
				Minimap.instance.SetMapMode((MapMode)1);
			}
		}

		private static void AddPins()
		{
			//IL_0021: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			RemovePins();
			foreach (PortalRecord candidate in Candidates)
			{
				PinData val = Minimap.instance.AddPin(candidate.Position, (PinType)3, Describe(candidate), false, false, 0L, default(PlatformUserID));
				Pins.Add(val);
				if (candidate.Pid == _homePid)
				{
					_homePin = val;
				}
			}
		}

		private static void TintPins()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			bool value = StaveboundConfig.ColourPortalPins.Value;
			Color valheimOrange = GUIManager.Instance.ValheimOrange;
			foreach (PinData pin in Pins)
			{
				if (!((Object)(object)pin?.m_iconElement == (Object)null))
				{
					if (pin == _homePin)
					{
						((Graphic)pin.m_iconElement).color = HomeColour;
					}
					else if (value)
					{
						((Graphic)pin.m_iconElement).color = valheimOrange;
					}
				}
			}
		}

		private static void RemovePins()
		{
			foreach (PinData pin in Pins)
			{
				if (pin != null)
				{
					Minimap instance = Minimap.instance;
					if (instance != null)
					{
						instance.RemovePin(pin);
					}
				}
			}
			Pins.Clear();
			_homePin = null;
		}

		private static void ShowHighlight()
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panel == (Object)null)
			{
				return;
			}
			RefreshPicker();
			bool flag = Candidates.Count > 0;
			foreach (Selectable needsCandidate in NeedsCandidates)
			{
				needsCandidate.interactable = flag;
			}
			_title.text = Translations.Format("stave_sel_title", _sourceName);
			if (!flag)
			{
				_status.text = "<color=#E06C4A>" + Translations.Get("stave_sel_empty") + "</color>";
				_moreAbove.text = string.Empty;
				_moreBelow.text = string.Empty;
				foreach (RowView row in Rows)
				{
					row.Root.SetActive(false);
					row.Candidate = -1;
				}
				_hovered = null;
				return;
			}
			PortalRecord destination = Candidates[_highlight];
			Minimap instance = Minimap.instance;
			if (instance != null)
			{
				instance.ShowPointOnMap(destination.Position);
			}
			string text = Translations.Get((_order == SortOrder.Distance) ? "stave_sel_by_distance" : "stave_sel_by_name");
			string text2 = (_onlyWhatAcceptsMyCargo ? Translations.Get("stave_sel_filtered") : string.Empty);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(text + text2);
			string text3 = FlowNote();
			if (text3 != null)
			{
				stringBuilder.AppendLine("<color=#B9A67A>" + text3 + "</color>");
			}
			stringBuilder.Append(Verdict(destination));
			_status.text = stringBuilder.ToString();
			int num = Mathf.Clamp(_highlight - 4, 0, Mathf.Max(0, Candidates.Count - 9));
			int num2 = Mathf.Min(num + 9, Candidates.Count);
			_moreAbove.text = ((num > 0) ? Translations.Format("stave_sel_more_above", num) : string.Empty);
			_moreBelow.text = ((num2 < Candidates.Count) ? Translations.Format("stave_sel_more_below", Candidates.Count - num2) : string.Empty);
			for (int i = 0; i < Rows.Count; i++)
			{
				RowView rowView = Rows[i];
				int num3 = num + i;
				if (num3 >= num2)
				{
					rowView.Root.SetActive(false);
					rowView.Candidate = -1;
					if (_hovered == rowView)
					{
						_hovered = null;
					}
					continue;
				}
				PortalRecord portal = Candidates[num3];
				bool flag2 = num3 == _highlight;
				string text4 = $"{Describe(portal)}  <size=12>{Vector3.Distance(_sourcePosition, portal.Position):F0}m</size>";
				rowView.Candidate = num3;
				rowView.Root.SetActive(true);
				string text5 = ((portal.Pid == _homePid) ? "#7FD4FF" : (flag2 ? "#FFB726" : "#C9C0AC"));
				rowView.Name.text = (flag2 ? ("<color=#FFB726>» </color><color=" + text5 + ">" + text4 + "</color>") : ("<color=" + text5 + ">   " + text4 + "</color>"));
				rowView.Chips.text = Chips(portal);
				((Selectable)rowView.Button).colors = RowColours(flag2);
			}
		}

		private static void RefreshPicker()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_picker == (Object)null)
			{
				return;
			}
			if (_pickerStale)
			{
				_pickerStale = false;
				_picker.ClearOptions();
				List<string> list = new List<string>(Candidates.Count);
				foreach (PortalRecord candidate in Candidates)
				{
					list.Add($"{Describe(candidate)}   {Vector3.Distance(_sourcePosition, candidate.Position):F0}m");
				}
				if (list.Count == 0)
				{
					list.Add(Translations.Get("stave_sel_empty"));
				}
				_picker.AddOptions(list);
			}
			_picker.SetValueWithoutNotify((Candidates.Count != 0) ? _highlight : 0);
		}

		private static ColorBlock RowColours(bool current)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(1f, 1f, 1f, 0f);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 0.72f, 0.15f, 0.16f);
			ColorBlock result = default(ColorBlock);
			((ColorBlock)(ref result)).normalColor = (current ? val2 : val);
			((ColorBlock)(ref result)).highlightedColor = (current ? new Color(1f, 0.72f, 0.15f, 0.26f) : new Color(1f, 1f, 1f, 0.08f));
			((ColorBlock)(ref result)).pressedColor = new Color(1f, 0.72f, 0.15f, 0.32f);
			((ColorBlock)(ref result)).selectedColor = (current ? val2 : val);
			((ColorBlock)(ref result)).disabledColor = val;
			((ColorBlock)(ref result)).colorMultiplier = 1f;
			((ColorBlock)(ref result)).fadeDuration = 0.08f;
			return result;
		}

		private static bool PickerIsOpen()
		{
			if ((Object)(object)_picker != (Object)null)
			{
				return (Object)(object)PickerBlocker.Invoke(_picker) != (Object)null;
			}
			return false;
		}

		private static string Chips(PortalRecord portal)
		{
			Clearance clearanceMask = (Clearance)portal.ClearanceMask;
			StringBuilder stringBuilder = new StringBuilder("<size=12>");
			Clearance[] ladder = ClearanceExtensions.Ladder;
			foreach (Clearance clearance in ladder)
			{
				bool num = (clearanceMask & clearance) == clearance;
				bool flag = (_carrying & clearance) == clearance;
				if (num)
				{
					stringBuilder.Append(clearance.Symbol());
				}
				else if (flag)
				{
					stringBuilder.Append("<color=#E06C4A>" + clearance.Symbol() + "</color>");
				}
				else
				{
					stringBuilder.Append("··");
				}
				stringBuilder.Append(' ');
			}
			return stringBuilder.ToString().TrimEnd(Array.Empty<char>()) + "</size>";
		}

		private static string Verdict(PortalRecord destination)
		{
			if (_carrying == Clearance.None)
			{
				return "<size=13>" + Translations.Get("stave_sel_carrying_nothing") + "</size>";
			}
			int num = Candidates.Count(Accepts);
			string text = "<size=13>" + Translations.Format("stave_sel_tally", num, Candidates.Count) + "</size>";
			if (!Accepts(destination))
			{
				return "<size=13><color=#E06C4A>" + Translations.Get("stave_sel_refuses") + "</color></size>  " + text;
			}
			return "<size=13><color=#8FC97A>" + Translations.Get("stave_sel_takes") + "</color></size>  " + text;
		}

		private static string FlowNote()
		{
			return (StaveboundConfig.Flow?.Value ?? MaterialFlow.Both) switch
			{
				MaterialFlow.Both => Translations.Get("stave_sel_flow_both"), 
				MaterialFlow.Deliver => Translations.Get("stave_sel_flow_deliver"), 
				_ => null, 
			};
		}

		private static bool Accepts(PortalRecord portal)
		{
			return (ClearanceGate.EffectiveMask(_sourceMask, (Clearance)portal.ClearanceMask) & _carrying) == _carrying;
		}

		private static Clearance CarriedTiers(Player player)
		{
			Clearance clearance = Clearance.None;
			Inventory val = ((player != null) ? ((Humanoid)player).GetInventory() : null);
			if (val == null)
			{
				return clearance;
			}
			foreach (ItemData allItem in val.GetAllItems())
			{
				if (allItem?.m_shared != null && !allItem.m_shared.m_teleportable)
				{
					string prefabName = (((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null);
					clearance |= TierMap.RequiredFor(prefabName);
				}
			}
			return clearance;
		}

		private static string Bound(string button)
		{
			return SelectorKeys.KeyLabel(button);
		}

		private static long NearestToHome()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null);
			if (!StaveboundConfig.ColourHomePortal.Value || val == null || !val.HaveCustomSpawnPoint())
			{
				return 0L;
			}
			Vector3 customSpawnPoint = val.GetCustomSpawnPoint();
			long result = 0L;
			float num = float.MaxValue;
			foreach (PortalRecord item in PortalRegistry.All)
			{
				Vector3 val2 = item.Position - customSpawnPoint;
				val2.y = 0f;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					result = item.Pid;
				}
			}
			return result;
		}

		private static string Describe(PortalRecord portal)
		{
			//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_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)
			if (StaveboundConfig.HidePortalNames.Value)
			{
				return Translations.Format("stave_portal_at", portal.Position.x.ToString("F0"), portal.Position.z.ToString("F0"));
			}
			if (!string.IsNullOrEmpty(portal.Name))
			{
				return portal.Name;
			}
			return Translations.Get("stave_unnamed_portal");
		}

		private static void BuildPanel()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panel != (Object)null)
			{
				Object.Destroy((Object)(object)_panel);
			}
			Rows.Clear();
			NeedsCandidates.Clear();
			float num = Mathf.Clamp((float)(StaveboundConfig.PortalNameLength.Value - 10) * 3f, 0f, 70f);
			Inner = 400f + num;
			PanelWidth = Inner + 40f;
			_panel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(40f + PanelWidth / 2f, -20f), PanelWidth, 530f);
			float num2 = 18f;
			_title = AddText(num2, 24f, 16, (TextAnchor)3);
			num2 += 28f;
			GameObject obj = GUIManager.Instance.CreateDropDown(_panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), Vector2.zero, 14, Inner, 32f);
			Place(obj.GetComponent<RectTransform>(), num2, 32f, Inner);
			_picker = obj.GetComponent<Dropdown>();
			Dropdown picker = _picker;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)picker).navigation = navigation;
			((UnityEvent<int>)(object)_picker.onValueChanged).AddListener((UnityAction<int>)OnPicked);
			_pickerStale = true;
			NeedsCandidates.Add((Selectable)(object)_picker);
			num2 += 38f;
			_status = AddText(num2, 56f, 13, (TextAnchor)0);
			num2 += 58f;
			_moreAbove = AddText(num2, 18f, 12, (TextAnchor)3);
			num2 += 18f;
			for (int i = 0; i < 9; i++)
			{
				Rows.Add(AddRow(num2, i));
				num2 += 28f;
			}
			_moreBelow = AddText(num2, 18f, 12, (TextAnchor)3);
			num2 += 24f;
			float num3 = (Inner - 12f) / 4f;
			float num4 = (0f - Inner) / 2f + num3 / 2f;
			NeedsCandidates.Add((Selectable)(object)AddButton("[" + Bound("stave_previous") + "]", num2, 30f, num3, num4, delegate
			{
				Step(-1);
			}));
			NeedsCandidates.Add((Selectable)(object)AddButton("[" + Bound("stave_next") + "]", num2, 30f, num3, num4 + (num3 + 4f), delegate
			{
				Step(1);
			}));
			AddButton("[" + Bound("stave_sort") + "] " + Translations.Get("stave_sel_sort"), num2, 30f, num3, num4 + 2f * (num3 + 4f), ToggleSort);
			AddButton("[" + Bound("stave_filter") + "] " + Translations.Get("stave_sel_filter"), num2, 30f, num3, num4 + 3f * (num3 + 4f), ToggleFilter);
			num2 += 36f;
			float num5 = (Inner - 6f) / 2f;
			NeedsCandidates.Add((Selectable)(object)AddButton("[" + Bound("stave_confirm") + "] " + Translations.Get("stave_sel_confirm"), num2, 34f, num5, (0f - num5) / 2f - 3f, Commit));
			AddButton("[" + Bound("stave_cancel") + "] " + Translations.Get("stave_sel_cancel"), num2, 34f, num5, num5 / 2f + 3f, Close);
		}

		private static void Place(RectTransform rect, float top, float height, float width, float x = 0f)
		{
			//IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0.5f, 1f);
			rect.anchorMax = new Vector2(0.5f, 1f);
			rect.pivot = new Vector2(0.5f, 1f);
			rect.sizeDelta = new Vector2(width, height);
			rect.anchoredPosition = new Vector2(x, 0f - top);
		}

		private static Text AddText(float top, float height, int size, TextAnchor alignment)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Text obj = CreateLabel(_panel.transform, size, alignment);
			Place(((Graphic)obj).rectTransform, top, height, Inner);
			return obj;
		}

		private static Text CreateLabel(Transform parent, int size, TextAnchor alignment)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Text component = GUIManager.Instance.CreateText(string.Empty, parent, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, GUIManager.Instance.AveriaSerifBold, size, GUIManager.Instance.ValheimOrange, true, Color.black, Inner, 28f, false).GetComponent<Text>();
			component.alignment = alignment;
			component.supportRichText = true;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private static RowView AddRow(float top, int slot)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0074: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject($"StaveboundRow{slot}", new Type[1] { typeof(RectTransform) });
			val.SetActive(false);
			val.transform.SetParent(_panel.transform, false);
			Place((RectTransform)val.transform, top, 28f, Inner);
			Image val2 = val.AddComponent<Image>();
			((Graphic)val2).color = Color.white;
			RowView view = new RowView
			{
				Root = val,
				Button = val.AddComponent<Button>()
			};
			((Selectable)view.Button).targetGraphic = (Graphic)(object)val2;
			((Selectable)view.Button).transition = (Transition)1;
			((Selectable)view.Button).colors = RowColours(current: false);
			Button button = view.Button;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)button).navigation = navigation;
			((UnityEvent)view.Button.onClick).AddListener((UnityAction)delegate
			{
				OnRowClicked(view);
				Unfocus();
			});
			val.AddComponent<SelectorRowHover>().Row = view;
			view.Name = CreateLabel(val.transform, 15, (TextAnchor)3);
			RectTransform rectTransform = ((Graphic)view.Name).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.pivot = new Vector2(0f, 0.5f);
			rectTransform.offsetMin = new Vector2(6f, 0f);
			rectTransform.offsetMax = new Vector2(-140f, 0f);
			view.Name.horizontalOverflow = (HorizontalWrapMode)0;
			view.Name.verticalOverflow = (VerticalWrapMode)0;
			view.Chips = CreateLabel(val.transform, 12, (TextAnchor)5);
			RectTransform rectTransform2 = ((Graphic)view.Chips).rectTransform;
			rectTransform2.anchorMin = new Vector2(1f, 0f);
			rectTransform2.anchorMax = new Vector2(1f, 1f);
			rectTransform2.pivot = new Vector2(1f, 0.5f);
			rectTransform2.sizeDelta = new Vector2(132f, 0f);
			rectTransform2.anchoredPosition = new Vector2(-6f, 0f);
			return view;
		}

		private static Button AddButton(string label, float top, float height, float width, float x, Action action)
		{
			//IL_0028: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			GameObject obj = GUIManager.Instance.CreateButton(label, _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), Vector2.zero, width, height);
			Place(obj.GetComponent<RectTransform>(), top, height, width, x);
			Text componentInChildren = obj.GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.resizeTextForBestFit = true;
				componentInChildren.resizeTextMinSize = 9;
				componentInChildren.resizeTextMaxSize = 14;
			}
			Button component = obj.GetComponent<Button>();
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)component).navigation = navigation;
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				action();
				Unfocus();
			});
			return component;
		}

		private static void OnRowClicked(RowView row)
		{
			if (row.Candidate >= 0 && row.Candidate < Candidates.Count)
			{
				_highlight = row.Candidate;
				if (StaveboundConfig.ClickPicksPortal.Value)
				{
					Commit();
				}
				else
				{
					ShowHighlight();
				}
			}
		}

		private static void OnPicked(int index)
		{
			if (index >= 0 && index < Candidates.Count)
			{
				_highlight = index;
				if (StaveboundConfig.ClickPicksPortal.Value)
				{
					Commit();
					return;
				}
				ShowHighlight();
				Unfocus();
			}
		}

		private static void Unfocus()
		{
			if ((Object)(object)EventSystem.current != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
		}

		private static int Stepped()
		{
			if (SelectorKeys.Pressed("stave_next"))
			{
				return 1;
			}
			if (!SelectorKeys.Pressed("stave_previous"))
			{
				return 0;
			}
			return -1;
		}

		private static bool Confirmed()
		{
			return SelectorKeys.Pressed("stave_confirm");
		}

		private static bool Cancelled()
		{
			return SelectorKeys.Pressed("stave_cancel");
		}
	}
	internal sealed class SelectorRowHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		internal DestinationSelector.RowView Row;

		public void OnPointerEnter(PointerEventData eventData)
		{
			DestinationSelector.HoverEntered(Row);
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			DestinationSelector.HoverLeft(Row);
		}
	}
}
namespace Stavebound.Travel
{
	internal static class ApproachWarning
	{
		private static ZDOID _warnedAbout = ZDOID.None;

		internal static void Consider(ZDO portal, ZDO destination, Player nearby, bool allowed)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			if (portal == null)
			{
				return;
			}
			if ((Object)(object)nearby == (Object)null || (Object)(object)nearby != (Object)(object)Player.m_localPlayer)
			{
				Forget(portal);
			}
			else if (allowed || !StaveboundConfig.WarnOnApproach.Value)
			{
				Forget(portal);
			}
			else if (!(_warnedAbout == portal.m_uid))
			{
				ClearanceGate.Refusal refusal = ClearanceGate.FirstRefusal(((Humanoid)nearby).GetInventory(), ClearanceGate.EffectiveMask(portal, destination));
				if (refusal != null)
				{
					_warnedAbout = portal.m_uid;
					((Character)nearby).Message((MessageType)2, ClearanceGate.Explain(refusal, destination.GetString(ZDOVars.s_tag, string.Empty)), 0, (Sprite)null, false);
				}
			}
		}

		private static void Forget(ZDO portal)
		{
			//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)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (_warnedAbout == portal.m_uid)
			{
				_warnedAbout = ZDOID.None;
			}
		}

		internal static void Reset()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			_warnedAbout = ZDOID.None;
		}
	}
	internal static class CargoPreview
	{
		internal static bool TryGetNearbyDestination(out Clearance mask, out bool allowsEverything)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			mask = Clearance.None;
			allowsEverything = false;
			if (!StaveboundConfig.ShowBlockedCargoOverlay.Value || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			TeleportWorld val = PortalTarget.FindNearest(((Component)Player.m_localPlayer).transform.position, StaveboundConfig.CargoPreviewRange.Value);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (val.m_allowAllItems)
			{
				allowsEverything = true;
				return true;
			}
			ZDO val2 = PortalTarget.ZdoOf(val);
			if (!ClearanceGate.TryResolveDestination(val2, out var destination, out var _) || destination == null)
			{
				return false;
			}
			mask = ClearanceGate.EffectiveMask(val2, destination);
			return true;
		}

		internal static bool WouldBeRefused(ItemData item, Clearance destinationMask, bool allowsEverything)
		{
			if (item?.m_shared == null || item.m_shared.m_teleportable)
			{
				return false;
			}
			if (allowsEverything)
			{
				return false;
			}
			string prefabName = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null);
			return !destinationMask.Permits(TierMap.RequiredFor(prefabName));
		}
	}
	internal static class ClearanceGate
	{
		internal sealed class Refusal
		{
			internal string Item;

			internal Clearance Missing;

			internal int OtherStacks;
		}

		internal static bool TryResolveDestination(ZDO portal, out ZDO destination, out long pendingPid)
		{
			//IL_0043: 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_005a: 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)
			destination = null;
			pendingPid = 0L;
			if (portal == null || ZDOMan.instance == null)
			{
				return false;
			}
			long destination2 = PortalTarget.GetDestination(portal);
			if (destination2 != 0L)
			{
				if (!PortalRegistry.TryGet(destination2, out var record))
				{
					return false;
				}
				pendingPid = destination2;
				destination = ZDOMan.instance.GetZDO(record.Id);
				return true;
			}
			ZDOID connectionZDOID = portal.GetConnectionZDOID((ConnectionType)1);
			if (((ZDOID)(ref connectionZDOID)).IsNone())
			{
				return false;
			}
			destination = ZDOMan.instance.GetZDO(connectionZDOID);
			return true;
		}

		internal static bool Allows(Player player, ZDO source, ZDO destination, bool allowAllItems)
		{
			if (allowAllItems)
			{
				return true;
			}
			if ((Object)(object)player != (Object)null)
			{
				return FirstRefusal(((Humanoid)player).GetInventory(), EffectiveMask(source, destination)) == null;
			}
			return false;
		}

		internal static Refusal FirstRefusal(Inventory inventory, Clearance permitted)
		{
			if (inventory == null)
			{
				return null;
			}
			Refusal refusal = null;
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem?.m_shared == null || allItem.m_shared.m_teleportable)
				{
					continue;
				}
				string text = (((Object)(object)allItem.m_dropPrefab != (Object)null) ? ((Object)allItem.m_dropPrefab).name : null);
				Clearance clearance = TierMap.RequiredFor(text);
				if (!permitted.Permits(clearance))
				{
					if (refusal == null)
					{
						refusal = new Refusal
						{
							Item = ((Localization.instance != null) ? Localization.instance.Localize(allItem.m_shared.m_name) : text),
							Missing = clearance
						};
					}
					else
					{
						num++;
					}
				}
			}
			if (refusal != null)
			{
				refusal.OtherStacks = num;
			}
			return refusal;
		}

		internal static string Explain(Refusal refusal, string destinationName)
		{
			string text;
			if (refusal.Missing == Clearance.Sealed)
			{
				text = Translations.Format("stave_refusal_sealed", refusal.Item);
			}
			else
			{
				string text2 = (string.IsNullOrEmpty(destinationName) ? Translations.Get("stave_that_portal") : ("\"" + destinationName + "\""));
				text = Translations.Format("stave_refusal", refusal.Item, text2, refusal.Missing.StaveName());
			}
			if (refusal.OtherStacks > 0)
			{
				text += Translations.Format("stave_refusal_more", refusal.OtherStacks);
			}
			return text;
		}

		internal static Clearance MaskOf(ZDO portal)
		{
			if (portal != null)
			{
				return (Clearance)portal.GetInt(ZdoKeys.ClearanceMask, 0);
			}
			return Clearance.None;
		}

		internal static Clearance EffectiveMask(ZDO source, ZDO destination)
		{
			return EffectiveMask(MaskOf(source), MaskOf(destination));
		}

		internal static Clearance EffectiveMask(Clearance source, Clearance destination)
		{
			MaterialFlow num = StaveboundConfig.Flow?.Value ?? MaterialFlow.Both;
			Clearance clearance = Clearance.None;
			if (num != MaterialFlow.Deliver)
			{
				clearance |= destination;
			}
			if (num != MaterialFlow.Receive)
			{
				clearance |= source;
			}
			return clearance;
		}
	}
	internal static class SeamlessTransit
	{
		private const float VanillaPause = 2f;

		private static readonly FieldRef<Player, float> TeleportTimer = AccessTools.FieldRefAccess<Player, float>("m_teleportTimer");

		internal static bool Enabled => StaveboundConfig.SeamlessTransit.Value;

		internal static bool DestinationIsLoaded(Vector3 destination)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				return ZNetScene.instance.IsAreaReady(destination);
			}
			return false;
		}

		internal static bool NeedsLoadingScreen(Vector3 destination)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				return !DestinationIsLoaded(destination);
			}
			return true;
		}

		internal static void ShortenPause(Player player, Vector3 destination)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !NeedsLoadingScreen(destination))
			{
				float num = Mathf.Clamp(StaveboundConfig.TransitPause.Value, 0f, 2f);
				TeleportTimer.Invoke(player) = 2f - num;
			}
		}

		internal static bool ArrivalIsReady(Vector3 destination)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (Enabled)
			{
				return DestinationIsLoaded(destination);
			}
			return false;
		}
	}
	internal static class StaleTravellers
	{
		private sealed class Watch
		{
			internal uint Revision;

			internal float Changed;

			internal float Requested;
		}

		private const float SweepSeconds = 2f;

		private const float AwayMetres = 100f;

		private const float StaleSeconds = 5f;

		private const float RequestCooldown = 10f;

		private static readonly Dictionary<ZDOID, Watch> Watched = new Dictionary<ZDOID, Watch>();

		private static readonly List<ZDOID> Forgotten = new List<ZDOID>();

		private static Coroutine _sweep;

		internal static void OnWorldStart()
		{
			OnWorldEnd();
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer())
			{
				_sweep = ((MonoBehaviour)Plugin.Instance).StartCoroutine(Sweep());
			}
		}

		internal static void OnWorldEnd()
		{
			if (_sweep != null)
			{
				if ((Object)(object)Plugin.Instance != (Object)null)
				{
					((MonoBehaviour)Plugin.Instance).StopCoroutine(_sweep);
				}
				_sweep = null;
			}
			Watched.Clear();
		}

		private static IEnumerator Sweep()
		{
			WaitForSeconds wait = new WaitForSeconds(2f);
			while (true)
			{
				yield return wait;
				try
				{
					Look();
				}
				catch (Exception arg)
				{
					Logger.LogError((object)$"Stale-traveller sweep failed, and has stopped: {arg}");
					_sweep = null;
					break;
				}
			}
		}

		private static void Look()
		{
			//IL_002e: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: 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)
			if (!StaveboundConfig.ClearLeftBehindBodies.Value || (Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			ZDOID val = LocalPlayer();
			float unscaledTime = Time.unscaledTime;
			Forgotten.Clear();
			Forgotten.AddRange(Watched.Keys);
			foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
			{
				ZDOID characterID = player.m_characterID;
				if (((ZDOID)(ref characterID)).IsNone() || ((ZDOID)(ref characterID)).Equals(val))
				{
					continue;
				}
				Forgotten.Remove(characterID);
				ZDO zDO = ZDOMan.instance.GetZDO(characterID);
				if (zDO == null || (Object)(object)ZNetScene.instance.FindInstance(characterID) == (Object)null)
				{
					Watched.Remove(characterID);
					continue;
				}
				if (!Watched.TryGetValue(characterID, out var value))
				{
					value = new Watch
					{
						Revision = zDO.DataRevision,
						Changed = unscaledTime
					};
					Watched[characterID] = value;
				}
				else if (value.Revision != zDO.DataRevision)
				{
					value.Revision = zDO.DataRevision;
					value.Changed = unscaledTime;
				}
				if (!(unscaledTime - value.Requested < 10f) && Suspect(player, zDO, value, unscaledTime, out var why))
				{
					value.Requested = unscaledTime;
					ZDOMan.instance.RequestZDO(characterID);
					SyncLog.Say("[stale] " + player.m_name + " " + why + " - asked the server for a fresh copy. If they have gone, the body they left here goes with it.");
				}
			}
			foreach (ZDOID item in Forgotten)
			{
				Watched.Remove(item);
			}
		}

		private static bool Suspect(PlayerInfo info, ZDO zdo, Watch watch, float now, out string why)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//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)
			if (info.m_publicPosition)
			{
				Vector3 val = zdo.GetPosition() - info.m_position;
				val.y = 0f;
				float magnitude = ((Vector3)(ref val)).magnitude;
				why = $"is drawn {magnitude:F0}m from where the server says they are";
				return magnitude > 100f;
			}
			why = $"has not changed in {now - watch.Changed:F0}s and hides their position";
			return now - watch.Changed > 5f;
		}

		private static ZDOID LocalPlayer()
		{
			//IL_0038: 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)
			ZNetView val = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).GetComponent<ZNetView>() : null);
			return (((Object)(object)val != (Object)null) ? val.GetZDO() : null)?.m_uid ?? ZDOID.None;
		}
	}
}
namespace Stavebound.Tiers
{
	internal sealed class BlockedItemsCommand : StaveboundCommand
	{
		public override string Name => "stave_items";

		public override string Help => "List every item the game refuses to teleport, grouped by the stave that will permit it. Anything unrecognised is listed separately and defaults to the highest tier.";

		protected override void Execute(string[] args, Terminal context)
		{
			if (!TierMap.Built)
			{
				StaveboundCommand.Echo(context, "Stavebound: the tier map has not been built yet. Load a world first — the main menu's item database is only a partial one.");
				return;
			}
			StaveboundCommand.Echo(context, $"Stavebound tiers - {TierMap.BlockedCount} blocked item(s):");
			Clearance[] array = new Clearance[5]
			{
				Clearance.Elder,
				Clearance.Bonemass,
				Clearance.Moder,
				Clearance.Yagluth,
				Clearance.Ashen
			};
			foreach (Clearance tier in array)
			{
				List<string> list = TierMap.AtTier(tier).Select(TierMap.Describe).ToList();
				StaveboundCommand.Echo(context, $"  {tier.StaveName()} ({list.Count}): " + ((list.Count == 0) ? "nothing" : string.Join(", ", list)));
			}
			IReadOnlyList<string> unclassifiedItems = TierMap.UnclassifiedItems;
			if (unclassifiedItems.Count == 0)
			{
				StaveboundCommand.Echo(context, "  Every blocked item is classified.");
				return;
			}
			StaveboundCommand.Echo(context, $"  UNCLASSIFIED ({unclassifiedItems.Count}), defaulting to " + Clearance.Ashen.StaveName() + ":");
			foreach (string item in unclassifiedItems.OrderBy((string n) => n))
			{
				StaveboundCommand.Echo(context, "    " + TierMap.Describe(item));
			}
			StaveboundCommand.Echo(context, "  Add these to the 2 - Clearance config lists to place them properly.");
		}
	}
	[Flags]
	internal enum Clearance
	{
		None = 0,
		Elder = 1,
		Bonemass = 2,
		Moder = 4,
		Yagluth = 8,
		Queen = 0x10,
		Ashen = 0x20,
		Sealed = 0x40
	}
	internal static class ClearanceExtensions
	{
		internal const Clearance Highest = Clearance.Ashen;

		internal const Clearance All = Clearance.Elder | Clearance.Bonemass | Clearance.Moder | Clearance.Yagluth | Clearance.Queen | Clearance.Ashen;

		internal static readonly Clearance[] Ladder = new Clearance[6]
		{
			Clearance.Elder,
			Clearance.Bonemass,
			Clearance.Moder,
			Clearance.Yagluth,
			Clearance.Queen,
			Clearance.Ashen
		};

		internal static Clearance UpToFirstGap(Clearance mask)
		{
			Clearance clearance = Clearance.None;
			Clearance[] ladder = Ladder;
			foreach (Clearance clearance2 in ladder)
			{
				if ((mask & clearance2) != clearance2)
				{
					break;
				}
				clearance |= clearance2;
			}
			return clearance;
		}

		internal static bool Permits(this Clearance mask, Clearance required)
		{
			if (required != Clearance.None)
			{
				return (mask & required) == required;
			}
			return true;
		}

		internal static string Symbol(this Clearance tier)
		{
			return tier switch
			{
				Clearance.Elder => "Cu", 
				Clearance.Bonemass => "Fe", 
				Clearance.Moder => "Ag", 
				Clearance.Yagluth => "Bm", 
				Clearance.Queen => "Dv", 
				Clearance.Ashen => "Fl", 
				_ => "--", 
			};
		}

		internal static string StaveName(this Clearance tier)
		{
			return Translations.Get(tier.NameToken());
		}

		internal static string NameToken(this Clearance tier)
		{
			return tier switch
			{
				Clearance.Elder => "stave_rune_elder", 
				Clearance.Bonemass => "stave_rune_bonemass", 
				Clearance.Moder => "stave_rune_moder", 
				Clearance.Yagluth => "stave_rune_yagluth", 
				Clearance.Queen => "stave_rune_queen", 
				Clearance.Ashen => "stave_rune_ashen", 
				_ => "stave_rune_none", 
			};
		}
	}
	internal sealed class PrefabInspectCommand : StaveboundCommand
	{
		private const int MaxDepth = 4;

		public override string Name => "stave_inspect";

		public override string Help => "stave_inspect <prefab> - show a prefab's child objects, renderers, materials and shader colour properties. Use it to find out what can be lit or tinted separately.";

		protected override void Execute(string[] args, Terminal context)
		{
			string text = string.Join(" ", args).Trim();
			if (text.Length == 0)
			{
				StaveboundCommand.Echo(context, "Stavebound: name a prefab, e.g. stave_inspect portal_wood");
				return;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				StaveboundCommand.Echo(context, "Stavebound: no world loaded.");
				return;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(text);
			if ((Object)(object)prefab == (Object)null)
			{
				StaveboundCommand.Echo(context, "Stavebound: no prefab called \"" + text + "\". Try stave_prefabs " + text);
				return;
			}
			StaveboundCommand.Echo(context, "Stavebound inspect - " + ((Object)prefab).name);
			Describe(context, prefab.transform, 0);
		}

		private static void Describe(Terminal context, Transform node, int depth)
		{
			string text = new string(' ', (depth + 1) * 2);
			List<string> list = (from c in ((Component)node).GetComponents<Component>()
				where (Object)(object)c != (Object)null && !(c is Transform)
				select ((object)c).GetType().Name).ToList();
			StringBuilder stringBuilder = new StringBuilder(text + ((Object)node).name);
			if (list.Count > 0)
			{
				stringBuilder.Append("  [" + string.Join(", ", list) + "]");
			}
			if (!((Component)node).gameObject.activeSelf)
			{
				stringBuilder.Append("  (inactive)");
			}
			StaveboundCommand.Echo(context, stringBuilder.ToString());
			Renderer component = ((Component)node).GetComponent<Renderer>();
			if ((Object)(object)component != (Object)null)
			{
				foreach (Material item in component.sharedMaterials.Where((Material m) => (Object)(object)m != (Object)null))
				{
					string[] obj = new string[7]
					{
						text,
						"  material '",
						((Object)item).name,
						"' shader '",
						null,
						null,
						null
					};
					Shader shader = item.shader;
					obj[4] = ((shader != null) ? ((Object)shader).name : null);
					obj[5] = "'";
					obj[6] = DescribeColours(item);
					StaveboundCommand.Echo(context, string.Concat(obj));
				}
			}
			if (depth >= 4)
			{
				if (node.childCount > 0)
				{
					StaveboundCommand.Echo(context, $"{text}  ... {node.childCount} more child object(s), deeper than this dump goes");
				}
			}
			else
			{
				for (int num = 0; num < node.childCount; num++)
				{
					Describe(context, node.GetChild(num), depth + 1);
				}
			}
		}

		private static string DescribeColours(Material material)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			string[] array = new string[4] { "_Color", "_EmissionColor", "_EmissiveColor", "_TintColor" };
			foreach (string text in array)
			{
				try
				{
					if (material.HasProperty(text))
					{
						list.Add($"{text}={material.GetColor(text)}");
					}
				}
				catch (Exception)
				{
				}
			}
			if (list.Count != 0)
			{
				return "  " + string.Join(" ", list);
			}
			return string.Empty;
		}
	}
	internal sealed class PrefabPreviewCommand : StaveboundCommand
	{
		private static readonly List<GameObject> Previews = new List<GameObject>();

		public override string Name => "stave_preview";

		public override string Help => "stave_preview <prefab> - place a look-at-only copy in front of you. It is not saved, not networked and vanishes on reload. 'stave_preview clear' removes them. For anything spawnable, use vanilla spawn instead.";

		protected override void Execute(string[] args, Terminal context)
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: 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)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			string text = string.Join(" ", args).Trim();
			if (string.Equals(text, "clear", StringComparison.OrdinalIgnoreCase))
			{
				Clear(context);
				return;
			}
			if (text.Length == 0)
			{
				StaveboundCommand.Echo(context, "Stavebound: name a prefab, or 'clear' to remove the previews.");
				return;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				StaveboundCommand.Echo(context, "Stavebound: no world loaded.");
				return;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(text);
			if ((Object)(object)prefab == (Object)null)
			{
				StaveboundCommand.Echo(context, "Stavebound: no prefab called \"" + text + "\". Try stave_prefabs " + text);
			}
			else if ((Object)(object)prefab.GetComponent<ZNetView>() != (Object)null)
			{
				StaveboundCommand.Echo(context, "Stavebound: " + ((Object)prefab).name + " is a networked object - use 'spawn " + ((Object)prefab).name + "' instead, which places it properly and can be removed with the hammer.");
			}
			else
			{
				Transform transform = ((Component)Player.m_localPlayer).transform;
				Vector3 val = transform.position + transform.forward * 3f;
				GameObject val2 = Object.Instantiate<GameObject>(prefab, val, transform.rotation);
				((Object)val2).name = "stave_preview_" + ((Object)prefab).name;
				Previews.Add(val2);
				StaveboundCommand.Echo(context, "Stavebound: previewing " + ((Object)prefab).name + " in front of you " + $"({Previews.Count} up). This is scenery only - nothing was added to the world.");
			}
		}

		private static void Clear(Terminal context)
		{
			int num = Previews.Count((GameObject p) => (Object)(object)p != (Object)null);
			foreach (GameObject item in Previews.Where((GameObject p) => (Object)(object)p != (Object)null))
			{
				Object.Destroy((Object)(object)item);
			}
			Previews.Clear();
			StaveboundCommand.Echo(context, (num == 0) ? "Stavebound: nothing was being previewed." : $"Stavebound: removed {num} preview(s).");
		}
	}
	internal sealed class PrefabSearchCommand : StaveboundCommand
	{
		private const int Limit = 60;

		public override string Name => "stave_prefabs";

		public override string Help => "stave_prefabs <text>[,<text>...] - list loaded prefabs whose name contains each term, marking which are buildable pieces and which are items. Comma-separate to search for several things at once.";

		protected override void Execute(string[] args, Terminal context)
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				StaveboundCommand.Echo(context, "Stavebound: no world loaded - prefabs only exist once you are in a game.");
				return;
			}
			string[] array = (from t in string.Join(" ", args).Split(new char[1] { ',' })
				select t.Trim() into t
				where t.Length > 0
				select t).ToArray();
			if (array.Length == 0)
			{
				StaveboundCommand.Echo(context, "Stavebound: give me something to search for, e.g. stave_prefabs trophy,sconce,brazier");
				return;
			}
			string[] array2 = array;
			foreach (string term in array2)
			{
				Search(context, term);
			}
		}

		private static void Search(Terminal context, string term)
		{
			List<GameObject> list = (from p in ZNetScene.instance.m_prefabs
				where (Object)(object)p != (Object)null && ((Object)p).name.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0
				orderby ((Object)p).name
				select p).ToList();
			if (list.Count == 0)
			{
				StaveboundCommand.Echo(context, "\"" + term + "\": nothing.");
				return;
			}
			StaveboundCommand.Echo(context, $"\"{term}\": {list.Count}" + ((list.Count > 60) ? $" (showing {60})" : string.Empty));
			foreach (GameObject item in list.Take(60))
			{
				List<string> list2 = new List<string>();
				if ((Object)(object)item.GetComponent<Piece>() != (Object)null)
				{
					list2.Add("piece");
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (component?.m_itemData?.m_shared != null)
				{
					list2.Add("item \"" + Localization.instance.Localize(component.m_itemData.m_shared.m_name) + "\"");
				}
				StaveboundCommand.Echo(context, "  " + ((Object)item).name + ((list2.Count > 0) ? ("  [" + string.Join(", ", list2) + "]") : string.Empty));
			}
		}
	}
	internal static class TierMap
	{
		private static readonly Dictionary<string, Clearance> Required = new Dictionary<string, Clearance>(StringComparer.OrdinalIgnoreCase);

		private static readonly List<string> Unclassified = new List<string>();

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

		internal static bool Built { get; private set; }

		internal static int BlockedCount => Required.Count;

		internal static IReadOnlyList<string> UnclassifiedItems => Unclassified;

		internal static Clearance RequiredFor(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return Clearance.None;
			}
			if (!Required.TryGetValue(prefabName, out var value))
			{
				return Clearance.None;
			}
			return value;
		}

		internal static IEnumerable<string> AtTier(Clearance tier)
		{
			return from pair in Required
				where pair.Value == tier
				select pair.Key into name
				orderby name
				select name;
		}

		internal static string Describe(string prefabName)
		{
			if (!DisplayTokens.TryGetValue(prefabName, out var value) || string.IsNullOrEmpty(value))
			{
				return prefabName;
			}
			string text = ((Localization.instance != null) ? Localization.instance.Localize(value) : value);
			if (!string.Equals(text, prefabName, StringComparison.OrdinalIgnoreCase))
			{
				return prefabName + " (" + text + ")";
			}
			return prefabName;
		}

		internal static void Build()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || instance.m_items == null || instance.m_items.Count == 0)
			{
				return;
			}
			Required.Clear();
			Unclassified.Clear();
			DisplayTokens.Clear();
			Dictionary<string, Clearance> dictionary = ReadConfiguredTiers();
			foreach (GameObject item in instance.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (!((Object)(object)component == (Object)null) && component.m_itemData?.m_shared != null && !component.m_itemData.m_shared.m_teleportable)
				{
					string name = ((Object)item).name;
					DisplayTokens[name] = component.m_itemData.m_shared.m_name;
					if (dictionary.TryGetValue(name, out var value))
					{
						Required[name] = value;
						continue;
					}
					Required[name] = Clearance.Ashen;
					Unclassified.Add(name);
				}
			}
			Built = true;
			Logger.LogInfo((object)$"Tier map built: {Required.Count} blocked item(s) across {instance.m_items.Count} in ObjectDB.");
			if (Unclassified.Count > 0)
			{
				Logger.LogWarning((object)($"{Unclassified.Count} blocked item(s) are not in the tier config and default to " + $"{Clearance.Ashen} ({Clearance.Ashen.StaveName()}): " + string.Join(", ", Unclassified.OrderBy((string n) => n)) + ". Add them to the 2 - Clearance section to place them properly."));
			}
		}

		private static Dictionary<string, Clearance> ReadConfiguredTiers()
		{
			Dictionary<string, Clearance> dictionary = new Dictionary<string, Clearance>(StringComparer.OrdinalIgnoreCase);
			foreach (KeyValuePair<Clearance, string> item in StaveboundConfig.TierPrefabs())
			{
				string[] array = item.Value.Split(new char[1] { ',' });
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.Length != 0)
					{
						if (dictionary.TryGetValue(text, out var value) && value != item.Key)
						{
							Logger.LogWarning((object)($"'{text}' is listed under both {value} and {item.Key}. Using {value}; " + "remove one of them."));
						}
						else
						{
							dictionary[text] = item.Key;
						}
					}
				}
			}
			return dictionary;
		}
	}
}
namespace Stavebound.Staves
{
	internal static class CoreTint
	{
		private static readonly string[] ColourProperties = new string[3] { "_EmissionColor", "_Color", "_TintColor" };

		internal static void Apply(GameObject prefab, Color tint, string describe)
		{
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return;
			}
			List<string> list = new List<string>();
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val2 = sharedMaterials[j];
					if ((Object)(object)val2 == (Object)null || !IsEmissive(val2))
					{
						continue;
					}
					Material val3 = new Material(val2)
					{
						name = ((Object)val2).name + "_" + describe
					};
					string[] colourProperties = ColourProperties;
					foreach (string text in colourProperties)
					{
						if (val3.HasProperty(text))
						{
							val3.SetColor(text, (text == "_EmissionColor") ? AtIntensityOf(tint, val2.GetColor(text)) : tint);
						}
					}
					sharedMaterials[j] = val3;
					flag = true;
				}
				if (flag)
				{
					val.sharedMaterials = sharedMaterials;
					list.Add("material on " + ((Object)val).name);
				}
			}
			Light[] componentsInChildren2 = prefab.GetComponentsInChildren<Light>(true);
			foreach (Light val4 in componentsInChildren2)
			{
				val4.color = tint;
				list.Add("light on " + ((Object)val4).name);
			}
			ParticleSystem[] componentsInChildren3 = prefab.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val5 in componentsInChildren3)
			{
				MainModule main = val5.main;
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(tint);
				list.Add("particles on " + ((Object)val5).name);
			}
			Logger.LogInfo((object)((list.Count == 0) ? ("Tint " + describe + ": found nothing emissive on " + ((Object)prefab).name + " - the glow is not where this expects it.") : string.Format("Tint {0} on {1}: {2} target(s) - {3}", describe, ((Object)prefab).name, list.Count, string.Join(", ", list.Distinct()))));
		}

		private static Color AtIntensityOf(Color tint, Color original)
		{
			//IL_0020: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			float maxColorComponent = ((Color)(ref original)).maxColorComponent;
			float maxColorComponent2 = ((Color)(ref tint)).maxColorComponent;
			if (maxColorComponent <= 0f || maxColorComponent2 <= 0f)
			{
				return tint;
			}
			float num = maxColorComponent / maxColorComponent2;
			return new Color(tint.r * num, tint.g * num, tint.b * num, tint.a);
		}

		private static bool IsEmissive(Material material)
		{
			//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)
			if (material.IsKeywordEnabled("_EMISSION") || material.IsKeywordEnabled("_EMISSIVE"))
			{
				return true;
			}
			if (material.HasProperty("_EmissionColor"))
			{
				Color color = material.GetColor("_EmissionColor");
				return ((Color)(ref color)).maxColorComponent > 0.01f;
			}
			return false;
		}
	}
	internal static class PlacementFeedback
	{
		private const float SearchInterval = 0.2f;

		private static readonly Vector3 BeamLift = Vector3.up * 1.2f;

		private static GameObject _circle;

		private static CircleProjector _projector;

		private static GameObject _beam;

		private static bool _beamUnavailable;

		private static bool _circleUnavailable;

		private static float _nextSearch;

		private static readonly List<TeleportWorld> InRange = new List<TeleportWorld>();

		private static string _lastAnswer;

		internal static void Update(GameObject ghost)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ghost == (Object)null || !IsOurs(ghost))
			{
				Hide();
				return;
			}
			Vector3 position = ghost.transform.position;
			float value = StaveboundConfig.StaveRadius.Value;
			Search(position, value);
			bool num = StaveboundConfig.Binding.Value == PortalBinding.AllInRadius;
			TeleportWorld val = ((InRange.Count > 0) ? InRange[0] : null);
			if (!num && (Object)(object)val != (Object)null)
			{
				ShowBeam(position + BeamLift, ((Component)val).transform.position + BeamLift);
				HideCircle();
			}
			else
			{
				ShowCircle(position, value);
				HideBeam();
			}
			Announce(num);
		}

		internal static void Reset()
		{
			if ((Object)(object)_circle != (Object)null)
			{
				Object.Destroy((Object)(object)_circle);
			}
			if ((Object)(object)_beam != (Object)null)
			{
				Object.Destroy((Object)(object)_beam);
			}
			_circle = null;
			_projector = null;
			_beam = null;
			_beamUnavailable = false;
			_circleUnavailable = false;
			_lastAnswer = null;
			_nextSearch = 0f;
			InRange.Clear();
		}

		private static bool IsOurs(GameObject ghost)
		{
			return StavePieces.ClearanceOf(((Object)ghost).name.Replace("(Clone)", string.Empty).Trim()) != Clearance.None;
		}

		private static void Search(Vector3 at, float radius)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.time < _nextSearch))
			{
				_nextSearch = Time.time + 0.2f;
				float limit = radius * radius;
				InRange.Clear();
				InRange.AddRange(LoadedPortals.Current().Where(delegate(TeleportWorld p)
				{
					//IL_0006: 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_0016: Unknown result type (might be due to invalid IL or missing references)
					Vector3 val = ((Component)p).transform.position - at;
					return ((Vector3)(ref val)).sqrMagnitude <= limit;
				}).OrderBy(delegate(TeleportWorld p)
				{
					//IL_0006: 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_0016: Unknown result type (might be due to invalid IL or missing references)
					Vector3 val = ((Component)p).transform.position - at;
					return ((Vector3)(ref val)).sqrMagnitude;
				}));
			}
		}

		private static void ShowBeam(Vector3 from, Vector3 to)
		{
			//IL_0016: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0049: 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)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_beam == (Object)null && !BuildBeam(from))
			{
				return;
			}
			Vector3 val = to - from;
			if (!(((Vector3)(ref val)).sqrMagnitude < 0.001f))
			{
				_beam.transform.position = from;
				_beam.transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized);
				_beam.transform.localScale = new Vector3(1f, 1f, ((Vector3)(ref val)).magnitude);
				if (!_beam.activeSelf)
				{
					_beam.SetActive(true);
				}
			}
		}

		private static bool BuildBeam(Vector3 at)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (_beamUnavailable)
			{
				return false;
			}
			StationExtension val = ((IEnumerable<StationExtension>)Resources.FindObjectsOfTypeAll<StationExtension>()).FirstOrDefault((Func<StationExtension, bool>)((StationExtension e) => (Object)(object)e != (Object)null && (Object)(object)e.m_connectionPrefab != (Object)null));
			if ((Object)(object)val == (Object)null)
			{
				_beamUnavailable = true;
				Logger.LogWarning((object)"No station-connection effect to borrow, so stave binding will be shown as a circle instead of a beam.");
				return false;
			}
			_beam = Object.Instantiate<GameObject>(val.m_connectionPrefab, at, Quaternion.identity);
			((Object)_beam).name = "stave_binding_beam";
			return true;
		}

		private static void HideBeam()
		{
			if ((Object)(object)_beam != (Object)null && _beam.activeSelf)
			{
				_beam.SetActive(false);
			}
		}

		private static void ShowCircle(Vector3 at, float radius)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_projector == (Object)null) || BuildCircle())
			{
				_circle.transform.position = at;
				_projector.m_radius = radius;
				if (!_circle.activeSelf)
				{
					_circle.SetActive(true);
				}
			}
		}

		private static bool BuildCircle()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (_circleUnavailable)
			{
				return false;
			}
			CircleProjector val = ((IEnumerable<CircleProjector>)Resources.FindObjectsOfTypeAll<CircleProjector>()).FirstOrDefault((Func<CircleProjector, bool>)((CircleProjector c) => (Object)(object)c != (Object)null && (Object)(object)c.m_prefab != (Object)null));
			if ((Object)(object)val == (Object)null)
			{
				_circleUnavailable = true;
				Logger.LogWarning((object)"No CircleProjector to borrow, so stave range will not be drawn. The portal it binds to is still named on placement.");
				return false;
			}
			_circle = new GameObject("stave_range");
			_projector = _circle.AddComponent<CircleProjector>();
			_projector.m_prefab = val.m_prefab;
			_projector.m_mask = val.m_mask;
			_projector.m_nrOfSegments = val.m_nrOfSegments;
			return true;
		}

		private static void HideCircle()
		{
			if ((Object)(object)_circle != (Object)null && _circle.activeSelf)
			{
				_circle.SetActive(false);
			}
		}

		private static void Hide()
		{
			HideCircle();
			HideBeam();
			_lastAnswer = null;
		}

		private static void Announce(bool all)
		{
			string text = Describe(all);
			if (!(text == _lastAnswer))
			{
				_lastAnswer = text;
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
				}
			}
		}

		private static string Describe(bool all)
		{
			if (InRange.Count == 0)
			{
				return Translations.Get("stave_place_no_portal");
			}
			if (all)
			{
				if (InRange.Count != 1)
				{
					return Translations.Format("stave_place_binds_all", InRange.Count);
				}
				return Translations.Format("stave_place_binds", Name(InRange[0]));
			}
			if (InRange.Count != 1)
			{
				return Translations.Format("stave_place_binds_nearest", Name(InRange[0]), InRange.Count);
			}
			return Translations.Format("stave_place_binds", Name(InRange[0]));
		}

		private static string Name(TeleportWorld portal)
		{
			ZDO val = PortalTarget.ZdoOf(portal);
			string text = ((val != null) ? val.GetString(ZDOVars.s_tag, string.Empty) : string.Empty);
			if (!string.IsNullOrEmpty(text))
			{
				return "\"" + text + "\"";
			}
			return Translations.Get("stave_an_unnamed_portal");
		}
	}
	internal static class SiteSweep
	{
		private const float SweepSeconds = 10f;

		private static Coroutine _sweep;

		private static readonly List<ZDO> Found = new List<ZDO>();

		private static readonly Dictionary<ZDO, Clearance> PortalMasks = new Dictionary<ZDO, Clearance>();

		internal static void Start()
		{
			Stop();
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				_sweep = ((MonoBehaviour)Plugin.Instance).StartCoroutine(Run());
			}
		}

		internal static void Stop()
		{
			if (_sweep != null && (Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StopCoroutine(_sweep);
			}
			_sweep = null;
			Found.Clear();
			PortalMasks.Clear();
		}

		private static IEnumerator Run()
		{
			WaitForSeconds wait = new WaitForSeconds(10f);
			while (true)
			{
				yield return Recompute();
				yield return wait;
			}
		}

		private static IEnumerator Recompute()
		{
			if (ZDOMan.instance == null)
			{
				yield break;
			}
			PortalMasks.Clear();
			float radius = StaveboundConfig.StaveRadius.Value;
			bool all = StaveboundConfig.Binding.Value == PortalBinding.AllInRadius;
			foreach (KeyValuePair<string, Clearance> stave in StavePieces.Staves)
			{
				yield return Collect(stave.Key, Found);
				foreach (ZDO item in Found)
				{
					Bind(item.GetPosition(), stave.Value, radius, all);
				}
			}
			if (StaveboundConfig.StrictLadder.Value)
			{
				foreach (ZDO item2 in new List<ZDO>(PortalMasks.Keys))
				{
					PortalMasks[item2] = ClearanceExtensions.UpToFirstGap(PortalMasks[item2]);
				}
			}
			WriteChangedMasks();
		}

		private static void Bind(Vector3 runePosition, Clearance tier, float radius, bool all)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			List<ZDO> list = ((instance != null) ? instance.GetPortalList() : null);
			if (list == null)
			{
				return;
			}
			float num = radius * radius;
			ZDO val = null;
			float num2 = num;
			foreach (ZDO item in list)
			{
				if (item == null || !item.IsValid())
				{
					continue;
				}
				Vector3 val2 = item.GetPosition() - runePosition;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (!(sqrMagnitude > num))
				{
					if (all)
					{
						Grant(item, tier);
					}
					else if (sqrMagnitude <= num2)
					{
						num2 = sqrMagnitude;
						val = item;
					}
				}
			}
			if (!all && val != null)
			{
				Grant(val, tier);
			}
		}

		private static IEnumerator Collect(string prefab, List<ZDO> into)
		{
			into.Clear();
			int index = 0;
			bool complete = false;
			while (!complete)
			{
				if (ZDOMan.instance == null)
				{
					into.Clear();
					break;
				}
				complete = ZDOMan.instance.GetAllZDOsWithPrefabIterative(prefab, into, ref index);
				yield return null;
			}
		}

		private static void Grant(ZDO portal, Clearance tier)
		{
			PortalMasks[portal] = (PortalMasks.TryGetValue(portal, out var value) ? (value | tier) : tier);
		}

		private static void WriteChangedMasks()
		{
			ZDOMan instance = ZDOMan.instance;
			List<ZDO> list = ((instance != null) ? instance.GetPortalList() : null);
			if (list == null)
			{
				return;
			}
			foreach (ZDO item in list)
			{
				if (item != null && item.IsValid())
				{
					PortalMasks.TryGetValue(item, out var value);
					Write(item, value);
				}
			}
		}

		private static void Write(ZDO portal, Clearance mask)
		{
			if (portal.GetInt(ZdoKeys.ClearanceMask, 0) != (int)mask)
			{
				PortalTarget.Claim(portal);
				portal.Set(ZdoKeys.ClearanceMask, (int)mask, false);
				PortalTarget.Publish(portal);
				string text = portal.GetString(ZDOVars.s_tag, string.Empty);
				Logger.LogInfo((object)("[site] Clearance of " + (string.IsNullOrEmpty(text) ? "an unnamed portal" : ("\"" + text + "\"")) + " is now " + Describe(mask) + "."));
			}
		}

		private static string Describe(Clearance mask)
		{
			if (mask == Clearance.None)
			{
				return "nothing";
			}
			List<string> list = new List<string>();
			Clearance[] ladder = ClearanceExtensions.Ladder;
			for (int i = 0; i < ladder.Length; i++)
			{
				Clearance clearance = ladder[i];
				if ((mask & clearance) == clearance)
				{
					list.Add(clearance.ToString());
				}
			}
			return string.Join(" + ", list);
		}
	}
	internal static class StavePieces
	{
		private sealed class PieceSpec
		{
			internal string Name;

			internal string Display;

			internal string Description;

			internal Color Tint;

			internal RequirementConfig[] Requirements;
		}

		private const string CloneSource = "Pickable_BlackCoreStand";

		private const string TrophyElder = "TrophyTheElder";

		private const string TrophyBonemass = "TrophyBonemass";

		private const string TrophyModer = "TrophyDragonQueen";

		private const string TrophyYagluth = "TrophyGoblinKing";

		private const string TrophyQueen = "TrophySeekerQueen";

		private const string TrophyFader = "TrophyFader";

		private static readonly List<PieceSpec> Specs = new List<PieceSpec>
		{
			new PieceSpec
			{
				Name = "stave_elder",
				Display = "stave_rune_elder",
				Description = "stave_desc_elder",
				Tint = new Color(0.95f, 0.8f, 0.15f),
				Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig
					{
						Item = "TrophyTheElder",
						Amount = 1,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Copper",
						Amount = 10,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Stone",
						Amount = 20,
						Recover = true
					}
				}
			},
			new PieceSpec
			{
				Name = "stave_bonemass",
				Display = "stave_rune_bonemass",
				Description = "stave_desc_bonemass",
				Tint = new Color(0.25f, 0.85f, 0.3f),
				Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig
					{
						Item = "TrophyBonemass",
						Amount = 1,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Iron",
						Amount = 10,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Stone",
						Amount = 20,
						Recover = true
					}
				}
			},
			new PieceSpec
			{
				Name = "stave_moder",
				Display = "stave_rune_moder",
				Description = "stave_desc_moder",
				Tint = new Color(0.75f, 0.85f, 1f),
				Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig
					{
						Item = "TrophyDragonQueen",
						Amount = 1,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Silver",
						Amount = 10,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Stone",
						Amount = 20,
						Recover = true
					}
				}
			},
			new PieceSpec
			{
				Name = "stave_yagluth",
				Display = "stave_rune_yagluth",
				Description = "stave_desc_yagluth",
				Tint = new Color(0.45f, 0.15f, 0.65f),
				Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig
					{
						Item = "TrophyGoblinKing",
						Amount = 1,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "BlackMetal",
						Amount = 10,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Stone",
						Amount = 20,
						Recover = true
					}
				}
			},
			new PieceSpec
			{
				Name = "stave_queen",
				Display = "stave_rune_queen",
				Description = "stave_desc_queen",
				Tint = new Color(0.4f, 0.95f, 0.95f),
				Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig
					{
						Item = "TrophySeekerQueen",
						Amount = 1,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "DvergrNeedle",
						Amount = 3,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Stone",
						Amount = 20,
						Recover = true
					}
				}
			},
			new PieceSpec
			{
				Name = "stave_ashen",
				Display = "stave_rune_ashen",
				Description = "stave_desc_ashen",
				Tint = new Color(1f, 0.35f, 0.1f),
				Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
				{
					new RequirementConfig
					{
						Item = "TrophyFader",
						Amount = 1,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "FlametalNew",
						Amount = 10,
						Recover = true
					},
					new RequirementConfig
					{
						Item = "Stone",
						Amount = 20,
						Recover = true
					}
				}
			}
		};

		private static readonly Dictionary<string, Clearance> Granted = new Dictionary<string, Clearance>
		{
			{
				"stave_elder",
				Clearance.Elder
			},
			{
				"stave_bonemass",
				Clearance.Bonemass
			},
			{
				"stave_moder",
				Clearance.Moder
			},
			{
				"stave_yagluth",
				Clearance.Yagluth
			},
			{
				"stave_queen",
				Clearance.Queen
			},
			{
				"stave_ashen",
				Clearance.Ashen
			}
		};

		internal static IEnumerable<KeyValuePair<string, Clearance>> Staves => Granted;

		internal static Clearance ClearanceOf(string prefabName)
		{
			if (!Granted.TryGetValue(prefabName, out var value))
			{
				return Clearance.None;
			}
			return value;
		}

		internal static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Create;
			PieceManager.OnPiecesRegistered += FileInTheBuildMenu;
		}

		private static void FileInTheBuildMenu()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			foreach (string key in Granted.Keys)
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(key);
				Piece val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null);
				if (!((Object)(object)val == (Object)null))
				{
					val.m_category = (PieceCategory)0;
					val.m_usage = (UsageTagFlags)2048;
					val.m_isUpgrade = true;
				}
			}
		}

		private static void Create()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= Create;
			if ((Object)(object)PrefabManager.Instance.GetPrefab("Pickable_BlackCoreStand") == (Object)null)
			{
				Logger.LogError((object)"'Pickable_BlackCoreStand' is missing, so no staves can be built. A game update may have renamed it — run stave_prefabs corestand to find its new name.");
				return;
			}
			foreach (PieceSpec spec in Specs)
			{
				try
				{
					CreateOne(spec);
				}
				catch (Exception arg)
				{
					Logger.LogError((object)$"Could not create {spec.Name}: {arg}");
				}
			}
		}

		private static void CheckRequirements(PieceSpec spec)
		{
			RequirementConfig[] requirements = spec.Requirements;
			foreach (RequirementConfig val in requirements)
			{
				if ((Object)(object)PrefabManager.Instance.GetPrefab(val.Item) == (Object)null)
				{
					Logger.LogError((object)(spec.Name + " needs '" + val.Item + "', which does not exist. That piece will be unbuildable until the name is corrected - try stave_prefabs to find it."));
				}
			}
		}

		private static void CreateOne(PieceSpec spec)
		{
			//IL_005e: 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_0075: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			CheckRequirements(spec);
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(spec.Name, "Pickable_BlackCoreStand");
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogError((object)("Could not clone Pickable_BlackCoreStand for " + spec.Name + "."));
				return;
			}
			Pickable component = val.GetComponent<Pickable>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			MakeBuildable(val);
			CoreTint.Apply(val, spec.Tint, spec.Name);
			CustomPiece val2 = new CustomPiece(val, false, new PieceConfig
			{
				Name = "$" + spec.Display,
				Description = "$" + spec.Description,
				PieceTable = PieceTables.Hammer,
				Category = "Misc",
				Icon = RenderIcon(val, spec.Name),
				Requirements = spec.Requirements
			});
			if (!val2.IsValid())
			{
				Logger.LogError((object)(spec.Name + " did not come out valid and will not be registered."));
				return;
			}
			PieceManager.Instance.AddPiece(val2);
			Logger.LogInfo((object)("Registered piece " + spec.Name + "."));
		}

		private static Sprite RenderIcon(GameObject prefab, string describe)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			try
			{
				Sprite obj = RenderManager.Instance.Render(new RenderRequest(prefab)
				{
					Rotation = RenderManager.IsometricRotation,
					Width = 128,
					Height = 128,
					UseCache = false
				});
				if ((Object)(object)obj == (Object)null)
				{
					Logger.LogWarning((object)("No icon could be rendered for " + describe + "."));
				}
				return obj;
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Icon render failed for " + describe + ": " + ex.Message));
				return null;
			}
		}

		private static void MakeBuildable(GameObject prefab)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			Piece obj = prefab.GetComponent<Piece>() ?? prefab.AddComponent<Piece>();
			obj.m_canBeRemoved = true;
			obj.m_canRotate = true;
			obj.m_allowedInDungeons = false;
			obj.m_groundPiece = false;
			obj.m_groundOnly = false;
			obj.m_noInWater = true;
			if (!((Object)(object)prefab.GetComponent<WearNTear>() != (Object)null))
			{
				WearNTear obj2 = prefab.AddComponent<WearNTear>();
				obj2.m_health = 500f;
				obj2.m_burnable = false;
				obj2.m_noRoofWear = true;
				obj2.m_noSupportWear = true;
				obj2.m_materialType = (MaterialType)1;
			}
		}
	}
}
namespace Stavebound.Portals
{
	internal static class LoadedPortals
	{
		private static readonly List<TeleportWorld> Live = new List<TeleportWorld>();

		internal static void Remember(TeleportWorld portal)
		{
			if (!((Object)(object)portal == (Object)null))
			{
				List<TeleportWorld> list = Current();
				if (!list.Contains(portal))
				{
					list.Add(portal);
				}
			}
		}

		internal static List<TeleportWorld> Current()
		{
			for (int num = Live.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)Live[num] == (Object)null)
				{
					Live.RemoveAt(num);
				}
			}
			return Live;
		}

		internal static void Forget()
		{
			Live.Clear();
		}
	}
	internal sealed class PlayerPositionsCommand : StaveboundCommand
	{
		private sealed class Sample
		{
			internal string Name;

			internal ZDOID Id;

			internal bool You;

			internal bool Public;

			internal Vector3 Server;

			internal bool HaveData;

			internal Vector3 Data;

			internal uint Revision;

			internal long Owner;

			internal bool HaveBody;

			internal Vector3 Body;
		}

		private const float WatchSeconds = 3f;

		private const float Apart = 30f;

		public override string Name => "stave_players";

		public override string Help => "Diagnose a player's body left at a portal after they went through: where each player is drawn, where this machine's data says, and where the server says. Watches for a few seconds. Run it on the watcher's machine while the body is visible, and on the traveller's.";

		protected override void Execute(string[] args, Terminal context)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				StaveboundCommand.Echo(context, "Stavebound: no world loaded.");
				return;
			}
			List<Sample> list = Take();
			if (list.Count == 0)
			{
				StaveboundCommand.Echo(context, "Stavebound: the server has not sent a player list yet.");
				return;
			}
			StaveboundCommand.Echo(context, $"Stavebound players - watching for {3f:F0}s, stay put ...");
			((MonoBehaviour)Plugin.Instance).StartCoroutine(Finish(context, list));
		}

		private static List<Sample> Take()
		{
			//IL_003f: 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_0044: 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_006a: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missin