Decompiled source of Wisplight Arrows v1.0.0

plugins/WisplightArrows.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: 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;
		}
	}
}
internal sealed class ConfigurationManagerAttributes
{
	public bool? IsAdvanced;
}
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 WisplightArrows
{
	internal static class ArrowIcon
	{
		private const float Shrink = 0.9f;

		private const float OrbRadius = 0.075f;

		private const float HeadLength = 0.18f;

		private const float ShaftHalf = 0.022f;

		private const float CorePart = 0.45f;

		private const float HazeRadius = 0.24f;

		private const float HazeStrength = 0.85f;

		private const float EdgeFade = 0.08f;

		private static readonly Color GlassTint = new Color(0.62f, 0.8f, 0.95f);

		private static readonly Color CoreColour = new Color(0.55f, 0.95f, 1f);

		private static readonly Color HazeColour = new Color(0.45f, 0.75f, 1f);

		private static readonly string[] Bases = new string[3] { "ArrowSilver", "ArrowFlint", "ArrowWood" };

		public static Sprite FromGame(ZNetScene scene)
		{
			//IL_0086: 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)
			Sprite val = null;
			string[] bases = Bases;
			foreach (string text in bases)
			{
				GameObject prefab = scene.GetPrefab(text);
				object obj;
				if (!((Object)(object)prefab != (Object)null))
				{
					obj = null;
				}
				else
				{
					ItemDrop component = prefab.GetComponent<ItemDrop>();
					obj = ((component != null) ? component.m_itemData.GetIcon() : null);
				}
				val = (Sprite)obj;
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			Texture2D val2 = Copy(val);
			if ((Object)(object)val2 == (Object)null)
			{
				return null;
			}
			Paint(val2, orb: true);
			return Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), 100f);
		}

		public static void AddHaze(Sprite drawn)
		{
			Texture2D val = (((Object)(object)drawn != (Object)null) ? drawn.texture : null);
			if ((Object)(object)val != (Object)null && ((Texture)val).isReadable)
			{
				Paint(val, orb: false);
			}
		}

		private static Texture2D Copy(Sprite sprite)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null)
			{
				return null;
			}
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				return null;
			}
			Rect textureRect = sprite.textureRect;
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)sprite.texture).width, ((Texture)sprite.texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			RenderTexture active = RenderTexture.active;
			try
			{
				Graphics.Blit((Texture)(object)sprite.texture, temporary);
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(Mathf.RoundToInt(((Rect)(ref textureRect)).width), Mathf.RoundToInt(((Rect)(ref textureRect)).height), (TextureFormat)4, false);
				val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)((Texture)val).width, (float)((Texture)val).height), 0, 0);
				val.Apply();
				return val;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("Could not copy the arrow icon (" + ex.Message + "): the icon is drawn from the model"));
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		private static void Paint(Texture2D tex, bool orb)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			int width = ((Texture)tex).width;
			int height = ((Texture)tex).height;
			Color[] array = (Color[])(object)new Color[width * height];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					float num = ((float)j + 0.5f) / ((float)width * 0.9f);
					float num2 = 0.5f + (((float)i + 0.5f) / (float)height - 0.5f) / 0.9f;
					array[i * width + j] = ((num > 1f || num2 < 0f || num2 > 1f) ? Color.clear : tex.GetPixelBilinear(num, num2));
				}
			}
			int num3 = -1;
			int num4 = width - 1;
			while (num4 >= 0 && num3 < 0)
			{
				for (int k = 0; k < height; k++)
				{
					if (array[k * width + num4].a > 0.3f)
					{
						num3 = num4;
						break;
					}
				}
				num4--;
			}
			if (num3 < 0)
			{
				return;
			}
			int num5 = num3 - Mathf.RoundToInt((float)width * (orb ? 0.05f : 0.14f));
			float num6 = 0f;
			float num7 = 0f;
			int num8 = 0;
			for (int l = 0; l < height; l++)
			{
				for (int m = Mathf.Max(0, num5); m <= num3; m++)
				{
					if (array[l * width + m].a > 0.3f)
					{
						num6 += (float)m;
						num7 += (float)l;
						num8++;
					}
				}
			}
			if (num8 == 0)
			{
				return;
			}
			num6 /= (float)num8;
			num7 /= (float)num8;
			float num9 = (float)width * 0.075f;
			if (orb)
			{
				int num10 = num3 - Mathf.RoundToInt((float)width * 0.18f);
				float num11 = (float)height * 0.022f;
				for (int n = 0; n < height; n++)
				{
					if (Mathf.Abs((float)n - num7) > num11)
					{
						for (int num12 = Mathf.Max(0, num10); num12 <= num3; num12++)
						{
							array[n * width + num12] = Color.clear;
						}
					}
				}
				num6 = (float)num3 - num9 * 0.6f;
			}
			float num13 = (float)width * 0.24f;
			float num14 = (float)width * 0.08f;
			for (int num15 = 0; num15 < height; num15++)
			{
				for (int num16 = 0; num16 < width; num16++)
				{
					float num17 = (float)num16 - num6;
					float num18 = (float)num15 - num7;
					float num19 = Mathf.Sqrt(num17 * num17 + num18 * num18);
					Color val = array[num15 * width + num16];
					if (num19 < num13)
					{
						float num20 = num19 / num13;
						float num21 = Mathf.Clamp01((float)Mathf.Min(Mathf.Min(num16, width - 1 - num16), Mathf.Min(num15, height - 1 - num15)) / num14);
						val = Under(val, HazeColour, 0.85f * (1f - num20) * (1f - num20) * num21 * num21);
					}
					if (orb && num19 < num9 + 1f)
					{
						float num22 = num19 / num9;
						float num23 = Mathf.Clamp01(num9 + 0.5f - num19);
						float a = Mathf.Lerp(0.35f, 0.85f, num22 * num22 * num22) * num23;
						val = Over(val, GlassTint, a);
						float num24 = Mathf.Clamp01(1f - num22 / 0.45f);
						val = Over(val, CoreColour, Mathf.Clamp01(num24 * 2.2f));
						val = Over(val, Color.white, Mathf.Clamp01(num24 * num24 * 1.5f));
						float num25 = Mathf.Clamp01(1f - Vector2.Distance(new Vector2(num17, num18), new Vector2(-0.38f, 0.42f) * num9) / (num9 * 0.28f));
						val = Over(val, Color.white, num25 * num25 * 0.9f);
					}
					array[num15 * width + num16] = val;
				}
			}
			tex.SetPixels(array);
			tex.Apply();
		}

		private static Color Over(Color under, Color colour, float a)
		{
			//IL_000b: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (a <= 0f)
			{
				return under;
			}
			float num = a + under.a * (1f - a);
			if (num <= 0f)
			{
				return Color.clear;
			}
			Color val = (colour * a + under * under.a * (1f - a)) / num;
			return new Color(val.r, val.g, val.b, num);
		}

		private static Color Under(Color over, Color colour, float a)
		{
			//IL_000a: 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_0008: 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_002f: 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_003c: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_006a: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			if (a <= 0f)
			{
				return over;
			}
			float num = over.a + a * (1f - over.a);
			if (num <= 0f)
			{
				return Color.clear;
			}
			Color val = (over * over.a + colour * a * (1f - over.a)) / num;
			return new Color(val.r, val.g, val.b, num);
		}
	}
	internal static class ArrowItem
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class ZNetScene_Awake
		{
			private static void Postfix(ZNetScene __instance)
			{
				Guarded(delegate
				{
					Register(__instance, ObjectDB.instance);
				});
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake
		{
			private static void Postfix(ObjectDB __instance)
			{
				Guarded(delegate
				{
					Register(ZNetScene.instance, __instance);
				});
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDB_CopyOtherDB
		{
			private static void Postfix(ObjectDB __instance)
			{
				Guarded(delegate
				{
					Register(ZNetScene.instance, __instance);
				});
			}
		}

		public const string PrefabName = "nick_wisparrow";

		public const string ProjectileName = "nick_wisparrow_projectile";

		public const string GlowName = "nick_wisparrow_glow";

		internal static GameObject Prefab;

		private static GameObject _projectile;

		private static GameObject _glow;

		internal static GameObject NockTemplate;

		internal static GameObject TrailPoint;

		private static Recipe _recipe;

		internal static GameObject Glow => _glow;

		public static void Register(ZNetScene scene, ObjectDB db)
		{
			if ((Object)(object)scene == (Object)null && (Object)(object)db == (Object)null)
			{
				return;
			}
			scene = (((Object)(object)scene != (Object)null) ? scene : ZNetScene.instance);
			if ((Object)(object)Prefab == (Object)null && (Object)(object)scene != (Object)null)
			{
				Build(scene);
			}
			if (!((Object)(object)Prefab == (Object)null))
			{
				ItemReload.Replace(scene, db, (IEnumerable<GameObject>)(object)new GameObject[1] { Prefab });
				ItemReload.Replace(scene, null, (IEnumerable<GameObject>)(object)new GameObject[2] { _projectile, _glow });
				Content.ItemExtras((IEnumerable<GameObject>)(object)new GameObject[1] { Prefab }, db);
				if (!((Object)(object)db == (Object)null) && !((Object)(object)scene == (Object)null))
				{
					GameObject prefab = scene.GetPrefab("piece_workbench");
					CraftingStation station = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<CraftingStation>() : null);
					_recipe = Content.Recipe(Prefab, station, 1, Plugin.PerCraft.Value, null, Plugin.Cost.Value, Plugin.Log, null, upgradeOnly: false, null, db);
					ApplyRecipeSettings();
					Plugin.Synced.NeedsServer(_recipe);
				}
			}
		}

		public static void ApplyRecipeSettings()
		{
			if (!((Object)(object)_recipe == (Object)null))
			{
				Costs.Apply(_recipe, Plugin.Cost.Value, Plugin.Log);
				Costs.ApplyStation(_recipe, Plugin.Station.Value, Plugin.Log);
				_recipe.m_amount = Plugin.PerCraft.Value;
			}
		}

		public static void ApplyDamage()
		{
			//IL_0034: 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_004c: 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)
			ItemDrop val = (((Object)(object)Prefab != (Object)null) ? Prefab.GetComponent<ItemDrop>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				SharedData shared = val.m_itemData.m_shared;
				shared.m_damages = new DamageTypes
				{
					m_pierce = Plugin.Damage.Value
				};
				shared.m_damagesPerLevel = default(DamageTypes);
			}
		}

		public static void ApplyMist()
		{
			SetRadius(_projectile, Plugin.FlightRadius.Value);
			SetRadius(_glow, Plugin.LandingRadius.Value);
			TimedDestruction val = (((Object)(object)_glow != (Object)null) ? _glow.GetComponent<TimedDestruction>() : null);
			if ((Object)(object)val != (Object)null)
			{
				val.m_timeout = Plugin.LandingSeconds.Value;
			}
		}

		public static void Forget()
		{
			Prefab = null;
			_projectile = (_glow = (TrailPoint = (NockTemplate = null)));
			_recipe = null;
			ArrowModel.Forget();
		}

		private static void Guarded(Action register)
		{
			try
			{
				register();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Registering the wisplight arrow failed: " + ex));
			}
		}

		private static void Build(ZNetScene scene)
		{
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: 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_0070: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = scene.GetPrefab("ArrowWood");
			GameObject val = WispBall(scene);
			GameObject val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_attack.m_attackProjectile : null);
			if ((Object)(object)prefab == (Object)null || (Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"The game has no wooden arrow or Wisplight to copy: no wisplight arrows this session");
				return;
			}
			GameObject val3 = new GameObject("nick_wisparrow_holder");
			val3.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val3);
			_glow = new GameObject("nick_wisparrow_glow");
			_glow.transform.SetParent(val3.transform, false);
			_glow.AddComponent<ZNetView>();
			TimedDestruction val4 = _glow.AddComponent<TimedDestruction>();
			val4.m_triggerOnAwake = true;
			_glow.AddComponent<GlowFollow>();
			_glow.AddComponent<GlowFade>();
			AddWisp(val, _glow.transform, Vector3.zero);
			_projectile = Object.Instantiate<GameObject>(val2, val3.transform);
			((Object)_projectile).name = "nick_wisparrow_projectile";
			AddWisp(val, _projectile.transform, Vector3.zero);
			_projectile.AddComponent<MistTrail>();
			TrailPoint = BareField(val, val3.transform);
			NockTemplate = new GameObject("nick_wisparrow_nock");
			NockTemplate.transform.SetParent(val3.transform, false);
			AddWisp(val, NockTemplate.transform, Vector3.zero);
			Projectile component = _projectile.GetComponent<Projectile>();
			component.m_spawnOnHit = _glow;
			component.m_spawnOnHitChance = 1f;
			component.m_spawnCount = 1;
			component.m_spawnOnTtl = true;
			component.m_spawnOnCharacters = false;
			component.m_copyProjectileRotation = false;
			component.m_randomSpawnOnHit.Clear();
			component.m_spawnItem = null;
			Prefab = Object.Instantiate<GameObject>(prefab, val3.transform);
			((Object)Prefab).name = "nick_wisparrow";
			ItemDrop component2 = Prefab.GetComponent<ItemDrop>();
			SharedData shared = component2.m_itemData.m_shared;
			shared.m_name = "$nick_wisparrow";
			shared.m_description = "$nick_wisparrow_desc";
			shared.m_value = 0;
			shared.m_attack.m_attackProjectile = _projectile;
			component2.m_itemData.m_dropPrefab = Prefab;
			ApplyDamage();
			ApplyMist();
			try
			{
				ArrowModel.Dress(Prefab, val, scene, glow: true);
				ArrowModel.Dress(_projectile, val, scene, glow: false);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not put the orb on the arrow: " + ex));
			}
			Sprite val5 = null;
			try
			{
				val5 = ArrowIcon.FromGame(scene);
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogInfo((object)("Could not paint the icon from the game's: " + ex2.Message));
			}
			if ((Object)(object)val5 != (Object)null)
			{
				SetIcon(component2, val5);
				return;
			}
			try
			{
				ArrowModel.IconLook(Prefab, on: true);
				ArrowIcon.AddHaze(Icon.MakeItem(Prefab, setIcon: true, null, Quaternion.LookRotation(Vector3.right, Vector3.up)));
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogWarning((object)("Could not draw the wisplight arrow icon: " + ex3.Message));
			}
			finally
			{
				ArrowModel.IconLook(Prefab, on: false);
			}
		}

		private static void SetIcon(ItemDrop drop, Sprite icon)
		{
			SharedData shared = drop.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] = icon;
			shared.m_icons = array;
		}

		private static GameObject WispBall(ZNetScene scene)
		{
			GameObject prefab = scene.GetPrefab("Demister");
			ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
			return ((SE_Demister)((((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null)?)).m_ballPrefab;
		}

		private static void AddWisp(GameObject ball, Transform parent, Vector3 at)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(ball, parent, false);
			((Object)val).name = "wisp";
			val.transform.localPosition = at;
			val.transform.localRotation = Quaternion.identity;
			ZSyncTransform[] componentsInChildren = val.GetComponentsInChildren<ZSyncTransform>(true);
			foreach (ZSyncTransform val2 in componentsInChildren)
			{
				Object.DestroyImmediate((Object)(object)val2);
			}
			ZNetView[] componentsInChildren2 = val.GetComponentsInChildren<ZNetView>(true);
			foreach (ZNetView val3 in componentsInChildren2)
			{
				Object.DestroyImmediate((Object)(object)val3);
			}
			Rigidbody[] componentsInChildren3 = val.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val4 in componentsInChildren3)
			{
				Object.DestroyImmediate((Object)(object)val4);
			}
			Collider[] componentsInChildren4 = val.GetComponentsInChildren<Collider>(true);
			foreach (Collider val5 in componentsInChildren4)
			{
				Object.DestroyImmediate((Object)(object)val5);
			}
			Demister[] componentsInChildren5 = val.GetComponentsInChildren<Demister>(true);
			foreach (Demister val6 in componentsInChildren5)
			{
				if (val6.m_disableForcefieldDelay > 0f)
				{
					Plugin.Log.LogInfo((object)$"The wisp ball's force field switched itself off after {val6.m_disableForcefieldDelay} s: kept on");
				}
				val6.m_disableForcefieldDelay = 0f;
			}
		}

		private static GameObject BareField(GameObject ball, Transform holder)
		{
			Demister componentInChildren = ball.GetComponentInChildren<Demister>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)componentInChildren).gameObject, holder, false);
			((Object)val).name = "nick_wisparrow_trail";
			for (int num = val.transform.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(num)).gameObject);
			}
			Component[] components = val.GetComponents<Component>();
			foreach (Component val2 in components)
			{
				if (!(val2 is Transform) && !(val2 is Demister) && !(val2 is ParticleSystemForceField))
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			val.GetComponent<Demister>().m_disableForcefieldDelay = 0f;
			val.AddComponent<TrailPoint>();
			return val;
		}

		private static void SetRadius(GameObject prefab, float radius)
		{
			if (!((Object)(object)prefab == (Object)null))
			{
				ParticleSystemForceField[] componentsInChildren = prefab.GetComponentsInChildren<ParticleSystemForceField>(true);
				foreach (ParticleSystemForceField val in componentsInChildren)
				{
					val.endRange = radius;
				}
			}
		}
	}
	internal static class ArrowModel
	{
		private const float GlassSize = 0.095f;

		private const float PullBack = 0.03f;

		private const float CoreSize = 0.04f;

		private const float LightRange = 1.2f;

		private const float LightIntensity = 0.6f;

		private const float FlareScale = 0.3f;

		private const float SparkScale = 0.35f;

		private const float SparkRate = 0.25f;

		private static readonly Color GlassColour = new Color(0.78f, 0.9f, 1f, 0.3f);

		private static readonly Color IconGlassColour = new Color(0.6f, 0.8f, 1f, 0.6f);

		private static readonly Color WispColour = new Color(0.7f, 0.85f, 1f);

		private static Material _glass;

		private const float IconOrbScale = 3.5f;

		public static void Dress(GameObject root, GameObject ball, ZNetScene scene, bool glow)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Expected O, but got Unknown
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			MeshFilter val = null;
			MeshFilter[] componentsInChildren = root.GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val2 in componentsInChildren)
			{
				if ((Object)(object)val2.sharedMesh != (Object)null && (Object)(object)((Component)val2).transform.parent == (Object)(object)root.transform)
				{
					val = val2;
					break;
				}
			}
			Transform val3 = ball.transform.Find("demister_ball");
			MeshFilter val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<MeshFilter>() : null);
			MeshRenderer val5 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<MeshRenderer>() : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Could not find the arrow's or the wisp's model: the arrow keeps the wooden one's look");
				return;
			}
			GameObject val6 = new GameObject("orb")
			{
				layer = ((Component)val).gameObject.layer
			};
			val6.transform.SetParent(((Component)val).transform, false);
			Vector3 localScale = ((Component)val).transform.localScale;
			val6.transform.localPosition = Tip(val.sharedMesh) + new Vector3(0f, 0f, 0.03f / localScale.z);
			val6.transform.localScale = new Vector3(1f / localScale.x, 1f / localScale.y, 1f / localScale.z);
			Mesh sharedMesh = val4.sharedMesh;
			Bounds bounds = sharedMesh.bounds;
			float num = Mathf.Max(((Bounds)(ref bounds)).size.x, 0.0001f);
			Material val7 = GlassMat(scene);
			if ((Object)(object)val7 != (Object)null)
			{
				Part(val6, "glass", sharedMesh, val7, 0.095f / num);
			}
			Part(val6, "core", sharedMesh, ((Renderer)val5).sharedMaterial, 0.04f / num);
			if (glow)
			{
				GameObject val8 = new GameObject("light")
				{
					layer = val6.layer
				};
				val8.transform.SetParent(val6.transform, false);
				Light val9 = val8.AddComponent<Light>();
				val9.type = (LightType)2;
				val9.color = WispColour;
				val9.range = 1.2f;
				val9.intensity = 0.6f;
				val9.shadows = (LightShadows)0;
				Effect(ball, "effects/flame/flare", val6.transform, 0.3f, 1f);
				Effect(ball, "effects/flame/embers", val6.transform, 0.35f, 0.25f);
			}
		}

		public static void Forget()
		{
			_glass = null;
		}

		public static void IconLook(GameObject root, bool on)
		{
			//IL_001c: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0071: 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)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_glass != (Object)null)
			{
				_glass.color = (on ? IconGlassColour : GlassColour);
			}
			Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == "orb")
				{
					Vector3 localScale = val.parent.localScale;
					float num = (on ? 3.5f : 1f);
					val.localScale = new Vector3(num / localScale.x, num / localScale.y, num / localScale.z);
				}
			}
		}

		private static Vector3 Tip(Mesh mesh)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_006a: 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_0085: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = mesh.bounds;
			if (!mesh.isReadable)
			{
				Plugin.Log.LogInfo((object)"The arrow's mesh can't be read: the orb goes at the middle of its tip end");
				return new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y, ((Bounds)(ref bounds)).min.z);
			}
			Vector3[] vertices = mesh.vertices;
			Vector3 val = Vector3.zero;
			int num = 0;
			Vector3[] array = vertices;
			foreach (Vector3 val2 in array)
			{
				if (val2.z < ((Bounds)(ref bounds)).min.z + 0.02f)
				{
					val += val2;
					num++;
				}
			}
			if (num <= 0)
			{
				return new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y, ((Bounds)(ref bounds)).min.z);
			}
			return new Vector3(val.x / (float)num, val.y / (float)num, ((Bounds)(ref bounds)).min.z);
		}

		private static void Part(GameObject orb, string name, Mesh mesh, Material material, float scale)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//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)
			GameObject val = new GameObject(name)
			{
				layer = orb.layer
			};
			val.transform.SetParent(orb.transform, false);
			val.transform.localScale = Vector3.one * scale;
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			MeshRenderer val2 = val.AddComponent<MeshRenderer>();
			((Renderer)val2).sharedMaterial = material;
			((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
		}

		private static void Effect(GameObject ball, string path, Transform at, float size, float rate)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_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_00ae: 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)
			Transform val = ball.transform.Find(path);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogInfo((object)("The wisp ball has no " + path + ": the dropped arrow goes without it"));
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, at, false);
			((Object)val2).name = ((Object)val).name;
			val2.transform.localPosition = Vector3.zero;
			ParticleSystem[] componentsInChildren = val2.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val3 in componentsInChildren)
			{
				MainModule main = val3.main;
				((MainModule)(ref main)).startSizeMultiplier = ((MainModule)(ref main)).startSizeMultiplier * size;
				((MainModule)(ref main)).startSpeedMultiplier = ((MainModule)(ref main)).startSpeedMultiplier * size;
				EmissionModule emission = val3.emission;
				((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission)).rateOverTimeMultiplier * rate;
				ShapeModule shape = val3.shape;
				if (((ShapeModule)(ref shape)).enabled)
				{
					((ShapeModule)(ref shape)).radius = ((ShapeModule)(ref shape)).radius * size;
				}
			}
		}

		private static Material GlassMat(ZNetScene scene)
		{
			//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_00a7: 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_00b3: Expected O, but got Unknown
			if ((Object)(object)_glass != (Object)null)
			{
				return _glass;
			}
			Material val = null;
			GameObject prefab = scene.GetPrefab("crystal_wall_1x1");
			if ((Object)(object)prefab != (Object)null)
			{
				MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true);
				foreach (MeshRenderer val2 in componentsInChildren)
				{
					if ((Object)(object)((Renderer)val2).sharedMaterial != (Object)null && ((Object)((Renderer)val2).sharedMaterial).name.StartsWith("crystal_window", StringComparison.Ordinal))
					{
						val = ((Renderer)val2).sharedMaterial;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"The game has no crystal window glass: the orb goes without its glass");
				return null;
			}
			Material val3 = new Material(val)
			{
				name = "nick_wisparrow_glass",
				color = GlassColour
			};
			string[] array = new string[7] { "_MainTex", "_BumpMap", "_MetallicGlossMap", "_OcclusionMap", "_EmissionMap", "_DetailAlbedoMap", "_DetailNormalMap" };
			foreach (string text in array)
			{
				if (val3.HasProperty(text))
				{
					val3.SetTexture(text, (Texture)null);
				}
			}
			val3.DisableKeyword("_NORMALMAP");
			val3.DisableKeyword("_METALLICGLOSSMAP");
			val3.DisableKeyword("_EMISSION");
			if (val3.HasProperty("_Metallic"))
			{
				val3.SetFloat("_Metallic", 0f);
			}
			if (val3.HasProperty("_Glossiness"))
			{
				val3.SetFloat("_Glossiness", 0.95f);
			}
			_glass = val3;
			return val3;
		}
	}
	internal static class Content
	{
		private class Sale
		{
			public string Trader;

			public TradeItem Item;

			public Func<bool> When;
		}

		private static readonly FieldInfo NamedField = AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs");

		private static readonly MethodInfo UpdateRegisters = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null);

		private static readonly List<GameObject> OurItems = new List<GameObject>();

		private static readonly List<StatusEffect> OurEffects = new List<StatusEffect>();

		private static readonly Dictionary<string, Recipe> OurRecipes = new Dictionary<string, Recipe>();

		private static readonly List<(GameObject Station, string From, string To)> OurConversions = new List<(GameObject, string, string)>();

		private static readonly List<(GameObject Creature, string Item)> OurDrops = new List<(GameObject, string)>();

		private static readonly List<Sale> OurSales = new List<Sale>();

		private static Dictionary<int, GameObject> Named(ZNetScene scene)
		{
			return (Dictionary<int, GameObject>)NamedField.GetValue(scene);
		}

		private static bool Destroyed(Object o)
		{
			if (o != null)
			{
				return o == (Object)null;
			}
			return false;
		}

		public static void Item(GameObject prefab, ObjectDB db = null)
		{
			Items((IEnumerable<GameObject>)(object)new GameObject[1] { prefab }, db);
		}

		public static void Items(IEnumerable<GameObject> prefabs, ObjectDB db = null)
		{
			db = (((Object)(object)db != (Object)null) ? db : ObjectDB.instance);
			ZNetScene instance = ZNetScene.instance;
			bool flag = false;
			foreach (GameObject prefab in prefabs)
			{
				if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<ItemDrop>() == (Object)null)
				{
					continue;
				}
				if ((Object)(object)instance != (Object)null)
				{
					if (!instance.m_prefabs.Contains(prefab))
					{
						instance.m_prefabs.RemoveAll((GameObject p) => (Object)(object)p == (Object)null || ((Object)p).name == ((Object)prefab).name);
						instance.m_prefabs.Add(prefab);
					}
					Named(instance)[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab;
				}
				if ((Object)(object)db != (Object)null && !db.m_items.Contains(prefab))
				{
					db.m_items.RemoveAll((GameObject i) => (Object)(object)i == (Object)null || ((Object)i).name == ((Object)prefab).name);
					db.m_items.Add(prefab);
					flag = true;
				}
				if (!OurItems.Contains(prefab))
				{
					OurItems.Add(prefab);
				}
			}
			ItemExtras(prefabs, db);
			if (flag)
			{
				UpdateRegisters?.Invoke(db, null);
			}
		}

		public static void ItemExtras(IEnumerable<GameObject> prefabs, ObjectDB db = null)
		{
			db = (((Object)(object)db != (Object)null) ? db : ObjectDB.instance);
			foreach (GameObject prefab in prefabs)
			{
				ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				val.m_itemData.m_dropPrefab = prefab;
				if ((Object)(object)db == (Object)null)
				{
					continue;
				}
				SharedData shared = val.m_itemData.m_shared;
				StatusEffect[] array = (StatusEffect[])(object)new StatusEffect[4] { shared.m_consumeStatusEffect, shared.m_equipStatusEffect, shared.m_attackStatusEffect, shared.m_setStatusEffect };
				foreach (StatusEffect effect in array)
				{
					if ((Object)(object)effect == (Object)null)
					{
						continue;
					}
					if (!db.m_StatusEffects.Contains(effect))
					{
						db.m_StatusEffects.RemoveAll((StatusEffect e) => (Object)(object)e == (Object)null || ((Object)e).name == ((Object)effect).name);
						db.m_StatusEffects.Add(effect);
					}
					if (!OurEffects.Contains(effect))
					{
						OurEffects.Add(effect);
					}
				}
			}
		}

		public static void RemoveItems(IEnumerable<GameObject> prefabs)
		{
			ZNetScene instance = ZNetScene.instance;
			ObjectDB instance2 = ObjectDB.instance;
			HashSet<GameObject> gone = new HashSet<GameObject>(prefabs.Where((GameObject p) => p != null));
			foreach (GameObject item in gone)
			{
				OurItems.Remove(item);
				if ((Object)(object)instance != (Object)null)
				{
					instance.m_prefabs.Remove(item);
				}
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				if ((Object)(object)instance != (Object)null)
				{
					Dictionary<int, GameObject> dictionary = Named(instance);
					int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)item).name);
					if (dictionary.TryGetValue(stableHashCode, out var value) && (Object)(object)value == (Object)(object)item)
					{
						dictionary.Remove(stableHashCode);
					}
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if (!((Object)(object)component != (Object)null) || !((Object)(object)instance2 != (Object)null))
				{
					continue;
				}
				SharedData shared = component.m_itemData.m_shared;
				StatusEffect[] array = (StatusEffect[])(object)new StatusEffect[4] { shared.m_consumeStatusEffect, shared.m_equipStatusEffect, shared.m_attackStatusEffect, shared.m_setStatusEffect };
				foreach (StatusEffect val in array)
				{
					if ((Object)(object)val != (Object)null && OurEffects.Remove(val))
					{
						instance2.m_StatusEffects.Remove(val);
					}
				}
			}
			if ((Object)(object)instance2 != (Object)null)
			{
				instance2.m_items.RemoveAll((GameObject i) => (Object)(object)i == (Object)null || gone.Contains(i));
				instance2.m_StatusEffects.RemoveAll((StatusEffect e) => (Object)(object)e == (Object)null);
				UpdateRegisters?.Invoke(instance2, null);
			}
		}

		public static Recipe Recipe(GameObject item, CraftingStation station, int level = 1, int amount = 1, Requirement[] cost = null, string costText = null, ManualLogSource log = null, string way = null, bool upgradeOnly = false, CraftingStation repairStation = null, ObjectDB db = null)
		{
			ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			string name = "Recipe_" + ((Object)item).name + (string.IsNullOrEmpty(way) ? "" : ("_" + way));
			if (!OurRecipes.TryGetValue(name, out var value) || (Object)(object)value == (Object)null)
			{
				value = ScriptableObject.CreateInstance<Recipe>();
				((Object)value).name = name;
				value.m_item = val;
				value.m_amount = Mathf.Max(1, amount);
				value.m_craftingStation = station;
				value.m_repairStation = repairStation;
				value.m_minStationLevel = Mathf.Max(1, level);
				value.m_noCraftOnlyUpgrade = upgradeOnly;
				value.m_resources = (Requirement[])(((object)cost) ?? ((object)new Requirement[0]));
				if (costText != null)
				{
					Costs.Apply(value, costText, log);
				}
				OurRecipes[name] = value;
			}
			db = (((Object)(object)db != (Object)null) ? db : ObjectDB.instance);
			if ((Object)(object)db != (Object)null && !db.m_recipes.Contains(value))
			{
				db.m_recipes.RemoveAll((Recipe r) => (Object)(object)r == (Object)null || ((Object)r).name == name);
				db.m_recipes.Add(value);
			}
			return value;
		}

		public static void RemoveRecipe(Recipe recipe)
		{
			if (recipe == null)
			{
				return;
			}
			ObjectDB.instance?.m_recipes.RemoveAll((Recipe r) => (Object)(object)r == (Object)null || (Object)(object)r == (Object)(object)recipe);
			foreach (string item in (from kv in OurRecipes
				where (Object)(object)kv.Value == (Object)(object)recipe
				select kv.Key).ToList())
			{
				OurRecipes.Remove(item);
			}
			if ((Object)(object)recipe != (Object)null)
			{
				Object.Destroy((Object)(object)recipe);
			}
		}

		public static bool Conversion(GameObject stationPrefab, GameObject from, GameObject to, float cookSeconds = 10f, int makes = 4)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0080: Expected O, but got Unknown
			//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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			ItemDrop val = (((Object)(object)from != (Object)null) ? from.GetComponent<ItemDrop>() : null);
			ItemDrop val2 = (((Object)(object)to != (Object)null) ? to.GetComponent<ItemDrop>() : null);
			if ((Object)(object)stationPrefab == (Object)null || (Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return false;
			}
			RemoveConversion(stationPrefab, ((Object)from).name, ((Object)to).name, forget: false);
			bool flag = false;
			Smelter component = stationPrefab.GetComponent<Smelter>();
			if (component != null)
			{
				component.m_conversion.Add(new ItemConversion
				{
					m_from = val,
					m_to = val2
				});
				flag = true;
			}
			else
			{
				CookingStation component2 = stationPrefab.GetComponent<CookingStation>();
				if (component2 != null)
				{
					component2.m_conversion.Add(new ItemConversion
					{
						m_from = val,
						m_to = val2,
						m_cookTime = cookSeconds
					});
					flag = true;
				}
				else
				{
					Fermenter component3 = stationPrefab.GetComponent<Fermenter>();
					if (component3 != null)
					{
						component3.m_conversion.Add(new ItemConversion
						{
							m_from = val,
							m_to = val2,
							m_producedItems = Mathf.Max(1, makes)
						});
						flag = true;
					}
				}
			}
			if (flag && !OurConversions.Contains((stationPrefab, ((Object)from).name, ((Object)to).name)))
			{
				OurConversions.Add((stationPrefab, ((Object)from).name, ((Object)to).name));
			}
			return flag;
		}

		public static void RemoveConversion(GameObject stationPrefab, string from, string to)
		{
			RemoveConversion(stationPrefab, from, to, forget: true);
		}

		private static void RemoveConversion(GameObject stationPrefab, string from, string to, bool forget)
		{
			if (!((Object)(object)stationPrefab == (Object)null))
			{
				stationPrefab.GetComponent<Smelter>()?.m_conversion.RemoveAll((ItemConversion c) => c == null || Match(c.m_from, c.m_to));
				stationPrefab.GetComponent<CookingStation>()?.m_conversion.RemoveAll((ItemConversion c) => c == null || Match(c.m_from, c.m_to));
				stationPrefab.GetComponent<Fermenter>()?.m_conversion.RemoveAll((ItemConversion c) => c == null || Match(c.m_from, c.m_to));
				if (forget)
				{
					OurConversions.Remove((stationPrefab, from, to));
				}
			}
			bool Match(ItemDrop f, ItemDrop t)
			{
				if (!Destroyed((Object)(object)f) && !Destroyed((Object)(object)t))
				{
					if ((Object)(object)f != (Object)null && (Object)(object)t != (Object)null && ((Object)f).name == from)
					{
						return ((Object)t).name == to;
					}
					return false;
				}
				return true;
			}
		}

		public static Drop Drop(GameObject creaturePrefab, GameObject item, float chance = 1f, int min = 1, int max = 1, bool perLevel = true)
		{
			//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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_009b: Expected O, but got Unknown
			if ((Object)(object)creaturePrefab == (Object)null || (Object)(object)item == (Object)null)
			{
				return null;
			}
			CharacterDrop val = creaturePrefab.GetComponent<CharacterDrop>();
			if ((Object)(object)val == (Object)null)
			{
				val = creaturePrefab.AddComponent<CharacterDrop>();
			}
			val.m_drops.RemoveAll((Drop d) => d == null || Destroyed((Object)(object)d.m_prefab) || ((Object)(object)d.m_prefab != (Object)null && ((Object)d.m_prefab).name == ((Object)item).name));
			min = Mathf.Max(0, min);
			Drop val2 = new Drop
			{
				m_prefab = item,
				m_chance = Mathf.Clamp01(chance),
				m_amountMin = min,
				m_amountMax = Mathf.Max(min, max) + 1,
				m_levelMultiplier = perLevel
			};
			val.m_drops.Add(val2);
			if (!OurDrops.Contains((creaturePrefab, ((Object)item).name)))
			{
				OurDrops.Add((creaturePrefab, ((Object)item).name));
			}
			return val2;
		}

		public static void RemoveDrop(GameObject creaturePrefab, string item)
		{
			if (!((Object)(object)creaturePrefab == (Object)null))
			{
				creaturePrefab.GetComponent<CharacterDrop>()?.m_drops.RemoveAll((Drop d) => d == null || Destroyed((Object)(object)d.m_prefab) || ((Object)(object)d.m_prefab != (Object)null && ((Object)d.m_prefab).name == item));
				OurDrops.Remove((creaturePrefab, item));
			}
		}

		public static TradeItem Sell(Harmony harmony, string trader, GameObject item, int price, int stack = 1, string globalKey = null, Func<bool> when = null)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if (harmony == null || string.IsNullOrEmpty(trader) || (Object)(object)val == (Object)null)
			{
				return null;
			}
			Sale sale = OurSales.Find((Sale s) => s.Trader == trader && (Object)(object)s.Item.m_prefab != (Object)null && ((Object)s.Item.m_prefab).name == ((Object)item).name);
			if (sale == null)
			{
				List<Sale> ourSales = OurSales;
				Sale obj = new Sale
				{
					Trader = trader,
					Item = new TradeItem()
				};
				sale = obj;
				ourSales.Add(obj);
			}
			sale.Item.m_prefab = val;
			sale.Item.m_price = Mathf.Max(0, price);
			sale.Item.m_stack = Mathf.Max(1, stack);
			sale.Item.m_requiredGlobalKey = globalKey ?? "";
			sale.When = when;
			MethodInfo methodInfo = AccessTools.Method(typeof(Trader), "GetAvailableItems", (Type[])null, (Type[])null);
			MethodInfo postfix = AccessTools.Method(typeof(Content), "AddSales", (Type[])null, (Type[])null);
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo == null || !patchInfo.Postfixes.Any((Patch p) => p.owner == harmony.Id && p.PatchMethod == postfix))
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			return sale.Item;
		}

		public static void RemoveSale(string trader, string item)
		{
			OurSales.RemoveAll((Sale s) => s.Trader == trader && ((Object)(object)s.Item.m_prefab == (Object)null || ((Object)s.Item.m_prefab).name == item));
		}

		private static void AddSales(Trader __instance, List<TradeItem> __result)
		{
			if (__result == null || OurSales.Count == 0)
			{
				return;
			}
			string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject);
			foreach (Sale ourSale in OurSales)
			{
				if (!(ourSale.Trader != prefabName) && !((Object)(object)ourSale.Item.m_prefab == (Object)null) && !__result.Contains(ourSale.Item) && (string.IsNullOrEmpty(ourSale.Item.m_requiredGlobalKey) || (!((Object)(object)ZoneSystem.instance == (Object)null) && ZoneSystem.instance.GetGlobalKey(ourSale.Item.m_requiredGlobalKey))))
				{
					bool flag;
					try
					{
						flag = ourSale.When == null || ourSale.When();
					}
					catch
					{
						flag = false;
					}
					if (flag)
					{
						__result.Add(ourSale.Item);
					}
				}
			}
		}

		public static void RemoveAll(bool keepItems = false)
		{
			if (!keepItems)
			{
				if (OurItems.Count > 0)
				{
					RemoveItems(OurItems.ToList());
				}
				ObjectDB instance = ObjectDB.instance;
				if ((Object)(object)instance != (Object)null)
				{
					foreach (StatusEffect ourEffect in OurEffects)
					{
						instance.m_StatusEffects.Remove(ourEffect);
					}
				}
			}
			OurItems.Clear();
			OurEffects.Clear();
			foreach (Recipe item in OurRecipes.Values.ToList())
			{
				RemoveRecipe(item);
			}
			OurRecipes.Clear();
			foreach (var item2 in OurConversions.ToList())
			{
				RemoveConversion(item2.Station, item2.From, item2.To);
			}
			OurConversions.Clear();
			foreach (var item3 in OurDrops.ToList())
			{
				RemoveDrop(item3.Creature, item3.Item);
			}
			OurDrops.Clear();
			OurSales.Clear();
		}
	}
	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 class GlowFade : MonoBehaviour
	{
		private const string BornKey = "nick_wisparrow_born";

		private const string LastsKey = "nick_wisparrow_lasts";

		private const float FadeSeconds = 5f;

		private ZNetView _nview;

		private double _born;

		private float _lasts;

		private bool _ready;

		private float _shown = 1f;

		private readonly List<ParticleSystemForceField> _fields = new List<ParticleSystemForceField>();

		private readonly List<float> _ranges = new List<float>();

		private readonly List<Light> _lights = new List<Light>();

		private readonly List<float> _intensities = new List<float>();

		private readonly List<ParticleSystem> _particles = new List<ParticleSystem>();

		private readonly List<float> _rates = new List<float>();

		private readonly List<Transform> _cores = new List<Transform>();

		private readonly List<Vector3> _coreScales = new List<Vector3>();

		private void Awake()
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			_nview = ((Component)this).GetComponent<ZNetView>();
			ParticleSystemForceField[] componentsInChildren = ((Component)th