Decompiled source of Wardrobe Portal v1.0.0

plugins/WardrobePortal.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HeaveHo.Shared;
using Microsoft.CodeAnalysis;
using Nick.Shared;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI.")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")]
[assembly: AssemblyMetadata("ClaudeTools.Reload", "menu")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HeaveHo.Shared
{
	internal sealed class ServerSettings : IDisposable
	{
		public enum ServerMod
		{
			NotConnected,
			Checking,
			Installed,
			Missing
		}

		private sealed class ConfigurationManagerAttributes
		{
			public bool? ReadOnly;
		}

		private sealed class SyncedText
		{
			public string Key;

			public Func<string> Own;

			public Action<string> Use;

			public string Given;

			public bool FromServer;

			public bool Pending;

			public byte[] Packed;

			public bool TooBig;

			public MemoryStream Incoming;

			public int NextPart;
		}

		private sealed class Sending
		{
			public ZRpc Rpc;

			public string Key;

			public byte[] Data;

			public int Next;

			public int Parts;
		}

		private const int Protocol = 2;

		private const float ChangeSendGap = 0.5f;

		private const float AnswerWait = 20f;

		private const float FileWait = 1f;

		private const int PartSize = 65536;

		private const int CompressFrom = 1024;

		private const int WarnBytes = 262144;

		private const int MaxBytes = 8388608;

		private const int PaceBelow = 10240;

		private readonly string _send;

		private readonly string _ask;

		private readonly string _dAsk;

		private readonly string _dHello;

		private readonly string _dSend;

		private readonly string _edit;

		private readonly string _dTextAsk;

		private readonly string _dText;

		private readonly string _dAgain;

		private readonly ConfigFile _config;

		private readonly ManualLogSource _log;

		private readonly string _name;

		private readonly List<ConfigEntryBase> _entries = new List<ConfigEntryBase>();

		private readonly Dictionary<ConfigEntryBase, object> _own = new Dictionary<ConfigEntryBase, object>();

		private readonly Dictionary<ConfigEntryBase, object> _server = new Dictionary<ConfigEntryBase, object>();

		private readonly List<GameObject> _guardedPieces = new List<GameObject>();

		private readonly List<Recipe> _guardedRecipes = new List<Recipe>();

		private ZRoutedRpc _registeredOn;

		private bool _applying;

		private bool _reloading;

		private bool _changePending;

		private float _nextChangeSend;

		private float _askedAt = -1f;

		private int _serverProtocol;

		private bool _directSeen;

		private readonly HashSet<ZRpc> _directPeers = new HashSet<ZRpc>();

		private readonly List<SyncedText> _texts = new List<SyncedText>();

		private readonly Dictionary<ZRpc, HashSet<string>> _textPeers = new Dictionary<ZRpc, HashSet<string>>();

		private bool _textPending;

		private float _nextTextSend;

		private bool _readOnlyShown;

		private float _nextAdminCheck;

		private FileSystemWatcher _watcher;

		private volatile bool _fileTouched;

		private float _reloadAt = -1f;

		private string _fileText;

		private readonly List<Sending> _outbox = new List<Sending>();

		private static readonly MethodInfo UpdateAvailablePieces = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null);

		private static readonly List<ServerSettings> Live = new List<ServerSettings>();

		private static Harmony _saveHarmony;

		public string Version { get; }

		public bool FromServer => _server.Count > 0;

		public ServerMod Server { get; private set; }

		public string ServerVersion { get; private set; }

		public bool CanEditServer
		{
			get
			{
				if (!IsServer)
				{
					if (Server == ServerMod.Installed && _serverProtocol >= 1 && (Object)(object)ZNet.instance != (Object)null)
					{
						return ZNet.instance.LocalPlayerIsAdminOrHost();
					}
					return false;
				}
				return true;
			}
		}

		private static bool IsServer
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		public event Action ServerChanged;

		public ServerSettings(string guid, ConfigFile config, ManualLogSource log)
		{
			_send = guid + ".settings";
			_ask = guid + ".settings.ask";
			_dAsk = guid + ".settings.d.ask";
			_dHello = guid + ".settings.d.hello";
			_dSend = guid + ".settings.d.values";
			_edit = guid + ".settings.d.edit";
			_dTextAsk = guid + ".settings.d.textask";
			_dAgain = guid + ".settings.d.again";
			_dText = guid + ".settings.d.text";
			_config = config;
			_log = log;
			BepInPlugin val = PluginOf(guid);
			_name = ((val != null) ? val.Name : null) ?? guid;
			Version = ((val == null) ? null : val.Version?.ToString()) ?? "";
			Live.Add(this);
			if (Live.Count == 1)
			{
				PatchSave();
			}
			WatchFile();
		}

		public ConfigEntry<T> Add<T>(ConfigEntry<T> entry)
		{
			if (entry == null || _entries.Contains((ConfigEntryBase)(object)entry))
			{
				return entry;
			}
			_entries.Add((ConfigEntryBase)(object)entry);
			entry.SettingChanged += OnChanged;
			GiveManagerAttributes((ConfigEntryBase)(object)entry);
			return entry;
		}

		private static void GiveManagerAttributes(ConfigEntryBase entry)
		{
			ConfigDescription description = entry.Description;
			if (description == null || description == ConfigDescription.Empty || (description.Tags ?? new object[0]).Any(IsManagerAttributes))
			{
				return;
			}
			try
			{
				object[] value = new object[1]
				{
					new ConfigurationManagerAttributes()
				}.Concat(description.Tags ?? new object[0]).ToArray();
				AccessTools.Field(typeof(ConfigDescription), "<Tags>k__BackingField")?.SetValue(description, value);
			}
			catch (Exception)
			{
			}
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T value, string description, AcceptableValueBase range = null, params object[] tags)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			if (!description.Contains("[Synced with Server]"))
			{
				description += " [Synced with Server]";
			}
			return Add<T>(_config.Bind<T>(section, key, value, new ConfigDescription(description, range, tags ?? new object[0])));
		}

		public void NeedsServer(GameObject piecePrefab)
		{
			if (!((Object)(object)piecePrefab == (Object)null))
			{
				_guardedPieces.RemoveAll((GameObject p) => (Object)(object)p == (Object)null || ((Object)p).name == ((Object)piecePrefab).name);
				_guardedPieces.Add(piecePrefab);
				Guard();
			}
		}

		public void NeedsServer(Recipe recipe)
		{
			if (!((Object)(object)recipe == (Object)null))
			{
				_guardedRecipes.RemoveAll((Recipe r) => (Object)(object)r == (Object)null || (Object)(object)r == (Object)(object)recipe || (!string.IsNullOrEmpty(((Object)recipe).name) && ((Object)r).name == ((Object)recipe).name));
				_guardedRecipes.Add(recipe);
				Guard();
			}
		}

		public void AddText(string key, Func<string> own, Action<string> use)
		{
			if (string.IsNullOrEmpty(key) || own == null || use == null)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)"AddText needs a key, own and use");
				}
				return;
			}
			_texts.RemoveAll((SyncedText x) => x.Key == key);
			SyncedText syncedText = new SyncedText
			{
				Key = key,
				Own = own,
				Use = use
			};
			_texts.Add(syncedText);
			Give(syncedText, OwnText(syncedText));
			ZRpc val = ((!((Object)(object)ZNet.instance != (Object)null) || IsServer) ? null : ZNet.instance.GetServerPeer()?.m_rpc);
			if (_registeredOn != null && val != null)
			{
				val.Register<ZPackage>(_dText, (Action<ZRpc, ZPackage>)OnText);
				AskTexts(val);
			}
		}

		public void TextChanged(string key)
		{
			SyncedText syncedText = _texts.FirstOrDefault((SyncedText x) => x.Key == key);
			if (syncedText != null)
			{
				syncedText.Packed = null;
				if (!syncedText.FromServer)
				{
					Give(syncedText, OwnText(syncedText));
				}
				if (IsServer)
				{
					syncedText.Pending = true;
					_textPending = true;
				}
			}
		}

		public bool TextFromServer(string key)
		{
			return _texts.Any((SyncedText x) => x.Key == key && x.FromServer);
		}

		public void Update()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != _registeredOn)
			{
				Unregister();
				Restore();
				RestoreTexts(give: true);
				_changePending = false;
				_textPending = false;
				SetServer(ServerMod.NotConnected, null, 0);
				if (instance != null)
				{
					Register(instance);
				}
			}
			float unscaledTime = Time.unscaledTime;
			if (_changePending && unscaledTime >= _nextChangeSend)
			{
				SendChange();
			}
			if (_textPending && unscaledTime >= _nextTextSend)
			{
				SendTexts();
			}
			if (_outbox.Count > 0)
			{
				Pump();
			}
			if (Server == ServerMod.Checking && _askedAt >= 0f && unscaledTime - _askedAt > 20f)
			{
				if (_guardedPieces.Count + _guardedRecipes.Count > 0)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)("The server didn't answer: " + _name + " isn't installed there (or its copy is older than 2026-10-11), so its pieces and items can't be made on this server."));
					}
				}
				else
				{
					ManualLogSource log2 = _log;
					if (log2 != null)
					{
						log2.LogInfo((object)("The server didn't answer: " + _name + " isn't installed there, or its copy is older" + (FromServer ? " (its settings apply)." : " (your own settings apply).")));
					}
				}
				SetServer(ServerMod.Missing, null, 0);
			}
			if (_fileTouched)
			{
				_fileTouched = false;
				_reloadAt = unscaledTime + 1f;
			}
			if (_reloadAt >= 0f && unscaledTime >= _reloadAt)
			{
				_reloadAt = -1f;
				ReloadFile();
			}
			if (FromServer && unscaledTime >= _nextAdminCheck)
			{
				_nextAdminCheck = unscaledTime + 1f;
				ShowReadOnly();
			}
		}

		public void Dispose()
		{
			Unregister();
			Restore();
			RestoreTexts(give: false);
			SetServer(ServerMod.NotConnected, null, 0);
			foreach (ConfigEntryBase entry in _entries)
			{
				Unsubscribe(entry);
			}
			_entries.Clear();
			_texts.Clear();
			try
			{
				_watcher?.Dispose();
			}
			catch (Exception)
			{
			}
			_watcher = null;
			Live.Remove(this);
			if (Live.Count == 0)
			{
				UnpatchSave();
			}
		}

		private void Register(ZRoutedRpc rpc)
		{
			Forget(rpc, _send);
			Forget(rpc, _ask);
			rpc.Register<ZPackage>(_send, (Action<long, ZPackage>)OnRoutedValues);
			rpc.Register(_ask, (Action<long>)OnRoutedAsk);
			rpc.m_onNewPeer = (Action<long>)Delegate.Combine(rpc.m_onNewPeer, new Action<long>(OnNewPeer));
			_registeredOn = rpc;
			if (IsServer)
			{
				foreach (ZNetPeer peer in ZNet.instance.GetPeers())
				{
					ListenTo(peer);
					if (peer != null)
					{
						ZRpc rpc2 = peer.m_rpc;
						if (rpc2 != null)
						{
							rpc2.Invoke(_dAgain, Array.Empty<object>());
						}
					}
				}
				return;
			}
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				SetServer(ServerMod.Checking, null, 0);
				if (ZNet.instance.GetServerPeer() != null)
				{
					AskServer();
				}
			}
		}

		private void Unregister()
		{
			if (_registeredOn == null)
			{
				return;
			}
			ZRoutedRpc registeredOn = _registeredOn;
			registeredOn.m_onNewPeer = (Action<long>)Delegate.Remove(registeredOn.m_onNewPeer, new Action<long>(OnNewPeer));
			Forget(_registeredOn, _send);
			Forget(_registeredOn, _ask);
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				foreach (ZNetPeer peer in ZNet.instance.GetPeers())
				{
					if (peer?.m_rpc != null)
					{
						string[] array = new string[7] { _dAsk, _dHello, _dSend, _edit, _dTextAsk, _dText, _dAgain };
						foreach (string name in array)
						{
							ForgetDirect(peer.m_rpc, name);
						}
					}
				}
			}
			_directPeers.Clear();
			_textPeers.Clear();
			_outbox.Clear();
			_directSeen = false;
			_registeredOn = null;
		}

		private static void Forget(ZRoutedRpc rpc, string name)
		{
			if (AccessTools.Field(typeof(ZRoutedRpc), "m_functions")?.GetValue(rpc) is IDictionary dictionary)
			{
				dictionary.Remove(StringExtensionMethods.GetStableHashCode(name));
			}
		}

		private static void ForgetDirect(ZRpc rpc, string name)
		{
			if (AccessTools.Field(typeof(ZRpc), "m_functions")?.GetValue(rpc) is IDictionary dictionary)
			{
				dictionary.Remove(StringExtensionMethods.GetStableHashCode(name));
			}
		}

		private void OnNewPeer(long uid)
		{
			if (IsServer)
			{
				ZNetPeer peer = ZNet.instance.GetPeer(uid);
				ListenTo(peer);
				if (peer?.m_rpc != null)
				{
					SendDirect(peer.m_rpc);
				}
				SendRouted(uid);
			}
			else if ((Object)(object)ZNet.instance != (Object)null)
			{
				ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
				if (serverPeer != null && serverPeer.m_uid == uid)
				{
					AskServer();
				}
			}
		}

		private void ListenTo(ZNetPeer peer)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if (peer?.m_rpc != null)
			{
				peer.m_rpc.Register(_dAsk, new Method(OnDirectAsk));
				peer.m_rpc.Register<ZPackage>(_edit, (Action<ZRpc, ZPackage>)OnEdit);
				peer.m_rpc.Register<ZPackage>(_dTextAsk, (Action<ZRpc, ZPackage>)OnTextAsk);
			}
		}

		private void OnDirectAsk(ZRpc rpc)
		{
			if (IsServer)
			{
				_directPeers.Add(rpc);
				SendDirect(rpc);
			}
		}

		private void OnRoutedAsk(long sender)
		{
			if (IsServer)
			{
				SendRouted(sender);
			}
		}

		private void SendDirect(ZRpc rpc)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(2);
			val.Write(Version);
			rpc.Invoke(_dHello, new object[1] { val });
			if (_entries.Count > 0)
			{
				rpc.Invoke(_dSend, new object[1] { Values() });
			}
		}

		private void SendRouted(long target)
		{
			if (ZRoutedRpc.instance != null && _entries.Count > 0)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(target, _send, new object[1] { Values() });
			}
		}

		private ZPackage Values()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(_entries.Count);
			foreach (ConfigEntryBase entry in _entries)
			{
				val.Write(entry.Definition.Section);
				val.Write(entry.Definition.Key);
				val.Write(TomlTypeConverter.ConvertToString(entry.BoxedValue, entry.SettingType));
			}
			return val;
		}

		private void AskServer()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null);
			if (val?.m_rpc == null)
			{
				return;
			}
			_askedAt = Time.unscaledTime;
			val.m_rpc.Register<ZPackage>(_dHello, (Action<ZRpc, ZPackage>)OnDirectHello);
			val.m_rpc.Register<ZPackage>(_dSend, (Action<ZRpc, ZPackage>)OnDirectValues);
			val.m_rpc.Register<ZPackage>(_dText, (Action<ZRpc, ZPackage>)OnText);
			val.m_rpc.Register(_dAgain, new Method(OnAskAgain));
			val.m_rpc.Invoke(_dAsk, Array.Empty<object>());
			AskTexts(val.m_rpc);
			try
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(val.m_uid, _ask, Array.Empty<object>());
				}
			}
			catch (Exception)
			{
			}
		}

		private static bool IsServerConnection(ZRpc rpc)
		{
			if (!IsServer)
			{
				ZNet instance = ZNet.instance;
				return ((instance == null) ? null : instance.GetServerPeer()?.m_rpc) == rpc;
			}
			return false;
		}

		private void OnAskAgain(ZRpc rpc)
		{
			if (IsServerConnection(rpc))
			{
				rpc.Invoke(_dAsk, Array.Empty<object>());
				AskTexts(rpc);
			}
		}

		private void OnDirectHello(ZRpc rpc, ZPackage pkg)
		{
			if (!IsServerConnection(rpc))
			{
				return;
			}
			try
			{
				int protocol = pkg.ReadInt();
				string text = pkg.ReadString();
				if (text != Version && text != ServerVersion)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)("The server has " + _name + " " + text + ", you have " + Version + ": some things may not match. Use the same version as the server."));
					}
				}
				_directSeen = true;
				SetServer(ServerMod.Installed, text, protocol);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Could not read the server's hello: " + ex.Message));
				}
			}
		}

		private void OnDirectValues(ZRpc rpc, ZPackage pkg)
		{
			if (IsServerConnection(rpc))
			{
				TakeValues(pkg);
			}
		}

		private void OnRoutedValues(long sender, ZPackage pkg)
		{
			if (!_directSeen && !IsServer)
			{
				ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null);
				if (val != null && val.m_uid == sender)
				{
					TakeValues(pkg);
				}
			}
		}

		private void TakeValues(ZPackage pkg)
		{
			try
			{
				int num = pkg.ReadInt();
				List<string> list = new List<string>();
				for (int i = 0; i < num; i++)
				{
					string section = pkg.ReadString();
					string key = pkg.ReadString();
					string text = pkg.ReadString();
					ConfigEntryBase val = ((IEnumerable<ConfigEntryBase>)_entries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase x) => x.Definition.Section == section && x.Definition.Key == key));
					if (val != null)
					{
						object obj;
						try
						{
							obj = TomlTypeConverter.ConvertToValue(text, val.SettingType);
						}
						catch (Exception)
						{
							continue;
						}
						if (!_own.ContainsKey(val))
						{
							_own[val] = val.BoxedValue;
						}
						_server[val] = obj;
						if (!object.Equals(val.BoxedValue, obj))
						{
							Apply(val, obj);
							list.Add(section + "/" + key + " = " + text);
						}
					}
				}
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)($"Settings from the server apply while you play here ({_server.Count})" + ((list.Count > 0) ? (": " + string.Join(", ", list.ToArray())) : "")));
				}
				ShowReadOnly();
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Could not read the server's settings: " + ex2.Message));
				}
			}
		}

		private void Apply(ConfigEntryBase e, object value)
		{
			bool saveOnConfigSet = _config.SaveOnConfigSet;
			_applying = true;
			try
			{
				_config.SaveOnConfigSet = false;
				e.BoxedValue = value;
			}
			finally
			{
				_config.SaveOnConfigSet = saveOnConfigSet;
				_applying = false;
			}
		}

		private void Restore()
		{
			if (_server.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<ConfigEntryBase, object> item in _own)
			{
				Apply(item.Key, item.Value);
			}
			_own.Clear();
			_server.Clear();
			ShowReadOnly();
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)"Your own settings apply again");
			}
		}

		private void OnChanged(object sender, EventArgs args)
		{
			if (_applying)
			{
				return;
			}
			ConfigEntryBase val = (ConfigEntryBase)((sender is ConfigEntryBase) ? sender : null);
			if (val == null)
			{
				return;
			}
			if (_server.TryGetValue(val, out var value))
			{
				if (!_reloading && CanEditServer)
				{
					SendEdit(val);
				}
				else
				{
					_own[val] = val.BoxedValue;
				}
				Apply(val, value);
			}
			else if (IsServer)
			{
				_changePending = true;
				if (Time.unscaledTime >= _nextChangeSend)
				{
					SendChange();
				}
			}
		}

		private void SendChange()
		{
			_changePending = false;
			_nextChangeSend = Time.unscaledTime + 0.5f;
			if (!IsServer)
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer?.m_rpc == null)
				{
					continue;
				}
				if (_directPeers.Contains(peer.m_rpc))
				{
					if (_entries.Count > 0)
					{
						peer.m_rpc.Invoke(_dSend, new object[1] { Values() });
					}
				}
				else
				{
					SendRouted(peer.m_uid);
				}
			}
		}

		private void SendEdit(ConfigEntryBase e)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			ZNet instance = ZNet.instance;
			ZNetPeer val = ((instance != null) ? instance.GetServerPeer() : null);
			if (val?.m_rpc != null)
			{
				ZPackage val2 = new ZPackage();
				val2.Write(e.Definition.Section);
				val2.Write(e.Definition.Key);
				val2.Write(TomlTypeConverter.ConvertToString(e.BoxedValue, e.SettingType));
				val.m_rpc.Invoke(_edit, new object[1] { val2 });
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)("Asked the server to set " + e.Definition.Section + "/" + e.Definition.Key));
				}
			}
		}

		private void OnEdit(ZRpc rpc, ZPackage pkg)
		{
			try
			{
				if (!IsServer)
				{
					return;
				}
				ISocket socket = rpc.GetSocket();
				string text = ((socket != null) ? socket.GetHostName() : null) ?? "";
				ZNetPeer val = ((IEnumerable<ZNetPeer>)ZNet.instance.GetPeers()).FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.m_rpc == rpc));
				string section = pkg.ReadString();
				string key = pkg.ReadString();
				string text2 = pkg.ReadString();
				if (!ZNet.instance.IsAdmin(text))
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)((val?.m_playerName ?? text) + " tried to change " + section + "/" + key + " but isn't on the admin list"));
					}
					if (_entries.Count > 0)
					{
						rpc.Invoke(_dSend, new object[1] { Values() });
					}
					return;
				}
				ConfigEntryBase val2 = ((IEnumerable<ConfigEntryBase>)_entries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase x) => x.Definition.Section == section && x.Definition.Key == key));
				if (val2 != null)
				{
					val2.BoxedValue = TomlTypeConverter.ConvertToValue(text2, val2.SettingType);
					ManualLogSource log2 = _log;
					if (log2 != null)
					{
						log2.LogInfo((object)("Admin " + (val?.m_playerName ?? text) + " set " + section + "/" + key + " = " + text2));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = _log;
				if (log3 != null)
				{
					log3.LogWarning((object)("Could not take an admin's change: " + ex.Message));
				}
			}
		}

		private void ShowReadOnly()
		{
			bool flag = FromServer && !CanEditServer;
			if (flag == _readOnlyShown)
			{
				return;
			}
			_readOnlyShown = flag;
			foreach (ConfigEntryBase entry in _entries)
			{
				ConfigDescription description = entry.Description;
				object[] array = ((description != null) ? description.Tags : null) ?? new object[0];
				foreach (object obj in array)
				{
					if (IsManagerAttributes(obj))
					{
						try
						{
							AccessTools.Field(obj.GetType(), "ReadOnly")?.SetValue(obj, flag ? ((object)true) : null);
						}
						catch (Exception)
						{
						}
					}
				}
			}
		}

		private static bool IsManagerAttributes(object tag)
		{
			if (tag != null)
			{
				return tag.GetType().Name == "ConfigurationManagerAttributes";
			}
			return false;
		}

		private string OwnText(SyncedText t)
		{
			try
			{
				return t.Own() ?? "";
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Could not read " + t.Key + ": " + ex.Message));
				}
				return t.Given ?? "";
			}
		}

		private void Give(SyncedText t, string text)
		{
			if (t.Given != null && t.Given == text)
			{
				return;
			}
			t.Given = text;
			try
			{
				t.Use(text);
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Could not use " + t.Key + ": " + ex));
				}
			}
		}

		private void RestoreTexts(bool give)
		{
			foreach (SyncedText text in _texts)
			{
				text.Incoming = null;
				if (!text.FromServer)
				{
					continue;
				}
				text.FromServer = false;
				if (give)
				{
					Give(text, OwnText(text));
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)("Your own " + text.Key + " applies again"));
					}
				}
			}
		}

		private void AskTexts(ZRpc server)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			if (_texts.Count == 0 || server == null)
			{
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(_texts.Count);
			foreach (SyncedText text in _texts)
			{
				val.Write(text.Key);
			}
			server.Invoke(_dTextAsk, new object[1] { val });
		}

		private void OnTextAsk(ZRpc rpc, ZPackage pkg)
		{
			try
			{
				if (!IsServer)
				{
					return;
				}
				int num = pkg.ReadInt();
				HashSet<string> hashSet = new HashSet<string>();
				for (int i = 0; i < num && i < 1000; i++)
				{
					string key = pkg.ReadString();
					if (_texts.Any((SyncedText x) => x.Key == key))
					{
						hashSet.Add(key);
					}
				}
				if (_textPeers.TryGetValue(rpc, out var value))
				{
					hashSet.UnionWith(value);
				}
				foreach (ZRpc item in _textPeers.Keys.Where((ZRpc r) => !r.IsConnected()).ToList())
				{
					_textPeers.Remove(item);
				}
				_textPeers[rpc] = hashSet;
				foreach (SyncedText text in _texts)
				{
					if (hashSet.Contains(text.Key))
					{
						SendText(rpc, text);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Could not answer a player's ask for server data: " + ex.Message));
				}
			}
		}

		private void SendTexts()
		{
			_textPending = false;
			_nextTextSend = Time.unscaledTime + 0.5f;
			if (!IsServer)
			{
				return;
			}
			foreach (SyncedText text in _texts)
			{
				if (!text.Pending)
				{
					continue;
				}
				text.Pending = false;
				foreach (ZNetPeer peer in ZNet.instance.GetPeers())
				{
					if (peer?.m_rpc != null && _textPeers.TryGetValue(peer.m_rpc, out var value) && value.Contains(text.Key))
					{
						SendText(peer.m_rpc, text);
					}
				}
			}
		}

		private void SendText(ZRpc rpc, SyncedText t)
		{
			byte[] array = Packed(t);
			if (array != null)
			{
				_outbox.RemoveAll((Sending s) => s.Rpc == rpc && s.Key == t.Key);
				_outbox.Add(new Sending
				{
					Rpc = rpc,
					Key = t.Key,
					Data = array,
					Parts = Math.Max(1, (array.Length + 65536 - 1) / 65536)
				});
				Pump();
			}
		}

		private void Pump()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			for (int num = _outbox.Count - 1; num >= 0; num--)
			{
				Sending sending = _outbox[num];
				try
				{
					while (sending.Next < sending.Parts && sending.Rpc.IsConnected() && sending.Rpc.GetSocket().GetSendQueueSize() < 10240)
					{
						int num2 = sending.Next * 65536;
						int num3 = Math.Min(65536, sending.Data.Length - num2);
						byte[] array = new byte[num3];
						Buffer.BlockCopy(sending.Data, num2, array, 0, num3);
						ZPackage val = new ZPackage();
						val.Write(sending.Key);
						val.Write(sending.Next);
						val.Write(sending.Parts);
						val.Write(array);
						sending.Rpc.Invoke(_dText, new object[1] { val });
						sending.Next++;
					}
					if (sending.Next >= sending.Parts || !sending.Rpc.IsConnected())
					{
						_outbox.RemoveAt(num);
					}
				}
				catch (Exception ex)
				{
					_outbox.RemoveAt(num);
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)("Could not send " + sending.Key + " to a player: " + ex.Message));
					}
				}
			}
		}

		private byte[] Packed(SyncedText t)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (t.Packed == null)
			{
				string text = OwnText(t);
				ZPackage val = new ZPackage();
				val.Write(text);
				ZPackage val2 = new ZPackage();
				bool flag = text.Length > 1024;
				val2.Write(flag);
				if (flag)
				{
					val2.WriteCompressed(val);
				}
				else
				{
					val2.Write(val);
				}
				t.Packed = val2.GetArray();
				t.TooBig = t.Packed.Length > 8388608;
				string arg = $"{t.Packed.Length / 1024} KB" + (flag ? $" gzipped ({text.Length / 1024} KB of text)" : "");
				if (t.TooBig)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogError((object)$"{t.Key} is too big to send to players ({arg}, at most {8} MB): they keep their own.");
					}
				}
				else if (t.Packed.Length > 262144)
				{
					ManualLogSource log2 = _log;
					if (log2 != null)
					{
						log2.LogWarning((object)$"{t.Key} is big to send to every player who joins ({arg}): it takes about {(float)t.Packed.Length / 153600f:0} s of their connection, and their world loads slower meanwhile.");
					}
				}
			}
			if (!t.TooBig)
			{
				return t.Packed;
			}
			return null;
		}

		private void OnText(ZRpc rpc, ZPackage pkg)
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			if (!IsServerConnection(rpc))
			{
				return;
			}
			SyncedText syncedText = null;
			try
			{
				string key = pkg.ReadString();
				int num = pkg.ReadInt();
				int num2 = pkg.ReadInt();
				byte[] array = pkg.ReadByteArray();
				syncedText = _texts.FirstOrDefault((SyncedText x) => x.Key == key);
				if (syncedText == null)
				{
					return;
				}
				if (num2 < 1 || num2 > 129 || num < 0 || num >= num2)
				{
					throw new InvalidDataException($"part {num} of {num2}");
				}
				if (num == 0)
				{
					syncedText.Incoming = new MemoryStream();
					syncedText.NextPart = 0;
				}
				if (syncedText.Incoming == null || num != syncedText.NextPart)
				{
					throw new InvalidDataException($"part {num} came out of order");
				}
				syncedText.Incoming.Write(array, 0, array.Length);
				syncedText.NextPart = num + 1;
				if (num >= num2 - 1)
				{
					ZPackage val = new ZPackage(syncedText.Incoming.ToArray());
					syncedText.Incoming = null;
					ZPackage val2 = (val.ReadBool() ? val.ReadCompressedPackage() : val.ReadPackage());
					string text = val2.ReadString();
					syncedText.FromServer = true;
					Give(syncedText, text);
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogInfo((object)$"The server's {key} applies while you play here ({text.Length / 1024} KB)");
					}
				}
			}
			catch (Exception ex)
			{
				if (syncedText != null)
				{
					syncedText.Incoming = null;
				}
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Could not read the server's data" + ((syncedText != null) ? (" for " + syncedText.Key) : "") + ": " + ex.Message));
				}
			}
		}

		private void SetServer(ServerMod state, string version, int protocol)
		{
			if (state != ServerMod.Checking)
			{
				_askedAt = -1f;
			}
			bool flag = state != Server || version != ServerVersion;
			Server = state;
			ServerVersion = version;
			_serverProtocol = protocol;
			if (!flag)
			{
				return;
			}
			Guard();
			try
			{
				this.ServerChanged?.Invoke();
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("ServerChanged: " + ex));
				}
			}
		}

		private void Guard()
		{
			bool flag = Server == ServerMod.NotConnected || Server == ServerMod.Installed;
			bool flag2 = false;
			foreach (GameObject guardedPiece in _guardedPieces)
			{
				Piece val = (((Object)(object)guardedPiece != (Object)null) ? guardedPiece.GetComponent<Piece>() : null);
				if ((Object)(object)val != (Object)null && val.m_enabled != flag)
				{
					val.m_enabled = flag;
					flag2 = true;
				}
			}
			foreach (Recipe guardedRecipe in _guardedRecipes)
			{
				if ((Object)(object)guardedRecipe != (Object)null && guardedRecipe.m_enabled != flag)
				{
					guardedRecipe.m_enabled = flag;
					flag2 = true;
				}
			}
			if (flag2 && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				try
				{
					UpdateAvailablePieces?.Invoke(Player.m_localPlayer, null);
				}
				catch (Exception)
				{
				}
			}
		}

		private void WatchFile()
		{
			try
			{
				string configFilePath = _config.ConfigFilePath;
				_watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath))
				{
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite)
				};
				FileSystemEventHandler value = delegate
				{
					_fileTouched = true;
				};
				_watcher.Changed += value;
				_watcher.Created += value;
				_watcher.Renamed += delegate
				{
					_fileTouched = true;
				};
				_watcher.EnableRaisingEvents = true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Edits to the config file apply after a restart (can't watch it: " + ex.Message + ")"));
				}
			}
		}

		private void ReloadFile()
		{
			string text = ReadFile(_config.ConfigFilePath);
			if (text == null)
			{
				if (File.Exists(_config.ConfigFilePath))
				{
					_reloadAt = Time.unscaledTime + 1f;
				}
			}
			else
			{
				if (text == _fileText)
				{
					return;
				}
				_fileText = text;
				bool saveOnConfigSet = _config.SaveOnConfigSet;
				_reloading = true;
				try
				{
					_config.SaveOnConfigSet = false;
					_config.Reload();
				}
				catch (Exception ex)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)("Could not read the edited config file (check the line you changed): " + ex.Message));
					}
				}
				finally
				{
					_config.SaveOnConfigSet = saveOnConfigSet;
					_reloading = false;
				}
			}
		}

		private void PatchSave()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0067: Expected O, but got Unknown
			try
			{
				_saveHarmony = new Harmony(_send + ".save");
				_saveHarmony.Patch((MethodBase)AccessTools.Method(typeof(ConfigFile), "Save", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ServerSettings), "BeforeSave", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ServerSettings), "AfterSave", (Type[])null), (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("Could not keep the server's values out of your config file: " + ex.Message));
				}
			}
		}

		private static void UnpatchSave()
		{
			try
			{
				Harmony saveHarmony = _saveHarmony;
				if (saveHarmony != null)
				{
					saveHarmony.UnpatchSelf();
				}
			}
			catch (Exception)
			{
			}
			_saveHarmony = null;
		}

		private static void BeforeSave(ConfigFile __instance)
		{
			foreach (ServerSettings item in Live)
			{
				if (item._config != __instance)
				{
					continue;
				}
				foreach (KeyValuePair<ConfigEntryBase, object> item2 in item._own)
				{
					SetQuietly(item2.Key, item2.Value);
				}
			}
		}

		private static Exception AfterSave(ConfigFile __instance, Exception __exception)
		{
			foreach (ServerSettings item in Live)
			{
				if (item._config != __instance)
				{
					continue;
				}
				foreach (KeyValuePair<ConfigEntryBase, object> item2 in item._server)
				{
					SetQuietly(item2.Key, item2.Value);
				}
				item._fileText = ReadFile(__instance.ConfigFilePath);
			}
			return __exception;
		}

		private static string ReadFile(string path)
		{
			try
			{
				return File.Exists(path) ? File.ReadAllText(path) : null;
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static void SetQuietly(ConfigEntryBase e, object value)
		{
			AccessTools.Field(((object)e).GetType(), "_typedValue")?.SetValue(e, value);
		}

		private static BepInPlugin PluginOf(string guid)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			Type[] array;
			try
			{
				array = typeof(ServerSettings).Assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				array = ex.Types.Where((Type t) => t != null).ToArray();
			}
			Type[] array2 = array;
			foreach (Type type in array2)
			{
				object[] customAttributes = type.GetCustomAttributes(typeof(BepInPlugin), inherit: false);
				for (int num2 = 0; num2 < customAttributes.Length; num2++)
				{
					BepInPlugin val = (BepInPlugin)customAttributes[num2];
					if (val.GUID == guid || guid.StartsWith(val.GUID + "."))
					{
						return val;
					}
				}
			}
			return null;
		}

		private void Unsubscribe(ConfigEntryBase e)
		{
			((object)e).GetType().GetEvent("SettingChanged")?.RemoveEventHandler(e, new EventHandler(OnChanged));
		}
	}
}
namespace WardrobePortal
{
	internal static class Cabinet
	{
		public const string DoorPrefix = "door_hinge";

