Decompiled source of Below the Keel v1.0.0

plugins/BelowTheKeel.dll

Decompiled a day 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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HeaveHo.Shared;
using Microsoft.CodeAnalysis;
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;
		}
	}
}
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 BelowTheKeel
{
	internal static class Commands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__3_0;

			internal void <Register>b__3_0(ConsoleEventArgs args)
			{
				Run(args.Context, args.Args);
			}
		}

		private const string Command = "keel";

		private const string Usage = "keel status | keel next | keel play <eye [classic] [width] [depth] | eye [classic] at <seconds> | eye [classic] show [at <seconds>]|pacer [side] [depth] [glow x]|halfboat [near [metres]]|ransnet [side <metres>]> | keel probe [off] | keel pose | keel hands [up] [out] [marks] | keel plate <name> <x> <y> <z> <yaw> <pitch> [fov] [size] [cut [omens]] | keel depths | keel shaders [text] | keel material <prefab>";

		private static readonly FieldRef<Dictionary<string, ConsoleCommand>> TerminalCommands = AccessTools.StaticFieldRefAccess<Dictionary<string, ConsoleCommand>>(AccessTools.Field(typeof(Terminal), "commands"));

		internal static void Register()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			object obj = <>c.<>9__3_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					Run(args.Context, args.Args);
				};
				<>c.<>9__3_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("keel", "Below the Keel: keel status | keel next | keel play <eye [classic] [width] [depth] | eye [classic] at <seconds> | eye [classic] show [at <seconds>]|pacer [side] [depth] [glow x]|halfboat [near [metres]]|ransnet [side <metres>]> | keel probe [off] | keel pose | keel hands [up] [out] [marks] | keel plate <name> <x> <y> <z> <yaw> <pitch> [fov] [size] [cut [omens]] | keel depths | keel shaders [text] | keel material <prefab>", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		internal static void Unregister()
		{
			TerminalCommands.Invoke().Remove("keel");
		}

		private static string Spread(List<float> depths)
		{
			if (depths.Count == 0)
			{
				return "none";
			}
			depths.Sort();
			return $"{depths.Count} points, deepest {depths[depths.Count - 1]:0} m; 10% {At(0.1f):0}, half {At(0.5f):0}, 90% {At(0.9f):0} m";
			float At(float q)
			{
				return depths[Mathf.Clamp((int)(q * (float)(depths.Count - 1)), 0, depths.Count - 1)];
			}
		}

		private static void Run(Terminal t, string[] a)
		{
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ab5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bb1: Invalid comparison between Unknown and I4
			//IL_0bb3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bc5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eaf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eb4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eb6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f23: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f28: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ebd: Invalid comparison between Unknown and I4
			//IL_0ebf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ec2: Invalid comparison between Unknown and I4
			//IL_0ee1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ee6: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_08dc: Unknown result type (might be due to invalid IL or missing references)
			string text = ((a.Length > 1) ? a[1].ToLowerInvariant() : "status");
			Ship localShip = Ship.GetLocalShip();
			switch (text)
			{
			case "status":
			{
				if ((Object)(object)localShip == (Object)null)
				{
					t.AddString("Not aboard a ship.");
					break;
				}
				Vector3 position = ((Component)localShip).transform.position;
				string why2;
				bool flag2 = Sea.IsDeep(position, out why2);
				t.AddString($"Depth {Sea.Depth(position):0} m, biome {WorldGenerator.instance.GetBiome(position)}: " + (flag2 ? "omens may come" : ("no omens (" + why2 + ")")));
				t.AddString($"Ship id {Director.ShipId(localShip):X}, {Visuals.Count} omen object(s) showing");
				foreach (string item2 in Visuals.Where())
				{
					t.AddString("  " + item2);
				}
				t.AddString($"Open sea since its last omen: {Director.OpenSeaSeconds(localShip) / 60f:0.0} min (fail-safe at {Plugin.FailSafeMinutes.Value:0})");
				t.AddString($"Weather {EnvMan.instance.GetCurrentEnvironment()?.m_name}, fog {RenderSettings.fogMode} density {RenderSettings.fogDensity:0.0000} (sight {Sea.SightDistance():0} m), night {EnvMan.IsNight()}");
				break;
			}
			case "next":
			{
				if ((Object)(object)localShip == (Object)null)
				{
					t.AddString("Not aboard a ship.");
					break;
				}
				ulong shipId = Director.ShipId(localShip);
				double timeSeconds = ZNet.instance.GetTimeSeconds();
				long num = (long)(timeSeconds / 30.0);
				int num2 = 0;
				for (long num3 = num + 1; num3 < num + 2000; num3++)
				{
					if (num2 >= 3)
					{
						break;
					}
					if (Director.Fires(shipId, num3, out var omen, out var _))
					{
						float num4 = (float)(((double)num3 * 30.0 - timeSeconds) / 60.0);
						t.AddString($"In {num4:0.0} min: {omen.Name} (if the ship is in deep water then; night now: {EnvMan.IsNight()})");
						num2++;
					}
				}
				if (num2 == 0)
				{
					t.AddString("None in the next 1000 minutes.");
				}
				break;
			}
			case "play":
			{
				if ((Object)(object)localShip == (Object)null)
				{
					t.AddString("Not aboard a ship.");
					break;
				}
				Omen omen2 = ((a.Length > 2) ? Omens.Find(a[2]) : null);
				if (omen2 == null)
				{
					t.AddString("keel status | keel next | keel play <eye [classic] [width] [depth] | eye [classic] at <seconds> | eye [classic] show [at <seconds>]|pacer [side] [depth] [glow x]|halfboat [near [metres]]|ransnet [side <metres>]> | keel probe [off] | keel pose | keel hands [up] [out] [marks] | keel plate <name> <x> <y> <z> <yaw> <pitch> [fov] [size] [cut [omens]] | keel depths | keel shaders [text] | keel material <prefab>");
					break;
				}
				EyeOmen.Classic = omen2 is EyeOmen && Array.IndexOf(a, "classic") > 2;
				bool flag = omen2 is EyeOmen && Array.IndexOf(a, "show") > 2;
				List<string> list4 = new List<string>(a);
				list4.Remove("fire");
				list4.Remove("classic");
				list4.Remove("show");
				a = list4.ToArray();
				if (flag)
				{
					EyeOmen.Show = true;
					int num7 = Array.IndexOf(a, "at");
					EyeOmen.FreezeAt = ((num7 > 0 && a.Length > num7 + 1) ? float.Parse(a[num7 + 1], CultureInfo.InvariantCulture) : 10f);
					EyeOmen.Play(localShip, (uint)Random.Range(int.MinValue, int.MaxValue), 12f, -9f);
					t.AddString("The eye, lifted above the water beside the ship for a minute");
				}
				else if (omen2 is EyeOmen && a.Length > 4 && a[3] == "at")
				{
					float num8 = (EyeOmen.FreezeAt = float.Parse(a[4], CultureInfo.InvariantCulture));
					omen2.Play(localShip, (uint)Random.Range(int.MinValue, int.MaxValue));
					t.AddString($"Eye held at {num8:0.##} s for a minute");
				}
				else if (omen2 is EyeOmen && a.Length > 3)
				{
					float result2;
					float num9 = (float.TryParse(a[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result2) ? result2 : 36f);
					float result3;
					float num10 = ((a.Length > 4 && float.TryParse(a[4], NumberStyles.Float, CultureInfo.InvariantCulture, out result3)) ? result3 : float.NaN);
					EyeOmen.Play(localShip, (uint)Random.Range(int.MinValue, int.MaxValue), Mathf.Clamp(num9, 2f, 120f), num10);
					t.AddString(string.Format("Playing eye, {0:0} m across, top {1} down", num9, (!float.IsNaN(num10)) ? (num10.ToString("0.#") + " m") : "6-7 m"));
				}
				else if (omen2 is PacerOmen && a.Length > 3)
				{
					float num11 = float.Parse(a[3], CultureInfo.InvariantCulture);
					float num12 = ((a.Length > 4 && a[4] != "glow") ? float.Parse(a[4], CultureInfo.InvariantCulture) : float.NaN);
					int num13 = Array.IndexOf(a, "glow");
					PacerOmen.Glow = ((num13 > 0 && a.Length > num13 + 1) ? float.Parse(a[num13 + 1], CultureInfo.InvariantCulture) : 1f);
					try
					{
						PacerOmen.Play(localShip, (uint)Random.Range(int.MinValue, int.MaxValue), num11, num12);
					}
					finally
					{
						PacerOmen.Glow = 1f;
					}
					t.AddString($"Playing pacer {num11:0} m to the side" + (float.IsNaN(num12) ? "" : $", its middle {num12:0.#} m down"));
				}
				else if (omen2 is RansNetOmen && a.Length > 4 && a[3] == "side")
				{
					RansNetOmen.Side = float.Parse(a[4], CultureInfo.InvariantCulture);
					omen2.Play(localShip, (uint)Random.Range(int.MinValue, int.MaxValue));
					t.AddString("Playing ransnet " + a[4] + " m to the side");
				}
				else if (omen2 is HalfBoatOmen && a.Length > 3 && a[3] == "near")
				{
					float result4;
					float num14 = ((a.Length > 4 && float.TryParse(a[4], NumberStyles.Float, CultureInfo.InvariantCulture, out result4)) ? result4 : 12f);
					HalfBoatOmen.Play(localShip, (uint)Random.Range(int.MinValue, int.MaxValue), Mathf.Sign(num14) * Mathf.Clamp(Mathf.Abs(num14), 4f, 200f));
					t.AddString(string.Format("Half-boat holding {0:0} m to {1} for a minute; ship at {2:0.0} {3:0.0}, heading {4:0}", Mathf.Abs(num14), (num14 < 0f) ? "port" : "starboard", ((Component)localShip).transform.position.x, ((Component)localShip).transform.position.z, ((Component)localShip).transform.eulerAngles.y));
				}
				else
				{
					omen2.Play(localShip, (uint)Random.Range(int.MinValue, int.MaxValue));
					t.AddString("Playing " + omen2.Name);
				}
				break;
			}
			case "probe":
				if (a.Length > 2 && a[2] == "off")
				{
					Probe.Clear();
					t.AddString("Probe removed.");
				}
				else if ((Object)(object)localShip == (Object)null)
				{
					t.AddString("Not aboard a ship.");
				}
				else
				{
					t.AddString(Probe.Show(localShip));
				}
				break;
			case "hands":
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)localShip == (Object)null)
				{
					t.AddString("Stand aboard a ship, at its side, facing over it.");
					break;
				}
				Hands.Markers = Array.IndexOf(a, "marks") > 1;
				List<float> list = new List<float>();
				string[] array = a;
				foreach (string s in array)
				{
					if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						list.Add(result);
					}
				}
				t.AddString(Hands.Show(Player.m_localPlayer, localShip, (list.Count > 0) ? list[0] : 0f, (list.Count > 1) ? list[1] : 0f));
				break;
			}
			case "plate":
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)localShip == (Object)null || a.Length < 8)
				{
					t.AddString("keel plate <name> <x> <y> <z> <yaw> <pitch> [fov=60] [size=2048] [cut]");
					break;
				}
				bool cut = Array.IndexOf(a, "cut") > 0;
				t.AddString(Plate.Render(Player.m_localPlayer, localShip, a[2], new Vector3(F(3, 0f), F(4, 1.6f), F(5, 0f)), F(6, 0f), F(7, 0f), F(8, 60f), (int)F(9, 2048f), cut, Array.IndexOf(a, "omens") > 0));
				break;
			}
			case "pose":
			{
				if ((Object)(object)localShip == (Object)null)
				{
					t.AddString("Not aboard a ship.");
					break;
				}
				string text3 = RansNetOmen.Pose(localShip);
				t.AddString("One of Ran's drowned, above the water 7 m to starboard, for a minute (eyes open 11 s in): " + text3);
				break;
			}
			case "depths":
			{
				List<float> list2 = new List<float>();
				List<float> list3 = new List<float>();
				float value = Plugin.MinDepth.Value;
				Plugin.MinDepth.Value = -1000f;
				try
				{
					Vector3 val4 = default(Vector3);
					for (float num5 = -10000f; num5 <= 10000f; num5 += 200f)
					{
						for (float num6 = -10000f; num6 <= 10000f; num6 += 200f)
						{
							if (num5 * num5 + num6 * num6 > 100000000f)
							{
								continue;
							}
							((Vector3)(ref val4))..ctor(num5, 0f, num6);
							if ((int)WorldGenerator.instance.GetBiome(val4) == 256)
							{
								float item = Sea.Depth(val4);
								list2.Add(item);
								if (Sea.IsDeep(val4, out var _))
								{
									list3.Add(item);
								}
							}
						}
					}
				}
				finally
				{
					Plugin.MinDepth.Value = value;
				}
				t.AddString("Ocean depth (every 200 m over the world): " + Spread(list2));
				t.AddString($"Away from land ({Plugin.LandDistance.Value:0} m): " + Spread(list3));
				float[] array2 = new float[7] { 20f, 25f, 30f, 35f, 40f, 50f, 60f };
				foreach (float min in array2)
				{
					t.AddString($"  at least {min:0} m deep: {(float)list3.FindAll((float d) => d >= min).Count * 100f / (float)Mathf.Max(1, list3.Count):0}% of it");
				}
				break;
			}
			case "shaders":
			{
				string value2 = ((a.Length > 2) ? a[2] : "");
				SortedSet<string> sortedSet = new SortedSet<string>();
				Shader[] array3 = Resources.FindObjectsOfTypeAll<Shader>();
				foreach (Shader val5 in array3)
				{
					if (((Object)val5).name.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						sortedSet.Add(string.Format("{0} ({1}, queue {2})", ((Object)val5).name, val5.isSupported ? "ok" : "unsupported", val5.renderQueue));
					}
				}
				{
					foreach (string item3 in sortedSet)
					{
						t.AddString(item3);
					}
					break;
				}
			}
			case "material":
			{
				GameObject val = ((a.Length > 2 && (Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(a[2]) : null);
				if ((Object)(object)val == (Object)null)
				{
					t.AddString("No such prefab.");
					break;
				}
				Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					Material[] sharedMaterials = val2.sharedMaterials;
					foreach (Material val3 in sharedMaterials)
					{
						if (!((Object)(object)val3 == (Object)null))
						{
							t.AddString(((Object)val2).name + ": " + ((Object)val3).name + " (" + ((Object)val3.shader).name + ") keywords [" + string.Join(" ", val3.shaderKeywords) + "]");
							for (int k = 0; k < val3.shader.GetPropertyCount(); k++)
							{
								string propertyName = val3.shader.GetPropertyName(k);
								ShaderPropertyType propertyType = val3.shader.GetPropertyType(k);
								string text2 = (((int)propertyType == 0) ? ((object)val3.GetColor(propertyName)/*cast due to .constrained prefix*/).ToString() : (((int)propertyType == 4) ? (((Object)(object)val3.GetTexture(propertyName) != (Object)null) ? ((Object)val3.GetTexture(propertyName)).name : "-") : (((int)propertyType == 1) ? ((object)val3.GetVector(propertyName)/*cast due to .constrained prefix*/).ToString() : val3.GetFloat(propertyName).ToString("0.###"))));
								t.AddString("  " + propertyName + " = " + text2);
							}
						}
					}
				}
				break;
			}
			default:
				t.AddString("keel status | keel next | keel play <eye [classic] [width] [depth] | eye [classic] at <seconds> | eye [classic] show [at <seconds>]|pacer [side] [depth] [glow x]|halfboat [near [metres]]|ransnet [side <metres>]> | keel probe [off] | keel pose | keel hands [up] [out] [marks] | keel plate <name> <x> <y> <z> <yaw> <pitch> [fov] [size] [cut [omens]] | keel depths | keel shaders [text] | keel material <prefab>");
				break;
			}
			float F(int num16, float d)
			{
				if (a.Length <= num16 || !float.TryParse(a[num16], NumberStyles.Float, CultureInfo.InvariantCulture, out var result5))
				{
					return d;
				}
				return result5;
			}
		}
	}
	internal static class Director
	{
		internal const double SlotSeconds = 30.0;

		internal const string OpenSeaKey = "BelowTheKeel.deepSeconds";

		private static long _lastSlot = long.MinValue;

		private static float _lastPlayed = float.NegativeInfinity;

		internal static void Reset()
		{
			_lastSlot = long.MinValue;
			_lastPlayed = float.NegativeInfinity;
		}

		internal static void Update()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			Ship localShip = Ship.GetLocalShip();
			if ((Object)(object)localShip == (Object)null)
			{
				return;
			}
			long num = (long)(ZNet.instance.GetTimeSeconds() / 30.0);
			if (num == _lastSlot)
			{
				return;
			}
			bool flag = _lastSlot == long.MinValue;
			_lastSlot = num;
			if (flag || !Sea.IsDeep(((Component)localShip).transform.position, out var _))
			{
				return;
			}
			ulong shipId = ShipId(localShip);
			Omen omen;
			uint seed;
			bool flag2 = Fires(shipId, num, out omen, out seed);
			bool flag3 = false;
			if (!flag2 && FailSafeDue(localShip))
			{
				Pick(shipId, num, out omen, out seed);
				flag2 = (flag3 = true);
			}
			if (flag2)
			{
				omen = Playable(omen, localShip);
			}
			CountOpenSea(localShip, omen != null && flag2);
			if (flag2 && omen != null)
			{
				_lastPlayed = Time.time;
				if (Plugin.Enabled.Value && omen.IsEnabled)
				{
					Plugin.Log.LogInfo((object)("Omen: " + omen.Name + (flag3 ? " (fail-safe)" : "")));
					omen.Play(localShip, seed);
				}
			}
		}

		internal static bool Fires(ulong shipId, long slot, out Omen omen, out uint seed)
		{
			omen = null;
			seed = 0u;
			if (!RawHit(shipId, slot))
			{
				return false;
			}
			int num = Mathf.CeilToInt(Plugin.MinutesApart.Value * 60f / 30f);
			for (long num2 = slot - 1; num2 >= slot - num; num2--)
			{
				if (RawHit(shipId, num2))
				{
					return false;
				}
			}
			Pick(shipId, slot, out omen, out seed);
			return true;
		}

		private static void Pick(ulong shipId, long slot, out Omen omen, out uint seed)
		{
			omen = Omens.All[Hash(shipId, slot, 2u) % (uint)Omens.All.Length];
			seed = Hash(shipId, slot, 3u);
		}

		internal static Omen Playable(Omen picked, Ship ship)
		{
			int num = Array.IndexOf(Omens.All, picked);
			for (int i = 0; i < Omens.All.Length; i++)
			{
				Omen omen = Omens.All[(num + i) % Omens.All.Length];
				if (omen.CanPlay(ship))
				{
					return omen;
				}
			}
			return null;
		}

		internal static float OpenSeaSeconds(Ship ship)
		{
			ZDO val = ShipZdo(ship);
			if (val == null)
			{
				return 0f;
			}
			return val.GetFloat("BelowTheKeel.deepSeconds", 0f);
		}

		private static bool FailSafeDue(Ship ship)
		{
			float num = Plugin.FailSafeMinutes.Value * 60f;
			if (num <= 0f)
			{
				return false;
			}
			if (Time.time - _lastPlayed < Plugin.MinutesApart.Value * 60f)
			{
				return false;
			}
			return OpenSeaSeconds(ship) >= num;
		}

		private static void CountOpenSea(Ship ship, bool reset)
		{
			ZNetView component = ((Component)ship).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
			{
				ZDO zDO = component.GetZDO();
				zDO.Set("BelowTheKeel.deepSeconds", reset ? 0f : (zDO.GetFloat("BelowTheKeel.deepSeconds", 0f) + 30f));
			}
		}

		private static bool RawHit(ulong shipId, long slot)
		{
			float num = Plugin.MinutesBetween.Value * 60f / 30f;
			float num2 = 1f / num;
			if (EnvMan.IsNight())
			{
				num2 *= Plugin.NightFactor.Value;
			}
			return (float)Hash(shipId, slot, 1u) / 4.2949673E+09f < num2;
		}

		private static ZDO ShipZdo(Ship ship)
		{
			ZNetView component = ((Component)ship).GetComponent<ZNetView>();
			if (!((Object)(object)component != (Object)null) || !component.IsValid())
			{
				return null;
			}
			return component.GetZDO();
		}

		internal static ulong ShipId(Ship ship)
		{
			ZDO val = ShipZdo(ship);
			if (val == null)
			{
				return 0uL;
			}
			return (ulong)((((ZDOID)(ref val.m_uid)).UserID * -7046029254386353131L) ^ ((ZDOID)(ref val.m_uid)).ID);
		}

		internal static uint Hash(ulong a, long b, uint salt)
		{
			ulong num = a ^ (ulong)(b * -4658895280553007687L) ^ (ulong)(salt * -7723592293110705685L);
			num ^= num >> 30;
			num *= 13787848793156543929uL;
			num ^= num >> 27;
			num *= 10723151780598845931uL;
			num ^= num >> 31;
			return (uint)num;
		}
	}
	internal sealed class Hands : MonoBehaviour
	{
		private sealed class Arm
		{
			public Transform Upper;

			public Transform Fore;

			public Transform Hand;

			public List<Transform[]> Fingers = new List<Transform[]>();

			public Transform[] Thumb;

			public float Side;
		}

		private const float Seconds = 60f;

		private const float HandApart = 0.26f;

		private const float Lean = 6f;

		private const float BodyTilt = 0f;

		private const float StandBack = 0.42f;

		private const float RailBelowFeet = 1.05f;

		private const float HeadDown = 22f;

		private static Hands _current;

		internal static bool Markers;

		private Transform _holder;

		private Transform _spine;

		private Transform _neck;

		private Transform _head;

		private Vector3 _railLeft;

		private Vector3 _railRight;

		private Vector3 _outLocal;

		private Vector3 _out;

		private readonly Dictionary<Transform, Quaternion> _rest = new Dictionary<Transform, Quaternion>();

		private readonly List<Renderer> _hidden = new List<Renderer>();

		private float _age;

		private readonly List<Arm> _arms = new List<Arm>();

		internal static string Show(Player player, Ship ship, float raise = 0f, float further = 0f)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_0069: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_current != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_current).gameObject);
			}
			Vector3 forward = ((Component)player).transform.forward;
			forward.y = 0f;
			((Vector3)(ref forward)).Normalize();
			if (!FindRail(((Component)player).transform.position, forward, out var top, out var dist))
			{
				return "No gunwale found in front of you: stand at the ship's side, facing over it.";
			}
			GameObject val = new GameObject("BelowTheKeel_Hands");
			Vector3 val2 = ((Component)player).transform.position + forward * (dist - 0.42f);
			val2.y = top - 1.05f;
			val.transform.SetPositionAndRotation(val2, Quaternion.LookRotation(forward));
			val.transform.SetParent(((Component)ship).transform, true);
			Hands hands = val.AddComponent<Hands>();
			Visuals.Track(val, 61f);
			string text = hands.Build(player, ((Component)ship).transform, forward, top + raise, 0.42f + further);
			if (text != null)
			{
				Object.Destroy((Object)(object)val);
				return text;
			}
			_current = hands;
			hands.LateUpdate();
			Vector3 val3 = ((Component)player).transform.InverseTransformPoint(hands.Eye());
			return $"Hands on the rail for a minute. Camera at the eyes: view here {val3.x:0.00} {val3.y:0.00} {val3.z:0.00} 0 <pitch>";
		}

		private static bool FindRail(Vector3 feet, Vector3 fwd, out float top, out float dist)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_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)
			top = float.NegativeInfinity;
			dist = -1f;
			for (float num = 0.2f; num <= 1.6f; num += 0.03f)
			{
				if (!(dist < 0f))
				{
					break;
				}
				if (HighestAt(feet, fwd, num, feet.y + 0.3f, feet.y + 1.2f) > float.NegativeInfinity)
				{
					dist = num;
				}
			}
			if (dist < 0f)
			{
				return false;
			}
			for (float num2 = dist; num2 <= dist + 0.35f; num2 += 0.03f)
			{
				top = Mathf.Max(top, HighestAt(feet, fwd, num2, feet.y + 0.3f, feet.y + 1.2f));
			}
			return true;
		}

		private static float HighestAt(Vector3 feet, Vector3 fwd, float d, float min, float max)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0059: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			float num = float.NegativeInfinity;
			RaycastHit[] array = Physics.RaycastAll(feet + fwd * d + Vector3.up * 2.5f, Vector3.down, 3.5f);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if (!((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Player>() != (Object)null) && ((RaycastHit)(ref val)).point.y > min && ((RaycastHit)(ref val)).point.y < max)
				{
					num = Mathf.Max(num, ((RaycastHit)(ref val)).point.y);
				}
			}
			return num;
		}

		private string Build(Player player, Transform ship, Vector3 fwd, float railY, float railDist)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0505: Unknown result type (might be due to invalid IL or missing references)
			//IL_050a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0535: Unknown result type (might be due to invalid IL or missing references)
			//IL_0543: Unknown result type (might be due to invalid IL or missing references)
			//IL_054d: Unknown result type (might be due to invalid IL or missing references)
			_out = fwd;
			_outLocal = ship.InverseTransformDirection(fwd);
			Vector3 val = Vector3.Cross(Vector3.up, fwd);
			Vector3 val2 = ((Component)this).transform.position + fwd * (railDist + 0.04f);
			_railLeft = ship.InverseTransformPoint(new Vector3(val2.x, railY, val2.z) - val * 0.26f);
			_railRight = ship.InverseTransformPoint(new Vector3(val2.x, railY, val2.z) + val * 0.26f);
			GameObject look = Visuals.CloneLook("Player", ((Component)this).transform);
			if ((Object)(object)look == (Object)null)
			{
				return "Couldn't copy the player model.";
			}
			Animator[] componentsInChildren = look.GetComponentsInChildren<Animator>(true);
			foreach (Animator val3 in componentsInChildren)
			{
				((Behaviour)val3).enabled = false;
			}
			Renderer[] componentsInChildren2 = look.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val4 in componentsInChildren2)
			{
				if (!(val4 is SkinnedMeshRenderer) && !(val4 is MeshRenderer))
				{
					val4.enabled = false;
				}
			}
			_holder = new GameObject("Holder").transform;
			_holder.SetParent(((Component)this).transform, false);
			look.transform.SetParent(_holder, false);
			look.transform.localPosition = Vector3.zero;
			look.transform.localRotation = Quaternion.identity;
			Transform val5 = Find(look.transform, "LeftFoot");
			Transform val6 = Find(look.transform, "LeftToeBase");
			if ((Object)(object)val5 != (Object)null && (Object)(object)val6 != (Object)null)
			{
				Vector3 val7 = val6.position - val5.position;
				val7.y = 0f;
				if (((Vector3)(ref val7)).sqrMagnitude > 1E-06f)
				{
					look.transform.localRotation = Quaternion.FromToRotation(_holder.InverseTransformDirection(((Vector3)(ref val7)).normalized), Vector3.forward);
				}
			}
			_spine = B("Spine1");
			B("Spine2");
			_neck = B("Neck");
			_head = B("Head");
			string[] array = new string[2] { "Left", "Right" };
			foreach (string text in array)
			{
				Arm arm = new Arm
				{
					Upper = B(text + "Arm"),
					Fore = B(text + "ForeArm"),
					Hand = B(text + "Hand"),
					Side = ((text == "Left") ? (-1f) : 1f)
				};
				if ((Object)(object)arm.Upper == (Object)null || (Object)(object)arm.Fore == (Object)null || (Object)(object)arm.Hand == (Object)null)
				{
					return "The player model is missing arm bones.";
				}
				string[] array2 = new string[4] { "Index", "Middle", "Ring", "Pinky" };
				foreach (string text2 in array2)
				{
					Transform[] array3 = (Transform[])(object)new Transform[3]
					{
						B(text + "Hand" + text2 + "1"),
						B(text + "Hand" + text2 + "2"),
						B(text + "Hand" + text2 + "3")
					};
					if ((Object)(object)array3[0] != (Object)null && (Object)(object)array3[1] != (Object)null && (Object)(object)array3[2] != (Object)null)
					{
						arm.Fingers.Add(array3);
					}
				}
				arm.Thumb = (Transform[])(object)new Transform[3]
				{
					B(text + "HandThumb1"),
					B(text + "HandThumb2"),
					B(text + "HandThumb3")
				};
				_arms.Add(arm);
			}
			if ((Object)(object)_spine == (Object)null || (Object)(object)_head == (Object)null)
			{
				return "The player model is missing spine or head bones.";
			}
			if (Markers)
			{
				Vector3[] array4 = (Vector3[])(object)new Vector3[2] { _railLeft, _railRight };
				foreach (Vector3 localPosition in array4)
				{
					GameObject val8 = GameObject.CreatePrimitive((PrimitiveType)3);
					Object.Destroy((Object)(object)val8.GetComponent<Collider>());
					val8.transform.SetParent(ship, false);
					val8.transform.localPosition = localPosition;
					val8.transform.localScale = Vector3.one * 0.06f;
					val8.GetComponent<Renderer>().sharedMaterial = Look.Rope();
					val8.transform.SetParent(((Component)this).transform, true);
				}
			}
			Renderer[] componentsInChildren3 = ((Component)player).GetComponentsInChildren<Renderer>();
			foreach (Renderer val9 in componentsInChildren3)
			{
				if (val9.enabled)
				{
					val9.enabled = false;
					_hidden.Add(val9);
				}
			}
			return null;
			Transform B(string name)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				Transform val10 = Find(look.transform, name);
				if ((Object)(object)val10 != (Object)null)
				{
					_rest[val10] = val10.localRotation;
				}
				return val10;
			}
		}

		internal Vector3 Eye()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			return _neck.position + Vector3.up * 0.17f + _out * 0.08f;
		}

		private void LateUpdate()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: 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_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: 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_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			_age += Time.deltaTime;
			if (_age > 60f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			foreach (KeyValuePair<Transform, Quaternion> item in _rest)
			{
				item.Key.localRotation = item.Value;
			}
			Transform parent = ((Component)this).transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			_out = parent.TransformDirection(_outLocal);
			Vector3 val = Vector3.Cross(parent.up, _out);
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			_holder.localRotation = Quaternion.Euler(0f, 0f, 0f);
			_spine.rotation = Quaternion.AngleAxis(6f, normalized) * _spine.rotation;
			_head.rotation = Quaternion.AngleAxis(22f, normalized) * _head.rotation;
			_neck.localScale = Vector3.one * 0.001f;
			foreach (Arm arm in _arms)
			{
				Vector3 val2 = parent.TransformPoint((arm.Side < 0f) ? _railLeft : _railRight);
				Vector3 wrist = val2 - _out * 0.02f + Vector3.up * 0.07f;
				SolveArm(arm, wrist, normalized);
				Point(arm.Hand, (arm.Fingers.Count > 1) ? arm.Fingers[1][0] : null, _out - Vector3.up * 0.35f);
				PalmDown(arm);
				foreach (Transform[] finger in arm.Fingers)
				{
					Point(finger[0], finger[1], _out - Vector3.up * 0.25f);
					Point(finger[1], finger[2], _out * 0.3f - Vector3.up);
					Point(finger[2], (finger[2].childCount > 0) ? finger[2].GetChild(0) : null, -_out * 0.4f - Vector3.up);
				}
				if ((Object)(object)arm.Thumb[0] != (Object)null && (Object)(object)arm.Thumb[1] != (Object)null && (Object)(object)arm.Thumb[2] != (Object)null)
				{
					Point(arm.Thumb[0], arm.Thumb[1], -normalized * arm.Side * 0.6f + _out * 0.3f - Vector3.up * 0.6f);
					Point(arm.Thumb[1], arm.Thumb[2], _out * 0.2f - Vector3.up);
				}
			}
		}

		private static void PalmDown(Arm arm)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0069: 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_006f: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			if (arm.Fingers.Count >= 4)
			{
				Vector3 val = arm.Fingers[1][0].position - arm.Hand.position;
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				Vector3 val2 = arm.Fingers[3][0].position - arm.Fingers[0][0].position;
				val = Vector3.Cross(normalized, val2);
				Vector3 val3 = ((Vector3)(ref val)).normalized * (0f - arm.Side);
				Vector3 val4 = Vector3.ProjectOnPlane(Vector3.down, normalized);
				if (!(((Vector3)(ref val3)).sqrMagnitude < 1E-06f) && !(((Vector3)(ref val4)).sqrMagnitude < 1E-06f))
				{
					float num = Vector3.SignedAngle(val3, ((Vector3)(ref val4)).normalized, normalized);
					arm.Hand.rotation = Quaternion.AngleAxis(num, normalized) * arm.Hand.rotation;
				}
			}
		}

		private static void SolveArm(Arm arm, Vector3 wrist, Vector3 side)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = arm.Upper.position;
			float num = Vector3.Distance(arm.Upper.position, arm.Fore.position);
			float num2 = Vector3.Distance(arm.Fore.position, arm.Hand.position);
			Vector3 val = wrist - position;
			float num3 = Mathf.Clamp(((Vector3)(ref val)).magnitude, Mathf.Abs(num - num2) + 0.001f, num + num2 - 0.001f);
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			float num4 = Mathf.Acos(Mathf.Clamp((num * num + num3 * num3 - num2 * num2) / (2f * num * num3), -1f, 1f));
			Vector3 val2 = side * arm.Side + Vector3.down * 0.6f;
			Vector3 normalized2 = ((Vector3)(ref val2)).normalized;
			val2 = Vector3.Cross(normalized, normalized2);
			Vector3 normalized3 = ((Vector3)(ref val2)).normalized;
			Vector3 val3 = position + Quaternion.AngleAxis((0f - num4) * 57.29578f, normalized3) * normalized * num;
			Point(arm.Upper, arm.Fore, val3 - position);
			Point(arm.Fore, arm.Hand, wrist - arm.Fore.position);
		}

		private static void Point(Transform bone, Transform child, Vector3 want)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)bone == (Object)null) && !((Object)(object)child == (Object)null))
			{
				Vector3 val = child.position - bone.position;
				if (!(((Vector3)(ref val)).sqrMagnitude < 1E-10f) && !(((Vector3)(ref want)).sqrMagnitude < 1E-08f))
				{
					bone.rotation = Quaternion.FromToRotation(val, want) * bone.rotation;
				}
			}
		}

		private static Transform Find(Transform root, string name)
		{
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		private void OnDestroy()
		{
			foreach (Renderer item in _hidden)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.enabled = true;
				}
			}
			_hidden.Clear();
			if ((Object)(object)_current == (Object)(object)this)
			{
				_current = null;
			}
		}
	}
	internal static class Look
	{
		private static Material _darkSerpent;

		private static readonly Dictionary<Material, Material> _drowned = new Dictionary<Material, Material>();

		private static Material _rope;

		private static Material _hide;

		private static Material _eye;

		private static Texture2D _eyeAlbedo;

		private static Texture2D _eyeGlow;

		private static Material _eyeFire;

		private static Texture2D _fireAlbedo;

		private static Texture2D _fireGlow;

		private static Material _wood;

		internal static Material DarkSerpent()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_darkSerpent != (Object)null)
			{
				return _darkSerpent;
			}
			Material val = null;
			GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("Serpent") : null);
			SkinnedMeshRenderer val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponentInChildren<SkinnedMeshRenderer>(true) : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val = ((Renderer)val3).sharedMaterial;
			}
			_darkSerpent = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(FindShader("Custom/Creature")));
			((Object)_darkSerpent).name = "BelowTheKeel_DarkSerpent";
			_darkSerpent.color = new Color(0.05f, 0.06f, 0.07f);
			return _darkSerpent;
		}

		internal static Material Drowned(Material source)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			if (_drowned.TryGetValue(source, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			value = new Material(source)
			{
				name = "BelowTheKeel_Drowned_" + ((Object)source).name
			};
			value.color = new Color(0.22f, 0.27f, 0.25f);
			_drowned[source] = value;
			return value;
		}

		internal static Material Rope()
		{
			//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_003b: 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_005a: Expected O, but got Unknown
			if ((Object)(object)_rope != (Object)null)
			{
				return _rope;
			}
			_rope = new Material(FindShader("Custom/Creature") ?? FindShader("Legacy Shaders/Diffuse"))
			{
				name = "BelowTheKeel_Rope",
				color = new Color(0.12f, 0.1f, 0.07f)
			};
			return _rope;
		}

		internal static Material DarkHide()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_hide != (Object)null)
			{
				return _hide;
			}
			_hide = new Material(DarkSerpent())
			{
				name = "BelowTheKeel_DarkHide"
			};
			if (_hide.HasProperty("_EmissionColor"))
			{
				_hide.SetColor("_EmissionColor", Color.black);
			}
			return _hide;
		}

		internal static Material Eye()
		{
			//IL_0027: 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_0037: 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_0047: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_eye != (Object)null)
			{
				return _eye;
			}
			EyeMeshes.Draw(out _eyeAlbedo, out _eyeGlow);
			_eye = new Material(DarkSerpent())
			{
				name = "BelowTheKeel_Eye",
				color = Color.white
			};
			_eye.SetTexture("_MainTex", (Texture)(object)_eyeAlbedo);
			_eye.SetTexture("_EmissionMap", (Texture)(object)_eyeGlow);
			_eye.SetColor("_EmissionColor", new Color(3f, 3f, 3f));
			if (_eye.HasProperty("_BumpMap"))
			{
				_eye.SetTexture("_BumpMap", (Texture)null);
			}
			return _eye;
		}

		internal static Material EyeFire()
		{
			//IL_0027: 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_0037: 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_0047: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_eyeFire != (Object)null)
			{
				return _eyeFire;
			}
			EyeMeshes.DrawFire(out _fireAlbedo, out _fireGlow);
			_eyeFire = new Material(DarkSerpent())
			{
				name = "BelowTheKeel_EyeFire",
				color = Color.white
			};
			_eyeFire.SetTexture("_MainTex", (Texture)(object)_fireAlbedo);
			_eyeFire.SetTexture("_EmissionMap", (Texture)(object)_fireGlow);
			_eyeFire.SetColor("_EmissionColor", new Color(2.2f, 2.2f, 2.2f));
			if (_eyeFire.HasProperty("_BumpMap"))
			{
				_eyeFire.SetTexture("_BumpMap", (Texture)null);
			}
			return _eyeFire;
		}

		internal static Material Wood()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_wood != (Object)null)
			{
				return _wood;
			}
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("shipwreck_karve_stern") : null);
			MeshRenderer val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<MeshRenderer>(true) : null);
			_wood = (((Object)(object)val2 != (Object)null) ? new Material(((Renderer)val2).sharedMaterial) : new Material(FindShader("Custom/Piece") ?? FindShader("Legacy Shaders/Diffuse")));
			((Object)_wood).name = "BelowTheKeel_Wood";
			return _wood;
		}

		internal static Shader FindShader(string name)
		{
			Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
			foreach (Shader val in array)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		internal static void Forget()
		{
			if ((Object)(object)_darkSerpent != (Object)null)
			{
				Object.Destroy((Object)(object)_darkSerpent);
			}
			_darkSerpent = null;
			foreach (Material value in _drowned.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			_drowned.Clear();
			if ((Object)(object)_rope != (Object)null)
			{
				Object.Destroy((Object)(object)_rope);
			}
			_rope = null;
			if ((Object)(object)_wood != (Object)null)
			{
				Object.Destroy((Object)(object)_wood);
			}
			_wood = null;
			if ((Object)(object)_eye != (Object)null)
			{
				Object.Destroy((Object)(object)_eye);
			}
			if ((Object)(object)_eyeFire != (Object)null)
			{
				Object.Destroy((Object)(object)_eyeFire);
			}
			if ((Object)(object)_fireAlbedo != (Object)null)
			{
				Object.Destroy((Object)(object)_fireAlbedo);
			}
			if ((Object)(object)_fireGlow != (Object)null)
			{
				Object.Destroy((Object)(object)_fireGlow);
			}
			_eyeFire = null;
			_fireAlbedo = (_fireGlow = null);
			if ((Object)(object)_hide != (Object)null)
			{
				Object.Destroy((Object)(object)_hide);
			}
			_hide = null;
			if ((Object)(object)_eyeAlbedo != (Object)null)
			{
				Object.Destroy((Object)(object)_eyeAlbedo);
			}
			if ((Object)(object)_eyeGlow != (Object)null)
			{
				Object.Destroy((Object)(object)_eyeGlow);
			}
			_eye = null;
			_eyeAlbedo = (_eyeGlow = null);
		}
	}
	internal sealed class EyeOmen : Omen
	{
		internal const float Width = 36f;

		internal static float FreezeAt = -1f;

		internal static bool Classic;

		internal static bool Show;

		internal override string Name => "eye";

		protected override ConfigEntry<bool> Setting => Plugin.Eye;

		internal override void Play(Ship ship, uint seed)
		{
			Play(ship, seed, 36f, float.NaN);
		}

		internal static void Play(Ship ship, uint seed, float width, float depth)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			Random random = new Random((int)seed);
			float num = width / 2f;
			if (float.IsNaN(depth))
			{
				depth = 6.25f + (float)random.NextDouble() * 0.5f;
			}
			GameObject val = Visuals.Spawn("Eye", ((Component)ship).transform.position, Quaternion.identity, 27f);
			val.AddComponent<EyeBody>().Begin(ship, num, ((random.Next(2) == 0) ? (-1f) : 1f) * num * (Show ? 11.5f : (1.15f + (float)random.NextDouble() *