		private const float HingeX = 0.635f;

		private const float HingeZ = 0.45f;

		private static readonly Bounds RightDoor = Box(-0.645f, 0.01f, 0.1f, 2.58f, 0.34f, 0.6f);

		private static readonly Bounds Shelves = Box(-0.72f, 0.72f, 0.3f, 2.4f, -0.5f, 0.4f);

		private static Mesh _cut;

		private static bool _tried;

		private const float InnerSide = 0.64f;

		private const float InnerBack = -0.34f;

		private static Bounds Box(float x0, float x1, float y0, float y1, float z0, float z1)
		{
			//IL_0002: 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_0017: 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)
			Bounds result = default(Bounds);
			((Bounds)(ref result)).SetMinMax(new Vector3(x0, y0, z0), new Vector3(x1, y1, z1));
			return result;
		}

		public static MeshRenderer Build(Transform parent, GameObject wardrobe)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			Transform val = wardrobe.transform.Find("New");
			object obj;
			if (val == null)
			{
				obj = null;
			}
			else
			{
				Transform obj2 = val.Find("blackmetalchest");
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<MeshFilter>() : null);
			}
			MeshFilter val2 = (MeshFilter)obj;
			object obj3;
			if (val == null)
			{
				obj3 = null;
			}
			else
			{
				Transform obj4 = val.Find("Closed/blackmetalchesttop_closed");
				obj3 = ((obj4 != null) ? ((Component)obj4).GetComponent<MeshFilter>() : null);
			}
			MeshFilter val3 = (MeshFilter)obj3;
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				throw new Exception("the wardrobe's model has changed (no blackmetalchest or its door)");
			}
			Mesh val4 = CutBody(val2.sharedMesh);
			bool flag = (Object)(object)val4 != (Object)(object)val2.sharedMesh;
			GameObject val5 = new GameObject("cabinet");
			val5.transform.SetParent(parent, false);
			val5.AddComponent<MeshFilter>().sharedMesh = val4;
			MeshRenderer val6 = val5.AddComponent<MeshRenderer>();
			((Renderer)val6).sharedMaterials = ((Renderer)((Component)val2).GetComponent<MeshRenderer>()).sharedMaterials;
			Material[] sharedMaterials = ((Renderer)((Component)val3).GetComponent<MeshRenderer>()).sharedMaterials;
			AddDoor(parent, val3.sharedMesh, sharedMaterials, 1f);
			if (flag)
			{
				AddDoor(parent, val3.sharedMesh, sharedMaterials, -1f);
			}
			return val6;
		}

		private static void AddDoor(Transform parent, Mesh mesh, Material[] mats, float side)
		{
			//IL_001e: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0076: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = new GameObject("door_hinge_" + ((side > 0f) ? "left" : "right")).transform;
			transform.SetParent(parent, false);
			transform.localPosition = new Vector3(side * 0.635f, 0f, 0.45f);
			GameObject val = new GameObject("door");
			val.transform.SetParent(transform, false);
			val.transform.localScale = new Vector3(side, 1f, 1f);
			val.transform.localPosition = new Vector3((0f - side) * 0.635f, 0f, -0.45f);
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterials = mats;
			((Component)transform).gameObject.layer = LayerMask.NameToLayer("piece");
			BoxCollider val2 = ((Component)transform).gameObject.AddComponent<BoxCollider>();
			val2.center = new Vector3((0f - side) * 0.315f, 1.34f, 0f);
			val2.size = new Vector3(0.62f, 2.4f, 0.08f);
		}

		private static Mesh CutBody(Mesh src)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			if ((Object)(object)_cut != (Object)null)
			{
				return _cut;
			}
			if (_tried || (int)SystemInfo.graphicsDeviceType == 4)
			{
				return src;
			}
			_tried = true;
			try
			{
				_cut = Cut(src, Remove, out var kept, out var removed);
				Plugin.Log.LogInfo((object)$"Wardrobe cabinet: kept {kept} triangles, cut {removed} (the right door and the shelves)");
				return _cut;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't read the wardrobe's mesh, so it keeps its one door: " + ex.Message));
				return src;
			}
		}

		private static bool Remove(Vector3 a, Vector3 b, Vector3 c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			//IL_004f: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0087: 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)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			Bounds val = RightDoor;
			if (((Bounds)(ref val)).Contains(a))
			{
				val = RightDoor;
				if (((Bounds)(ref val)).Contains(b))
				{
					val = RightDoor;
					if (((Bounds)(ref val)).Contains(c))
					{
						return true;
					}
				}
			}
			val = Shelves;
			if (((Bounds)(ref val)).Contains(a))
			{
				val = Shelves;
				if (((Bounds)(ref val)).Contains(b))
				{
					val = Shelves;
					if (((Bounds)(ref val)).Contains(c))
					{
						Vector3 val2 = Vector3.Cross(b - a, c - a);
						Vector3 normalized = ((Vector3)(ref val2)).normalized;
						float num = Mathf.Min(Mathf.Abs(a.x), Mathf.Min(Mathf.Abs(b.x), Mathf.Abs(c.x)));
						float num2 = Mathf.Max(a.z, Mathf.Max(b.z, c.z));
						bool flag = Mathf.Abs(normalized.x) > 0.9f && num > 0.64f;
						bool flag2 = Mathf.Abs(normalized.z) > 0.9f && num2 < -0.34f;
						if (!flag)
						{
							return !flag2;
						}
						return false;
					}
				}
			}
			return false;
		}

		private static Mesh Cut(Mesh src, Func<Vector3, Vector3, Vector3, bool> remove, out int kept, out int removed)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Invalid comparison between Unknown and I4
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			if (src.subMeshCount != 1)
			{
				throw new Exception($"{src.subMeshCount} submeshes");
			}
			SubMeshDescriptor subMesh = src.GetSubMesh(0);
			if ((int)((SubMeshDescriptor)(ref subMesh)).topology != 0)
			{
				throw new Exception("not triangles");
			}
			GraphicsBuffer indexBuffer = src.GetIndexBuffer();
			if (indexBuffer == null)
			{
				throw new Exception("its triangle list isn't on the graphics card");
			}
			byte[] ib = Read(indexBuffer);
			VertexAttributeDescriptor[] vertexAttributes = src.GetVertexAttributes();
			int vertexCount = src.vertexCount;
			int vertexAttributeStream = src.GetVertexAttributeStream((VertexAttribute)0);
			int vertexAttributeOffset = src.GetVertexAttributeOffset((VertexAttribute)0);
			if ((int)src.GetVertexAttributeFormat((VertexAttribute)0) != 0)
			{
				throw new Exception("positions not 32-bit floats");
			}
			Mesh val = new Mesh
			{
				name = ((Object)src).name + "_wardrobeportal"
			};
			val.indexFormat = src.indexFormat;
			val.SetVertexBufferParams(vertexCount, vertexAttributes);
			Vector3[] array = (Vector3[])(object)new Vector3[vertexCount];
			int vertexBufferCount = src.vertexBufferCount;
			for (int i = 0; i < vertexBufferCount; i++)
			{
				byte[] array2 = Read(src.GetVertexBuffer(i));
				int vertexBufferStride = src.GetVertexBufferStride(i);
				if (array2.Length < vertexBufferStride * vertexCount)
				{
					throw new Exception($"vertex stream {i}: {array2.Length} bytes, wanted {vertexBufferStride * vertexCount}");
				}
				val.SetVertexBufferData<byte>(array2, 0, 0, vertexBufferStride * vertexCount, i, (MeshUpdateFlags)1);
				if (i == vertexAttributeStream)
				{
					for (int j = 0; j < vertexCount; j++)
					{
						int num = j * vertexBufferStride + vertexAttributeOffset;
						array[j] = new Vector3(BitConverter.ToSingle(array2, num), BitConverter.ToSingle(array2, num + 4), BitConverter.ToSingle(array2, num + 8));
					}
				}
			}
			bool wide = (int)src.indexFormat == 1;
			List<int> list = new List<int>(((SubMeshDescriptor)(ref subMesh)).indexCount);
			removed = 0;
			for (int k = ((SubMeshDescriptor)(ref subMesh)).indexStart; k + 2 < ((SubMeshDescriptor)(ref subMesh)).indexStart + ((SubMeshDescriptor)(ref subMesh)).indexCount; k += 3)
			{
				int num2 = Index(k) + ((SubMeshDescriptor)(ref subMesh)).baseVertex;
				int num3 = Index(k + 1) + ((SubMeshDescriptor)(ref subMesh)).baseVertex;
				int num4 = Index(k + 2) + ((SubMeshDescriptor)(ref subMesh)).baseVertex;
				if (remove(array[num2], array[num3], array[num4]))
				{
					removed++;
					continue;
				}
				list.Add(num2);
				list.Add(num3);
				list.Add(num4);
			}
			kept = list.Count / 3;
			val.SetIndexBufferParams(list.Count, val.indexFormat);
			if (wide)
			{
				val.SetIndexBufferData<uint>(list.ConvertAll((int t) => (uint)t), 0, 0, list.Count, (MeshUpdateFlags)0);
			}
			else
			{
				val.SetIndexBufferData<ushort>(list.ConvertAll((int t) => (ushort)t), 0, 0, list.Count, (MeshUpdateFlags)0);
			}
			val.SetSubMesh(0, new SubMeshDescriptor(0, list.Count, (MeshTopology)0), (MeshUpdateFlags)0);
			val.RecalculateBounds();
			val.UploadMeshData(false);
			return val;
			int Index(int num5)
			{
				if (!wide)
				{
					return BitConverter.ToUInt16(ib, num5 * 2);
				}
				return (int)BitConverter.ToUInt32(ib, num5 * 4);
			}
		}

		private static byte[] Read(GraphicsBuffer buffer)
		{
			try
			{
				int num = buffer.count * buffer.stride;
				int[] array = new int[(num + 3) / 4];
				buffer.GetData((Array)array);
				byte[] array2 = new byte[num];
				Buffer.BlockCopy(array, 0, array2, 0, num);
				return array2;
			}
			finally
			{
				((IDisposable)buffer)?.Dispose();
			}
		}
	}
	internal static class Costs
	{
		public const string Help = "Item prefab names and amounts, separated by commas, like FineWood:12, BronzeNails:30 (Claude Tools' `prefabs <text>` shows exact names). A cost with a mistake in it keeps the last good one.";

		public const string StationHelp = "The crafting station's prefab name (piece_workbench, forge, piece_stonecutter, piece_artisanstation, blackforge, piece_magetable), or none.";

		public static Requirement[] Parse(string text, List<string> problems, bool forRecipe)
		{
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Expected O, but got Unknown
			problems = problems ?? new List<string>();
			int count = problems.Count;
			List<Requirement> list = new List<Requirement>();
			string[] array = (text ?? "").Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.Length == 0)
				{
					continue;
				}
				string[] array2 = (from b in text3.Split(new char[1] { ':' })
					select b.Trim()).ToArray();
				if (array2.Length < 2 || array2.Length > 3 || !Whole(array2[1], out var value) || value < 1)
				{
					problems.Add("\"" + text3 + "\" isn't Name:amount");
					continue;
				}
				int value2 = 0;
				bool result = true;
				if (array2.Length == 3)
				{
					bool num;
					if (!forRecipe)
					{
						num = bool.TryParse(array2[2], out result);
					}
					else
					{
						if (!Whole(array2[2], out value2))
						{
							goto IL_0116;
						}
						num = value2 >= 0;
					}
					if (!num)
					{
						goto IL_0116;
					}
				}
				ItemDrop item = FindItem(array2[0]);
				if ((Object)(object)item == (Object)null)
				{
					problems.Add("no item called \"" + array2[0] + "\"");
					continue;
				}
				if (list.Any((Requirement r) => (Object)(object)r.m_resItem == (Object)(object)item))
				{
					problems.Add(array2[0] + " is listed twice");
					continue;
				}
				list.Add(new Requirement
				{
					m_resItem = item,
					m_amount = value,
					m_amountPerLevel = value2,
					m_recover = result
				});
				continue;
				IL_0116:
				problems.Add(forRecipe ? ("\"" + text3 + "\": the upgrade amount isn't a number") : ("\"" + text3 + "\": the last part isn't true or false"));
			}
			if (list.Count == 0 && problems.Count == count)
			{
				problems.Add("it's empty (nothing would be free: write at least one item)");
			}
			if (problems.Count != count)
			{
				return null;
			}
			return list.ToArray();
		}

		private static bool Whole(string text, out int value)
		{
			return int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out value);
		}

		public static string Write(IEnumerable<Requirement> cost, bool forRecipe)
		{
			return string.Join(", ", (from r in cost ?? Enumerable.Empty<Requirement>()
				where (Object)(object)r?.m_resItem != (Object)null
				select ((Object)r.m_resItem).name + ":" + r.m_amount + ((!forRecipe) ? (r.m_recover ? "" : ":false") : ((r.m_amountPerLevel > 0) ? (":" + r.m_amountPerLevel) : ""))).ToArray());
		}

		public static ItemDrop FindItem(string name)
		{
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null);
			if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				val = ObjectDB.instance.GetItemPrefab(name);
			}
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<ItemDrop>();
		}

		public static CraftingStation FindStation(string name, out bool found)
		{
			name = (name ?? "").Trim();
			found = true;
			if (name.Length == 0 || name.Equals("none", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null);
			CraftingStation val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<CraftingStation>() : null);
			found = (Object)(object)val2 != (Object)null;
			return val2;
		}

		public static bool Apply(Piece piece, string text, ManualLogSource log)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return false;
			}
			List<string> problems = new List<string>();
			Requirement[] array = Parse(text, problems, forRecipe: false);
			Report(log, ((Object)piece).name, problems);
			if (array == null)
			{
				return false;
			}
			piece.m_resources = array;
			return true;
		}

		public static bool Apply(Recipe recipe, string text, ManualLogSource log)
		{
			if ((Object)(object)recipe == (Object)null)
			{
				return false;
			}
			List<string> problems = new List<string>();
			Requirement[] array = Parse(text, problems, forRecipe: true);
			Report(log, ((Object)recipe).name, problems);
			if (array == null)
			{
				return false;
			}
			recipe.m_resources = array;
			return true;
		}

		public static bool ApplyStation(Piece piece, string text, ManualLogSource log)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return false;
			}
			bool found;
			CraftingStation craftingStation = FindStation((text ?? "").Split(new char[1] { ':' })[0], out found);
			if (!found)
			{
				if (log != null)
				{
					log.LogWarning((object)(((Object)piece).name + ": no crafting station called \"" + text + "\", it keeps its station"));
				}
				return false;
			}
			piece.m_craftingStation = craftingStation;
			return true;
		}

		public static bool ApplyStation(Recipe recipe, string text, ManualLogSource log)
		{
			if ((Object)(object)recipe == (Object)null)
			{
				return false;
			}
			string[] array = (text ?? "").Split(new char[1] { ':' });
			bool found;
			CraftingStation craftingStation = FindStation(array[0], out found);
			int value = 1;
			if (!found || (array.Length > 1 && (!Whole(array[1].Trim(), out value) || value < 1)))
			{
				if (log != null)
				{
					log.LogWarning((object)(((Object)recipe).name + ": \"" + text + "\" isn't a crafting station (and level), it keeps its station"));
				}
				return false;
			}
			recipe.m_craftingStation = craftingStation;
			recipe.m_minStationLevel = value;
			return true;
		}

		private static void Report(ManualLogSource log, string what, List<string> problems)
		{
			if (problems.Count > 0 && log != null)
			{
				log.LogWarning((object)(what + "'s cost setting has a mistake, so it keeps its last cost: " + string.Join("; ", problems.ToArray())));
			}
		}
	}
	internal static class Icon
	{
		private const int Size = 128;

		private static readonly Vector3 DefaultView = new Vector3(0.42f, 0.28f, -1f);

		private static int _layer = -1;

		private static readonly MethodInfo LoadImageMethod = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", new Type[2]
		{
			typeof(Texture2D),
			typeof(byte[])
		});

		private static int Layer
		{
			get
			{
				if (_layer < 0)
				{
					_layer = 31;
					for (int num = 31; num >= 8; num--)
					{
						if (string.IsNullOrEmpty(LayerMask.LayerToName(num)))
						{
							_layer = num;
							break;
						}
					}
				}
				return _layer;
			}
		}

		private static bool CanDraw => (int)SystemInfo.graphicsDeviceType != 4;

		private static string ModName => typeof(Icon).Assembly.GetName().Name;

		internal static Sprite Make(GameObject prefab, Vector3? view = null, Action<GameObject> pose = null, string fallback = "icon.png")
		{
			//IL_0017: 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)
			Sprite val = null;
			try
			{
				val = DrawPiece(prefab, (Vector3)(((??)view) ?? DefaultView), pose);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[" + ModName + "] could not draw the build icon: " + ex.Message));
			}
			if (!((Object)(object)val != (Object)null))
			{
				return LoadSprite(fallback);
			}
			return val;
		}

		internal static Sprite MakeItem(GameObject itemPrefab, bool setIcon = false, string fallback = null, Quaternion? look = null)
		{
			Sprite val = null;
			try
			{
				val = DrawItem(itemPrefab, look);
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[" + ModName + "] could not draw the icon of " + (((Object)(object)itemPrefab != (Object)null) ? ((Object)itemPrefab).name : "an item") + ": " + ex.Message));
			}
			Sprite val2 = (((Object)(object)val != (Object)null) ? val : LoadSprite(fallback));
			if (setIcon && (Object)(object)val2 != (Object)null && (Object)(object)itemPrefab != (Object)null)
			{
				ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
				if ((Object)(object)component != (Object)null)
				{
					SharedData shared = component.m_itemData.m_shared;
					Sprite[] array = (Sprite[])((shared.m_icons != null && shared.m_icons.Length > 1) ? ((Array)(Sprite[])shared.m_icons.Clone()) : ((Array)new Sprite[1]));
					array[0] = val2;
					shared.m_icons = array;
				}
			}
			return val2;
		}

		private static Sprite DrawPiece(GameObject prefab, Vector3 view, Action<GameObject> pose)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null || !CanDraw)
			{
				return null;
			}
			Transform val = prefab.transform.Find("Model");
			return Draw(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : prefab, (Object)(object)val == (Object)null, Quaternion.identity, pose, delegate(GameObject stage, Bounds bounds)
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: 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)
				//IL_0069: 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)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				Camera val2 = AddCamera(stage);
				val2.fieldOfView = 24f;
				val2.nearClipPlane = 0.1f;
				val2.farClipPlane = 60f;
				Vector3 extents = ((Bounds)(ref bounds)).extents;
				float magnitude = ((Vector3)(ref extents)).magnitude;
				((Component)val2).transform.position = ((Bounds)(ref bounds)).center + ((Vector3)(ref view)).normalized * (magnitude / Mathf.Sin(val2.fieldOfView * 0.5f * ((float)Math.PI / 180f))) * 1.02f;
				((Component)val2).transform.LookAt(((Bounds)(ref bounds)).center);
				AddLight(stage, Quaternion.Euler(38f, 28f, 0f), 1.25f);
				return val2;
			}, 0.08f);
		}

		private static Sprite DrawItem(GameObject itemPrefab, Quaternion? look)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)itemPrefab == (Object)null || !CanDraw)
			{
				return null;
			}
			Transform val = itemPrefab.transform.Find("attach");
			return Draw(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : itemPrefab, bare: true, ((Object)(object)val != (Object)null) ? val.localRotation : Quaternion.identity, null, delegate(GameObject stage, Bounds bounds)
			{
				//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_0031: 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_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: 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_0068: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: 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_00b8: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_015b: 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_015e: 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_016d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0175: Unknown result type (might be due to invalid IL or missing references)
				//IL_017c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0183: Unknown result type (might be due to invalid IL or missing references)
				//IL_018a: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ca: 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_01d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_0211: Unknown result type (might be due to invalid IL or missing references)
				//IL_0221: Unknown result type (might be due to invalid IL or missing references)
				//IL_0226: Unknown result type (might be due to invalid IL or missing references)
				//IL_022b: Unknown result type (might be due to invalid IL or missing references)
				//IL_022e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0230: Unknown result type (might be due to invalid IL or missing references)
				//IL_0231: Unknown result type (might be due to invalid IL or missing references)
				//IL_0236: Unknown result type (might be due to invalid IL or missing references)
				//IL_023b: 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_011a: Unknown result type (might be due to invalid IL or missing references)
				//IL_011f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0121: Unknown result type (might be due to invalid IL or missing references)
				//IL_0122: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_012b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				//IL_013a: Unknown result type (might be due to invalid IL or missing references)
				//IL_013c: Unknown result type (might be due to invalid IL or missing references)
				//IL_013d: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0144: Unknown result type (might be due to invalid IL or missing references)
				//IL_0145: Unknown result type (might be due to invalid IL or missing references)
				//IL_0147: Unknown result type (might be due to invalid IL or missing references)
				//IL_0149: Unknown result type (might be due to invalid IL or missing references)
				//IL_014e: Unknown result type (might be due to invalid IL or missing references)
				Camera val2 = AddCamera(stage);
				val2.orthographic = true;
				Vector3 size = ((Bounds)(ref bounds)).size;
				Quaternion val3 = (look.HasValue ? look.Value : ((size.y <= size.x * 1.15f && size.y <= size.z * 1.15f) ? Quaternion.LookRotation(Vector3.down, Vector3.forward) : ((!(size.x <= size.z)) ? Quaternion.LookRotation(Vector3.forward, Vector3.up) : Quaternion.LookRotation(Vector3.right, Vector3.up))));
				if (!look.HasValue)
				{
					val3 *= Quaternion.Euler(0f, 0f, 45f);
				}
				((Component)val2).transform.rotation = val3;
				Vector3 val4 = Vector3.positiveInfinity;
				Vector3 val5 = Vector3.negativeInfinity;
				for (int i = 0; i < 8; i++)
				{
					Vector3 val6 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((i & 1) != 0) ? 1 : (-1)), (float)(((i & 2) != 0) ? 1 : (-1)), (float)(((i & 4) != 0) ? 1 : (-1))));
					Vector3 val7 = Quaternion.Inverse(val3) * (val6 - ((Bounds)(ref bounds)).center);
					val4 = Vector3.Min(val4, val7);
					val5 = Vector3.Max(val5, val7);
				}
				Vector3 val8 = (val4 + val5) * 0.5f;
				val2.orthographicSize = Mathf.Max(0.01f, Mathf.Max(val5.x - val4.x, val5.y - val4.y) * 0.5f * 1.08f);
				float num = val5.z - val4.z;
				((Component)val2).transform.position = ((Bounds)(ref bounds)).center + val3 * new Vector3(val8.x, val8.y, val4.z - 1f);
				val2.nearClipPlane = 0.01f;
				val2.farClipPlane = num + 2f;
				Vector3 val9 = val3 * new Vector3(0.4f, -0.5f, 1f);
				AddLight(stage, Quaternion.LookRotation(val9, val3 * Vector3.up), 1.3f);
				return val2;
			}, 0.02f);
		}

		private static Sprite Draw(GameObject source, bool bare, Quaternion turn, Action<GameObject> pose, Func<GameObject, Bounds, Camera> frame, float minCover)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: 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_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			int layer = Layer;
			bool forceDisableInit = ZNetView.m_forceDisableInit;
			bool forceDisableTerrainOps = TerrainOp.m_forceDisableTerrainOps;
			RenderTexture active = RenderTexture.active;
			RenderTexture val = null;
			Camera val2 = null;
			GameObject val3 = new GameObject(ModName + "IconStage");
			val3.SetActive(false);
			val3.transform.position = new Vector3(0f, -3000f, 0f);
			try
			{
				ZNetView.m_forceDisableInit = true;
				TerrainOp.m_forceDisableTerrainOps = true;
				GameObject val4 = Object.Instantiate<GameObject>(source, val3.transform);
				val4.transform.localPosition = Vector3.zero;
				val4.transform.localRotation = turn;
				val4.SetActive(true);
				if (bare)
				{
					Strip(val4);
				}
				Transform[] componentsInChildren = val4.GetComponentsInChildren<Transform>(true);
				foreach (Transform val5 in componentsInChildren)
				{
					((Component)val5).gameObject.layer = layer;
				}
				if (!bare)
				{
					Renderer[] componentsInChildren2 = val4.GetComponentsInChildren<Renderer>(true);
					foreach (Renderer val6 in componentsInChildren2)
					{
						val6.enabled = true;
					}
				}
				val3.SetActive(true);
				pose?.Invoke(val4);
				Bounds arg = default(Bounds);
				bool flag = false;
				Renderer[] componentsInChildren3 = val4.GetComponentsInChildren<Renderer>();
				foreach (Renderer val7 in componentsInChildren3)
				{
					if (val7.enabled && !IsParticles(val7))
					{
						if (!flag)
						{
							arg = val7.bounds;
							flag = true;
						}
						else
						{
							((Bounds)(ref arg)).Encapsulate(val7.bounds);
						}
					}
				}
				if (!flag)
				{
					return null;
				}
				val2 = frame(val3, arg);
				val2.cullingMask = 1 << layer;
				val = (val2.targetTexture = RenderTexture.GetTemporary(256, 256, 24, (RenderTextureFormat)0));
				AmbientMode ambientMode = RenderSettings.ambientMode;
				Color ambientLight = RenderSettings.ambientLight;
				float reflectionIntensity = RenderSettings.reflectionIntensity;
				RenderSettings.ambientMode = (AmbientMode)3;
				RenderSettings.ambientLight = new Color(0.5f, 0.5f, 0.5f);
				RenderSettings.reflectionIntensity = 0.25f;
				try
				{
					val2.Render();
				}
				finally
				{
					RenderSettings.ambientMode = ambientMode;
					RenderSettings.ambientLight = ambientLight;
					RenderSettings.reflectionIntensity = reflectionIntensity;
				}
				RenderTexture.active = val;
				Texture2D val8 = new Texture2D(((Texture)val).width, ((Texture)val).height, (TextureFormat)4, false);
				val8.ReadPixels(new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), 0, 0);
				val8.Apply();
				if (LooksFine(val8, minCover))
				{
					return Sprite.Create(val8, new Rect(0f, 0f, (float)((Texture)val8).width, (float)((Texture)val8).height), new Vector2(0.5f, 0.5f), 100f);
				}
				Object.Destroy((Object)(object)val8);
				return null;
			}
			finally
			{
				ZNetView.m_forceDisableInit = forceDisableInit;
				TerrainOp.m_forceDisableTerrainOps = forceDisableTerrainOps;
				RenderTexture.active = active;
				if ((Object)(object)val2 != (Object)null)
				{
					val2.targetTexture = null;
				}
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
				Object.DestroyImmediate((Object)(object)val3);
			}
		}

		private static bool IsParticles(Renderer r)
		{
			if (!(r is TrailRenderer) && !(r is LineRenderer))
			{
				return ((object)r).GetType().Name == "ParticleSystemRenderer";
			}
			return true;
		}

		private static Camera AddCamera(GameObject stage)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("IconCamera");
			val.transform.SetParent(stage.transform, false);
			Camera val2 = val.AddComponent<Camera>();
			((Behaviour)val2).enabled = false;
			val2.clearFlags = (CameraClearFlags)2;
			val2.backgroundColor = new Color(0f, 0f, 0f, 0f);
			val2.allowHDR = false;
			val2.allowMSAA = false;
			val2.cullingMask = 1 << Layer;
			return val2;
		}

		private static void AddLight(GameObject stage, Quaternion rotation, float intensity)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("IconLight");
			val.transform.SetParent(stage.transform, false);
			val.transform.rotation = rotation;
			Light val2 = val.AddComponent<Light>();
			val2.type = (LightType)1;
			val2.intensity = intensity;
			val2.shadows = (LightShadows)0;
			val2.cullingMask = 1 << Layer;
		}

		private static void Strip(GameObject copy)
		{
			Transform[] componentsInChildren = copy.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				List<MonoBehaviour> list = new List<MonoBehaviour>(((Component)val).GetComponents<MonoBehaviour>());
				for (int j = 0; j < 4; j++)
				{
					if (list.Count <= 0)
					{
						break;
					}
					for (int num = list.Count - 1; num >= 0; num--)
					{
						if ((Object)(object)list[num] == (Object)null)
						{
							list.RemoveAt(num);
						}
						else if (!Needed(list[num], list))
						{
							Object.DestroyImmediate((Object)(object)list[num]);
							list.RemoveAt(num);
						}
					}
				}
			}
			Collider[] componentsInChildren2 = copy.GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				val2.enabled = false;
			}
			Rigidbody[] componentsInChildren3 = copy.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val3 in componentsInChildren3)
			{
				val3.isKinematic = true;
				val3.detectCollisions = false;
			}
		}

		private static bool Needed(MonoBehaviour script, List<MonoBehaviour> others)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			Type type = ((object)script).GetType();
			foreach (MonoBehaviour other in others)
			{
				if ((Object)(object)other == (Object)null || (Object)(object)other == (Object)(object)script)
				{
					continue;
				}
				object[] customAttributes = ((object)other).GetType().GetCustomAttributes(typeof(RequireComponent), inherit: true);
				for (int i = 0; i < customAttributes.Length; i++)
				{
					RequireComponent val = (RequireComponent)customAttributes[i];
					if (Is(val.m_Type0, type) || Is(val.m_Type1, type) || Is(val.m_Type2, type))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool Is(Type required, Type type)
		{
			if (required != null)
			{
				return required.IsAssignableFrom(type);
			}
			return false;
		}

		private static bool LooksFine(Texture2D tex, float minCover)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			Color32[] pixels = tex.GetPixels32();
			int num = 0;
			long num2 = 0L;
			for (int i = 0; i < pixels.Length; i += 7)
			{
				Color32 val = pixels[i];
				if (val.a > 40)
				{
					num++;
					num2 += val.r + val.g + val.b;
				}
			}
			int num3 = pixels.Length / 7 + 1;
			if ((float)num > (float)num3 * minCover)
			{
				return num2 / Math.Max(1, num) > 60;
			}
			return false;
		}

		private static bool LoadImage(Texture2D tex, byte[] data)
		{
			if (LoadImageMethod != null)
			{
				return (bool)LoadImageMethod.Invoke(null, new object[2] { tex, data });
			}
			return false;
		}

		internal static Texture2D LoadEmbedded(string name)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			using Stream stream = typeof(Icon).Assembly.GetManifestResourceStream(name);
			if (stream == null)
			{
				return null;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			return LoadImage(val, array) ? val : null;
		}

		internal static Sprite LoadSprite(string name)
		{
			//IL_0029: 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)
			Texture2D val = LoadEmbedded(name);
			if (!((Object)(object)val == (Object)null))
			{
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			}
			return null;
		}
	}
	[BepInPlugin("nick.valheim.wardrobeportal", "WardrobePortal", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "nick.valheim.wardrobeportal";

		public const string Name = "WardrobePortal";

		public const string Version = "1.0.0";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ServerSettings Synced;

		internal static ConfigEntry<string> Cost;

		internal static ConfigEntry<string> Station;

		internal static ConfigEntry<float> OpenDistance;

		internal static ConfigEntry<float> OpenAngle;

		internal static ConfigEntry<float> DoorSpeed;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Translations.Load((BaseUnityPlugin)(object)this);
			Synced = new ServerSettings("nick.valheim.wardrobeportal", ((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			Cost = Synced.Bind("1 - Building", "Cost", "Frostwood:10, Tar:2, BlackMetal:6, SurtlingCore:2, GreydwarfEye:10", "What a Wardrobe Portal costs to build (by default the wardrobe's cost, plus the two Surtling Cores and ten Greydwarf Eyes a portal takes). Item prefab names and amounts, separated by commas, like FineWood:12, BronzeNails:30 (Claude Tools' `prefabs <text>` shows exact names). A cost with a mistake in it keeps the last good one.", null);
			Station = Synced.Bind("1 - Building", "Station", "piece_workbench", "The crafting station that must be near to build it. The crafting station's prefab name (piece_workbench, forge, piece_stonecutter, piece_artisanstation, blackforge, piece_magetable), or none.", null);
			OpenDistance = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Doors", "Open distance", 4f, new ConfigDescription("The doors swing open when a player comes this close (metres).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			OpenAngle = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Doors", "Open angle", 110f, new ConfigDescription("How far the doors swing open (degrees).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 170f), Array.Empty<object>()));
			DoorSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Doors", "Door speed", 180f, new ConfigDescription("How fast the doors swing (degrees a second).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 720f), Array.Empty<object>()));
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			((BaseUnityPlugin)this).Config.Save();
			Cost.SettingChanged += delegate
			{
				WardrobePiece.ApplyCost();
			};
			Station.SettingChanged += delegate
			{
				WardrobePiece.ApplyCost();
			};
			_harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "nick.valheim.wardrobeportal");
			WardrobePiece.Register(ZNetScene.instance);
			Log.LogInfo((object)"WardrobePortal 1.0.0 loaded");
		}

		private void Update()
		{
			Synced?.Update();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			WardrobePiece.Unload();
			Synced?.Dispose();
			Translations.Unload();
			Instance = null;
			Synced = null;
		}
	}
	internal class WardrobeDoors : MonoBehaviour
	{
		private class Door
		{
			public Transform T;

			public Quaternion Shut;

			public float Sign;
		}

		private const string ClosedKey = "nick_wardrobeportal_closed";

		private const string ToggleRpc = "WardrobePortal_Toggle";

		private const string ArrivedKey = "nick_wardrobeportal_arrived";

		private const string ArriveRpc = "WardrobePortal_Arrive";

		private const float ArrivalSeconds = 4f;

		internal static ZDOID Pending = ZDOID.None;

		internal static float PendingSince;

		private ZNetView _nview;

		private TeleportWorld _portal;

		private readonly List<Door> _doors = new List<Door>();

		private float _angle;

		private bool _playerNear;

		private float _nextLook;

		public bool Closed
		{
			get
			{
				if ((Object)(object)_nview != (Object)null && _nview.IsValid())
				{
					return _nview.GetZDO().GetBool("nick_wardrobeportal_closed", false);
				}
				return false;
			}
		}

		public bool Arriving
		{
			get
			{
				if (Closed && (Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.GetTime().Ticks < _nview.GetZDO().GetLong("nick_wardrobeportal_arrived", 0L);
				}
				return false;
			}
		}

		public bool Asleep
		{
			get
			{
				if (Closed)
				{
					return !Arriving;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			_nview = ((Component)this).GetComponent<ZNetView>();
			_portal = ((Component)this).GetComponent<TeleportWorld>();
			if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			_nview.Register<bool>("WardrobePortal_Toggle", (Action<long, bool>)RPC_Toggle);
			_nview.Register("WardrobePortal_Arrive", (Action<long>)RPC_Arrive);
			Transform val = ((Component)this).transform.Find("wardrobe");
			if ((Object)(object)val != (Object)null)
			{
				foreach (Transform item in val)
				{
					Transform val2 = item;
					if (((Object)val2).name.StartsWith("door_hinge", StringComparison.Ordinal))
					{
						_doors.Add(new Door
						{
							T = val2,
							Shut = val2.localRotation,
							Sign = ((val2.localPosition.x < 0f) ? (-1f) : 1f)
						});
					}
				}
			}
			if (_doors.Count == 0)
			{
				Plugin.Log.LogWarning((object)"Wardrobe Portal: no doors found on the model (they don't swing)");
			}
		}

		public void RequestToggle(Humanoid human)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false))
			{
				((Character)human).Message((MessageType)2, "$piece_noaccess", 0, (Sprite)null, false);
				return;
			}
			_nview.InvokeRPC("WardrobePortal_Toggle", new object[1] { !Closed });
		}

		private void RPC_Toggle(long sender, bool closed)
		{
			try
			{
				if (_nview.IsValid() && _nview.IsOwner())
				{
					_nview.GetZDO().Set("nick_wardrobeportal_closed", closed);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Wardrobe Portal toggle: " + ex));
			}
		}

		private void RPC_Arrive(long sender)
		{
			try
			{
				if (_nview.IsValid() && _nview.IsOwner())
				{
					_nview.GetZDO().Set("nick_wardrobeportal_arrived", ZNet.instance.GetTime().AddSeconds(4.0).Ticks);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Wardrobe Portal arrival: " + ex));
			}
		}

		private void CheckArrival()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_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)
			if (Pending == ZDOID.None)
			{
				return;
			}
			if (Time.time - PendingSince > 60f)
			{
				Pending = ZDOID.None;
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsTeleporting() && !(Pending != _nview.GetZDO().m_uid) && !(Vector3.Distance(((Component)localPlayer).transform.position, ((Component)this).transform.position) > 8f))
			{
				Pending = ZDOID.None;
				if (Closed)
				{
					_nview.InvokeRPC("WardrobePortal_Arrive", Array.Empty<object>());
				}
			}
		}

		private void Update()
		{
			//IL_002b: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			CheckArrival();
			if (Time.time >= _nextLook)
			{
				_nextLook = Time.time + 0.25f;
				_playerNear = (Object)(object)Player.GetClosestPlayer(((Component)this).transform.position, Plugin.OpenDistance.Value) != (Object)null;
			}
			float num = ((!Asleep && _playerNear) ? Plugin.OpenAngle.Value : 0f);
			if (Mathf.Approximately(_angle, num))
			{
				return;
			}
			_angle = Mathf.MoveTowards(_angle, num, Plugin.DoorSpeed.Value * Time.deltaTime);
			foreach (Door door in _doors)
			{
				door.T.localRotation = door.Shut * Quaternion.Euler(0f, door.Sign * _angle, 0f);
			}
		}

		public string HoverText()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return "";
			}
			string text = (((Object)(object)_portal != (Object)null) ? _portal.GetText() : "");
			string text2 = (Closed ? Translations.T("wardrobeportal_closed") : "$piece_portal_connected");
			if (!Closed && _nview.GetZDO().GetConnectionZDOID((ConnectionType)1) == ZDOID.None)
			{
				text2 = "$piece_portal_unconnected";
			}
			return Localization.instance.Localize(Translations.T("wardrobeportal_piece") + " $piece_portal_tag:\"" + text + "\" [" + text2 + "]\n[<color=yellow><b>$KEY_Use</b></color>] $piece_portal_settag\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] " + Translations.T(Closed ? "wardrobeportal_open" : "wardrobeportal_close"));
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Interact")]
	internal static class TeleportWorld_Interact
	{
		private static bool Prefix(TeleportWorld __instance, Humanoid human, bool hold, bool alt, ref bool __result)
		{
			WardrobeDoors component = ((Component)__instance).GetComponent<WardrobeDoors>();
			if ((Object)(object)component == (Object)null || !alt)
			{
				return true;
			}
			__result = false;
			if (hold)
			{
				return false;
			}
			component.RequestToggle(human);
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "GetHoverText")]
	internal static class TeleportWorld_GetHoverText
	{
		private static void Postfix(TeleportWorld __instance, ref string __result)
		{
			WardrobeDoors component = ((Component)__instance).GetComponent<WardrobeDoors>();
			if ((Object)(object)component != (Object)null)
			{
				__result = component.HoverText();
			}
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	internal static class TeleportWorld_Teleport
	{
		private static bool Prefix(TeleportWorld __instance)
		{
			WardrobeDoors component = ((Component)__instance).GetComponent<WardrobeDoors>();
			if (!((Object)(object)component == (Object)null))
			{
				return !component.Closed;
			}
			return true;
		}

		private static void Postfix(TeleportWorld __instance, Player player)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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)
			//IL_0050: 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_007d: 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)
			try
			{
				if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && ((Character)player).IsTeleporting())
				{
					ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
					ZDO val = (((Object)(object)component != (Object)null) ? component.GetZDO() : null);
					ZDOID val2 = ((val != null) ? val.GetConnectionZDOID((ConnectionType)1) : ZDOID.None);
					ZDO val3 = ((val2 != ZDOID.None) ? ZDOMan.instance.GetZDO(val2) : null);
					if (val3 != null && val3.GetPrefab() == WardrobePiece.Hash)
					{
						WardrobeDoors.Pending = val2;
						WardrobeDoors.PendingSince = Time.time;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Wardrobe Portal: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "UpdatePortal")]
	internal static class TeleportWorld_UpdatePortal
	{
		private static void Postfix(TeleportWorld __instance)
		{
			WardrobeDoors component = ((Component)__instance).GetComponent<WardrobeDoors>();
			if ((Object)(object)component != (Object)null && component.Asleep && (Object)(object)__instance.m_target_found != (Object)null)
			{
				__instance.m_target_found.SetActive(false);
			}
		}
	}
	internal static class WardrobePiece
	{
		public const string PrefabName = "nick_wardrobeportal";

		public const string PieceName = "$wardrobeportal_piece";

		private const string PortalSource = "portal_wood";

		private const string WardrobeSource = "piece_chest_warderobe";

		internal static GameObject Prefab;

		private static PieceTable _table;

		private static GameObject _holder;

		private static readonly FieldRef<ZNetScene, Dictionary<int, GameObject>> NamedPrefabs = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs");

		private static readonly Vector3 SwirlScale = new Vector3(0.38f, 0.62f, 0.38f);

		private static readonly Vector3 SwirlAt = new Vector3(0f, 0.45f, -0.05f);

		private static readonly Vector3 TriggerAt = new Vector3(0f, 1.2f, 0.15f);

		private static readonly Vector3 TriggerScale = new Vector3(0.65f, 1.2f, 0.4f);

		private const float Wall = 0.05f;

		private const float FrontZSign = 1f;

		public static int Hash => StringExtensionMethods.GetStableHashCode("nick_wardrobeportal");

		public static void Register(ZNetScene scene)
		{
			if ((Object)(object)scene == (Object)null)
			{
				return;
			}
			if ((Object)(object)Prefab == (Object)null)
			{
				Prefab = Build(scene);
			}
			if ((Object)(object)Prefab == (Object)null)
			{
				return;
			}
			if (!scene.m_prefabs.Contains(Prefab))
			{
				scene.m_prefabs.Add(Prefab);
			}
			NamedPrefabs.Invoke(scene)[Hash] = Prefab;
			GameObject prefab = scene.GetPrefab("Hammer");
			PieceTable val = ((!((Object)(object)prefab != (Object)null)) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces);
			if ((Object)(object)val != (Object)null)
			{
				val.m_pieces.RemoveAll((GameObject p) => (Object)(object)p == (Object)null);
				if (!val.m_pieces.Contains(Prefab))
				{
					val.m_pieces.Add(Prefab);
				}
				_table = val;
			}
			ApplyCost();
			Plugin.Synced.NeedsServer(Prefab);
			AddPortalHash();
		}

		public static void ApplyCost()
		{
			Piece val = (((Object)(object)Prefab != (Object)null) ? Prefab.GetComponent<Piece>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				Costs.Apply(val, Plugin.Cost.Value, Plugin.Log);
				Costs.ApplyStation(val, Plugin.Station.Value, Plugin.Log);
			}
		}

		public static void AddPortalHash()
		{
			if ((Object)(object)Game.instance != (Object)null && !Game.instance.PortalPrefabHash.Contains(Hash))
			{
				Game.instance.PortalPrefabHash.Add(Hash);
			}
		}

		public static void Unload()
		{
			if ((Object)(object)_table != (Object)null && (Object)(object)Prefab != (Object)null)
			{
				_table.m_pieces.Remove(Prefab);
			}
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)Prefab != (Object)null)
			{
				instance.m_prefabs.Remove(Prefab);
				if (NamedPrefabs.Invoke(instance).TryGetValue(Hash, out var value) && (Object)(object)value == (Object)(object)Prefab)
				{
					NamedPrefabs.Invoke(instance).Remove(Hash);
				}
			}
			if ((Object)(object)_holder != (Object)null)
			{
				Object.Destroy((Object)(object)_holder);
			}
			Prefab = null;
			_table = null;
			_holder = null;
		}

		private static GameObject Build(ZNetScene scene)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			GameObject prefab = scene.GetPrefab("portal_wood");
			GameObject prefab2 = scene.GetPrefab("piece_chest_warderobe");
			if ((Object)(object)prefab == (Object)null || (Object)(object)prefab2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)("The game has no " + (((Object)(object)prefab == (Object)null) ? "portal_wood" : "piece_chest_warderobe") + " to copy: no Wardrobe Portal this session"));
				return null;
			}
			_holder = new GameObject("WardrobePortal_prefabs");
			_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_holder);
			GameObject val = Object.Instantiate<GameObject>(prefab, _holder