Decompiled source of Daywheel v1.0.14

Keel/Keel.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using Keel;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Keel")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyProduct("Keel")]
[assembly: AssemblyTitle("Keel")]
[assembly: AssemblyVersion("2.0.0.0")]
namespace Keel
{
	internal static class Starter
	{
		private static readonly string[] BepInExStarters = new string[2] { "BepInEx.Preloader.dll", "BepInEx.Unity.Mono.Preloader.dll" };

		private const string CoreName = "Keel.Core.";

		private static string _log;

		internal static void Begin()
		{
			try
			{
				string text = Environment.GetEnvironmentVariable("DOORSTOP_INVOKE_DLL_PATH");
				if (string.IsNullOrEmpty(text))
				{
					text = typeof(Starter).Assembly.Location;
				}
				string? directoryName = Path.GetDirectoryName(Path.GetFullPath(text));
				string environmentVariable = Environment.GetEnvironmentVariable("DOORSTOP_PROCESS_PATH");
				string text2 = Path.GetDirectoryName(directoryName);
				if (string.IsNullOrEmpty(text2))
				{
					text2 = Directory.GetCurrentDirectory();
				}
				Open(directoryName);
				Line("Keel is starting in " + text2 + ".");
				string text3 = Path.Combine(directoryName, "Keel.cfg");
				Read(text3, out var startBepInEx, out var skip);
				AppDomain.CurrentDomain.SetData("Keel.BepInEx", BepInEx(text2, environmentVariable, startBepInEx));
				Run(directoryName, text3, skip);
			}
			catch (Exception e)
			{
				Line("Keel couldn't start: " + Inner(e));
			}
		}

		private static string BepInEx(string game, string exe, bool start)
		{
			string path = Path.Combine(Path.Combine(game, "BepInEx"), "core");
			string[] bepInExStarters = BepInExStarters;
			foreach (string path2 in bepInExStarters)
			{
				string text = Path.Combine(path, path2);
				if (!File.Exists(text))
				{
					continue;
				}
				if (!start)
				{
					Line("BepInEx is installed here too, but Keel.cfg says not to start it, so it stays off.");
					return "off";
				}
				Line("BepInEx is installed here too, so Keel starts it first.");
				DateTime since = DateTime.UtcNow.AddSeconds(-2.0);
				try
				{
					Environment.SetEnvironmentVariable("DOORSTOP_INVOKE_DLL_PATH", text);
					Assembly assembly = Assembly.LoadFrom(text);
					Type type = assembly.GetType("Doorstop.Entrypoint") ?? assembly.GetType("BepInEx.Preloader.Entrypoint");
					MethodInfo methodInfo = ((type == null) ? null : type.GetMethod("Start", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
					MethodInfo methodInfo2 = ((type == null) ? null : type.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
					MethodInfo methodInfo3 = ((type == null) ? null : type.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string[]) }, null));
					if (methodInfo != null)
					{
						methodInfo.Invoke(null, null);
					}
					else if (methodInfo2 != null)
					{
						methodInfo2.Invoke(null, null);
					}
					else
					{
						if (!(methodInfo3 != null))
						{
							Line("BepInEx's starter, " + text + ", has no way in that Keel knows, so BepInEx didn't start.");
							return "unknown";
						}
						methodInfo3.Invoke(null, new object[1] { new string[1] { exe ?? string.Empty } });
					}
				}
				catch (Exception e)
				{
					Line("BepInEx failed to start: " + Inner(e));
					return "failed";
				}
				string text2 = NewPreloaderLog(game, since) ?? NewPreloaderLog(ProgramFolder(exe), since);
				if (text2 != null)
				{
					Line("BepInEx ran into a problem while starting, which it wrote to " + text2 + ", so Keel won't count on it running any mods.");
					return "failed";
				}
				Line("BepInEx started.");
				return "started";
			}
			return "none";
		}

		private static string NewPreloaderLog(string folder, DateTime since)
		{
			try
			{
				string[] files = Directory.GetFiles(folder, "preloader_*.log");
				foreach (string text in files)
				{
					if (File.GetLastWriteTimeUtc(text) >= since)
					{
						return text;
					}
				}
			}
			catch (Exception)
			{
			}
			return null;
		}

		private static string ProgramFolder(string exe)
		{
			try
			{
				return Path.GetDirectoryName(exe);
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static void Run(string home, string settings, List<string> skip)
		{
			int skipped;
			List<KeyValuePair<Version, string>> list = Cores(home, skip, out skipped);
			string marker = Path.Combine(home, "Keel.starting");
			string file;
			int num = Stopped(marker, out file);
			foreach (KeyValuePair<Version, string> item in list)
			{
				string fileName = Path.GetFileName(item.Value);
				string version = Three(item.Key);
				int num2 = (string.Equals(fileName, file, StringComparison.OrdinalIgnoreCase) ? num : 0);
				if (num2 >= 2)
				{
					Line("Keel passed over " + fileName + ", because the game stopped twice in a row while Keel was handing over to it. " + Added(settings, version, "the game stopped twice in a row while Keel was handing over to " + fileName));
					Remove(marker);
					continue;
				}
				Mark(marker, fileName, num2 + 1);
				MethodInfo boot;
				bool loaded;
				bool handedBack;
				string text = Check(item.Value, item.Key, out boot, out loaded, out handedBack);
				if (text != null && !loaded)
				{
					Remove(marker);
					Line("Keel passed over " + fileName + ", because " + text + ".");
					continue;
				}
				if (text != null)
				{
					Remove(marker);
					string text2 = fileName + " can't run, because " + text + ", and no other core can load in the same start, so no Keel mods start this time.";
					Line(handedBack ? text2 : (text2 + " " + Added(settings, version, fileName + " couldn't run: " + text)));
					return;
				}
				Line("Keel hands over to " + fileName + ".");
				try
				{
					boot.Invoke(null, new object[1] { home });
					return;
				}
				catch (Exception e)
				{
					Line(fileName + " failed while starting, so no Keel mods start this time. " + Added(settings, version, fileName + " failed while starting") + " What went wrong: " + Inner(e));
					return;
				}
				finally
				{
					Remove(marker);
				}
			}
			Line("Keel found no core it can run in " + home + ", so no Keel mods start." + ((skipped == 0) ? string.Empty : (" SkipCores in Keel.cfg passes over " + skipped.ToString(CultureInfo.InvariantCulture) + ((skipped == 1) ? " core here: take it out to try it again." : " cores here: take one out to try it again."))));
		}

		private static List<KeyValuePair<Version, string>> Cores(string home, List<string> skip, out int skipped)
		{
			skipped = 0;
			List<KeyValuePair<Version, string>> list = new List<KeyValuePair<Version, string>>();
			string[] files;
			try
			{
				files = Directory.GetFiles(home, "Keel.Core.*.dll");
			}
			catch (Exception ex)
			{
				Line("Keel couldn't look for cores in " + home + ": " + ex.Message);
				return list;
			}
			string[] array = files;
			foreach (string text in array)
			{
				string fileName = Path.GetFileName(text);
				Version version = Named(fileName);
				if (version == null)
				{
					Line("Keel passed over " + fileName + ", because a core's name is Keel.Core., then a version such as 2.0.0, then .dll.");
				}
				else if (skip.Contains(Three(version)))
				{
					skipped++;
					Line("Keel passed over " + fileName + ", because SkipCores in Keel.cfg names it.");
				}
				else
				{
					list.Add(new KeyValuePair<Version, string>(version, text));
				}
			}
			list.Sort(delegate(KeyValuePair<Version, string> a, KeyValuePair<Version, string> b)
			{
				int num = b.Key.CompareTo(a.Key);
				return (num == 0) ? string.CompareOrdinal(a.Value, b.Value) : num;
			});
			return list;
		}

		private static Version Named(string file)
		{
			if (file.Length <= "Keel.Core.".Length + 4 || !file.StartsWith("Keel.Core.", StringComparison.OrdinalIgnoreCase) || !file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			string[] array = file.Substring("Keel.Core.".Length, file.Length - "Keel.Core.".Length - 4).Split(new char[1] { '.' });
			if (array.Length != 3)
			{
				return null;
			}
			int[] array2 = new int[3];
			for (int i = 0; i < 3; i++)
			{
				string text = array[i];
				if (text.Length == 0 || text.Length > 9 || (text.Length > 1 && text[0] == '0'))
				{
					return null;
				}
				int num = 0;
				string text2 = text;
				foreach (char c in text2)
				{
					if (c < '0' || c > '9')
					{
						return null;
					}
					num = num * 10 + (c - 48);
				}
				array2[i] = num;
			}
			return new Version(array2[0], array2[1], array2[2]);
		}

		private static string Check(string path, Version named, out MethodInfo boot, out bool loaded, out bool handedBack)
		{
			boot = null;
			loaded = false;
			handedBack = false;
			try
			{
				AssemblyName assemblyName = AssemblyName.GetAssemblyName(path);
				if (assemblyName.Name != "Keel.Core")
				{
					return "it isn't one of Keel's cores";
				}
				if (!Same(assemblyName.Version, named))
				{
					return "its name says " + Three(named) + ", but the file itself is " + Three(assemblyName.Version);
				}
				Assembly assembly = Assembly.LoadFrom(path);
				loaded = true;
				Version version = assembly.GetName().Version;
				if (!Same(version, named))
				{
					handedBack = true;
					return "the game already has core " + Three(version) + " loaded" + From(assembly);
				}
				Type type = assembly.GetType("Keel.Boot");
				if (type != null)
				{
					boot = type.GetMethod("Start", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
				}
				return (boot == null) ? "it has no way in that this Keel.dll knows" : null;
			}
			catch (Exception e)
			{
				return (loaded ? "it failed as it loaded: " : "it couldn't be loaded: ") + Inner(e).Message.TrimEnd(new char[1] { '.' });
			}
		}

		private static bool Same(Version v, Version named)
		{
			if (v != null && v.Major == named.Major && v.Minor == named.Minor)
			{
				return v.Build == named.Build;
			}
			return false;
		}

		private static string From(Assembly a)
		{
			try
			{
				string location = a.Location;
				return string.IsNullOrEmpty(location) ? string.Empty : (", from " + location);
			}
			catch (Exception)
			{
				return string.Empty;
			}
		}

		private static int Stopped(string marker, out string file)
		{
			file = null;
			try
			{
				if (!File.Exists(marker))
				{
					return 0;
				}
				string[] array = File.ReadAllLines(marker);
				if (array.Length == 0)
				{
					return 0;
				}
				string[] array2 = array[0].Trim().Split(new char[1] { ' ' });
				if (array2.Length != 2 || !int.TryParse(array2[1], NumberStyles.None, CultureInfo.InvariantCulture, out var result))
				{
					return 0;
				}
				for (int i = 1; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.StartsWith("Process ", StringComparison.Ordinal) && int.TryParse(text.Substring(8), NumberStyles.None, CultureInfo.InvariantCulture, out var result2) && Running(result2))
					{
						result = Math.Max(result - 1, 0);
						break;
					}
				}
				file = array2[0];
				return result;
			}
			catch (Exception)
			{
				return 0;
			}
		}

		private static void Mark(string marker, string file, int tries)
		{
			try
			{
				string newLine = Environment.NewLine;
				string text = file + " " + tries.ToString(CultureInfo.InvariantCulture) + newLine + "Keel writes this file just before it hands over to a core, and deletes it once the core has" + newLine + "taken over, before the game loads. If it's still here and the process named below isn't running," + newLine + "the game stopped during that hand-over. After two such starts in a row, Keel passes over that" + newLine + "core and adds it to SkipCores in Keel.cfg." + newLine;
				try
				{
					text = text + ThisGame() + newLine;
				}
				catch (Exception)
				{
				}
				File.WriteAllText(marker, text);
			}
			catch (Exception)
			{
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static string ThisGame()
		{
			using Process process = Process.GetCurrentProcess();
			return "Process " + process.Id.ToString(CultureInfo.InvariantCulture);
		}

		private static bool Running(int pid)
		{
			try
			{
				return SameProgram(pid);
			}
			catch (Exception)
			{
				return false;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool SameProgram(int pid)
		{
			using Process process = Process.GetCurrentProcess();
			if (pid == process.Id || !Leader(pid))
			{
				return false;
			}
			using Process process2 = Process.GetProcessById(pid);
			return string.Equals(Path.GetFileName(process2.ProcessName), Path.GetFileName(process.ProcessName), StringComparison.OrdinalIgnoreCase);
		}

		private static bool Leader(int pid)
		{
			string text = pid.ToString(CultureInfo.InvariantCulture);
			string path = "/proc/" + text + "/status";
			if (!File.Exists(path))
			{
				return true;
			}
			string[] array = File.ReadAllLines(path);
			foreach (string text2 in array)
			{
				if (text2.StartsWith("Tgid:", StringComparison.Ordinal))
				{
					return string.Equals(text2.Substring(5).Trim(), text, StringComparison.Ordinal);
				}
			}
			return true;
		}

		private static void Remove(string marker)
		{
			int num = 25;
			for (int i = 0; i < 6; i++)
			{
				if (i > 0)
				{
					Thread.Sleep(num);
					num *= 2;
				}
				try
				{
					if (File.Exists(marker))
					{
						File.Delete(marker);
					}
					return;
				}
				catch (Exception)
				{
				}
				try
				{
					File.WriteAllText(marker, string.Empty);
					return;
				}
				catch (Exception)
				{
				}
			}
			Line("Keel couldn't delete or empty " + marker + ", so the next start may take this one for a start where the game stopped.");
		}

		private static void Read(string path, out bool startBepInEx, out List<string> skip)
		{
			startBepInEx = true;
			skip = new List<string>();
			try
			{
				if (!File.Exists(path))
				{
					return;
				}
				string[] array = File.ReadAllLines(path);
				for (int i = 0; i < array.Length; i++)
				{
					if (!Setting(array[i], out var key, out var value))
					{
						continue;
					}
					if (string.Equals(key, "StartBepInEx", StringComparison.OrdinalIgnoreCase))
					{
						string text = value.ToLowerInvariant();
						startBepInEx = text != "false" && text != "no" && text != "off" && text != "0";
					}
					else
					{
						if (!string.Equals(key, "SkipCores", StringComparison.OrdinalIgnoreCase))
						{
							continue;
						}
						string[] array2 = value.Split(new char[1] { ',' });
						for (int j = 0; j < array2.Length; j++)
						{
							string text2 = array2[j].Trim().Trim(new char[1] { '"' }).Trim();
							if (text2.Length != 0)
							{
								Version version = Listed(text2);
								if (version == null)
								{
									Line("SkipCores in Keel.cfg names " + text2 + ", which isn't a version such as 2.1.0, so Keel ignores it.");
								}
								else if (!skip.Contains(Three(version)))
								{
									skip.Add(Three(version));
								}
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				Line("Keel couldn't read " + path + ", so it goes by the defaults: " + ex.Message);
			}
		}

		private static bool Setting(string raw, out string key, out string value)
		{
			key = null;
			value = null;
			string text = raw.Trim();
			if (text.StartsWith("#", StringComparison.Ordinal))
			{
				return false;
			}
			int num = text.IndexOf('=');
			if (num < 0)
			{
				return false;
			}
			key = text.Substring(0, num).Trim();
			value = text.Substring(num + 1).Trim().Trim(new char[1] { '"' });
			return true;
		}

		private static Version Listed(string entry)
		{
			if (entry.StartsWith("Keel.Core.", StringComparison.OrdinalIgnoreCase))
			{
				entry = entry.Substring("Keel.Core.".Length);
			}
			if (entry.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
			{
				entry = entry.Substring(0, entry.Length - 4);
			}
			return Named("Keel.Core." + entry + ".dll");
		}

		private static string Added(string settings, string version, string reason)
		{
			if (!Skip(settings, version, reason))
			{
				return "To pass over it, add " + version + " to SkipCores in Keel.cfg.";
			}
			return "Keel added " + version + " to SkipCores in Keel.cfg, so the next start passes over it.";
		}

		private static bool Skip(string path, string version, string reason)
		{
			try
			{
				string newLine = Environment.NewLine;
				bool flag = File.Exists(path);
				string contents = (flag ? newLine : ("## Settings for Keel" + newLine + newLine)) + "## Keel added the line below on " + DateTime.Now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) + ", because " + reason.Replace('\r', ' ').Replace('\n', ' ') + "." + newLine + "## Take that line out to try the core again." + newLine + "SkipCores = " + version + newLine;
				File.AppendAllText(path, contents, flag ? EncodingOf(path) : new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				return true;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static Encoding EncodingOf(string path)
		{
			byte[] array = new byte[4];
			int num;
			using (FileStream fileStream = File.OpenRead(path))
			{
				num = fileStream.Read(array, 0, 4);
			}
			if (num >= 4 && array[0] == byte.MaxValue && array[1] == 254 && array[2] == 0 && array[3] == 0)
			{
				return new UTF32Encoding(bigEndian: false, byteOrderMark: false);
			}
			if (num >= 4 && array[0] == 0 && array[1] == 0 && array[2] == 254 && array[3] == byte.MaxValue)
			{
				return new UTF32Encoding(bigEndian: true, byteOrderMark: false);
			}
			if (num >= 2 && array[0] == byte.MaxValue && array[1] == 254)
			{
				return new UnicodeEncoding(bigEndian: false, byteOrderMark: false);
			}
			if (num >= 2 && array[0] == 254 && array[1] == byte.MaxValue)
			{
				return new UnicodeEncoding(bigEndian: true, byteOrderMark: false);
			}
			return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
		}

		private static string Three(Version v)
		{
			if (v == null)
			{
				return "no version";
			}
			return v.Major.ToString(CultureInfo.InvariantCulture) + "." + v.Minor.ToString(CultureInfo.InvariantCulture) + "." + Math.Max(v.Build, 0).ToString(CultureInfo.InvariantCulture);
		}

		private static void Open(string home)
		{
			string text = Path.Combine(home, "Keel.log");
			try
			{
				if (File.Exists(text))
				{
					File.Copy(text, Path.Combine(home, "Keel.previous.log"), overwrite: true);
				}
			}
			catch (Exception)
			{
			}
			try
			{
				File.WriteAllText(text, string.Empty);
				_log = text;
			}
			catch (Exception)
			{
				_log = null;
			}
		}

		private static void Line(string text)
		{
			if (_log == null)
			{
				return;
			}
			try
			{
				File.AppendAllText(_log, DateTime.Now.ToString("HH:mm:ss", CultureInfo.InvariantCulture) + "  " + text + Environment.NewLine);
			}
			catch (Exception)
			{
			}
		}

		private static Exception Inner(Exception e)
		{
			if (!(e is TargetInvocationException) || e.InnerException == null)
			{
				return e;
			}
			return e.InnerException;
		}
	}
}
namespace Doorstop
{
	internal static class Entrypoint
	{
		public static void Start()
		{
			Starter.Begin();
		}
	}
}

Keel/Keel.Core.2.0.0.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Keel.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyProduct("Keel.Core")]
[assembly: AssemblyTitle("Keel.Core")]
[assembly: AssemblyVersion("2.0.0.0")]
namespace Keel;

internal static class Boot
{
	internal static void Start(string home)
	{
		Loader.Begin(home);
	}
}
internal static class Loader
{
	internal static readonly string Version = Three(typeof(Loader).Assembly.GetName().Version);

	private static string _home;

	private static string _game;

	private static bool _bepinex;

	private static int _listening;

	private static bool _resolving;

	private static bool _sharedLoaded;

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

	internal static void Begin(string home)
	{
		try
		{
			_home = home;
			_game = Path.GetDirectoryName(Path.GetFullPath(home));
			if (string.IsNullOrEmpty(_game))
			{
				_game = Directory.GetCurrentDirectory();
			}
			Note.Open(Path.Combine(_home, "Keel.log"));
			Note.Line("Keel " + Version + " is running" + Fingerprint() + ".");
			_bepinex = AppDomain.CurrentDomain.GetData("Keel.BepInEx") as string == "started";
			Settings();
			try
			{
				Services.Publish();
			}
			catch (Exception ex)
			{
				Note.Line("Keel couldn't offer its core to mods: " + ex.Message);
			}
			Wait();
		}
		catch (Exception ex2)
		{
			Note.Line("Keel couldn't start: " + ex2);
		}
	}

	internal static string Three(Version v)
	{
		if (!(v == null))
		{
			return v.Major + "." + v.Minor + "." + Math.Max(v.Build, 0);
		}
		return "?";
	}

	private static string Fingerprint()
	{
		string text = "Keel.Core." + Version + ".dll";
		string text2 = Path.Combine(_home, text);
		string text3 = null;
		try
		{
			text3 = typeof(Loader).Assembly.Location;
		}
		catch (Exception)
		{
		}
		string text4 = text;
		string path = text2;
		if (text3 != null && text3.Length == 0)
		{
			return ", which wasn't loaded from a file";
		}
		if (!string.IsNullOrEmpty(text3))
		{
			try
			{
				if (!string.Equals(Path.GetFullPath(text3), Path.GetFullPath(text2), StringComparison.OrdinalIgnoreCase))
				{
					text4 = text3;
					path = text3;
				}
			}
			catch (Exception)
			{
			}
		}
		try
		{
			byte[] array;
			using (SHA256 sHA = SHA256.Create())
			{
				array = sHA.ComputeHash(File.ReadAllBytes(path));
			}
			StringBuilder stringBuilder = new StringBuilder(array.Length * 2);
			byte[] array2 = array;
			foreach (byte b in array2)
			{
				stringBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
			}
			return ", from " + text4 + " (SHA-256 " + stringBuilder?.ToString() + ")";
		}
		catch (Exception)
		{
			return ", from " + text4;
		}
	}

	private static void Settings()
	{
		string text = Path.Combine(_home, "Keel.cfg");
		try
		{
			string text2 = (File.Exists(text) ? File.ReadAllText(text) : null);
			bool flag = false;
			bool flag2 = false;
			if (text2 != null)
			{
				string[] array = text2.Split('\r', '\n');
				for (int i = 0; i < array.Length; i++)
				{
					string text3 = array[i].Trim();
					if (text3.StartsWith("#", StringComparison.Ordinal))
					{
						continue;
					}
					int num = text3.IndexOf('=');
					if (num >= 0)
					{
						string a = text3.Substring(0, num).Trim();
						if (string.Equals(a, "StartBepInEx", StringComparison.OrdinalIgnoreCase))
						{
							flag = true;
						}
						else if (string.Equals(a, "SkipCores", StringComparison.OrdinalIgnoreCase))
						{
							flag2 = true;
						}
					}
				}
			}
			if (flag && flag2)
			{
				return;
			}
			string newLine = Environment.NewLine;
			StringBuilder stringBuilder = new StringBuilder(1024);
			if (text2 == null)
			{
				stringBuilder.Append("## Settings for Keel").Append(newLine).Append(newLine);
			}
			else
			{
				int num2 = 0;
				for (int j = text2.TrimEnd('\r', '\n', ' ', '\t').Length; j < text2.Length; j++)
				{
					if (text2[j] == '\n' || (text2[j] == '\r' && (j + 1 == text2.Length || text2[j + 1] != '\n')))
					{
						num2++;
					}
				}
				if (text2.Trim().Length > 0 && num2 < 2)
				{
					stringBuilder.Append((num2 == 0) ? (newLine + newLine) : newLine);
				}
			}
			if (!flag)
			{
				stringBuilder.Append("[BepInEx]").Append(newLine).Append(newLine)
					.Append("## Whether Keel starts BepInEx too, when BepInEx is installed in this game")
					.Append(newLine)
					.Append("## folder. If you've switched BepInEx off, set this to false and it stays off.")
					.Append(newLine)
					.Append("# Setting type: Boolean")
					.Append(newLine)
					.Append("# Default value: true")
					.Append(newLine)
					.Append("StartBepInEx = true")
					.Append(newLine);
				if (!flag2)
				{
					stringBuilder.Append(newLine);
				}
			}
			if (!flag2)
			{
				stringBuilder.Append("[Cores]").Append(newLine).Append(newLine)
					.Append("## Versions of Keel's core to pass over, with commas between them, such as")
					.Append(newLine)
					.Append("## 2.1.0. Keel runs the newest core that isn't listed. It adds a core here")
					.Append(newLine)
					.Append("## itself, with a note saying when and why, when the core fails as Keel hands")
					.Append(newLine)
					.Append("## over to it, or the game stops twice in a row during that hand-over.")
					.Append(newLine)
					.Append("# Setting type: String")
					.Append(newLine)
					.Append("SkipCores =")
					.Append(newLine);
			}
			File.AppendAllText(text, stringBuilder.ToString(), (text2 == null) ? new UTF8Encoding(encoderShouldEmitUTF8Identifier: false) : EncodingOf(text));
		}
		catch (Exception ex)
		{
			Note.Line("Keel couldn't write its settings in " + text + ": " + ex.Message);
		}
	}

	private static Encoding EncodingOf(string path)
	{
		byte[] array = new byte[4];
		int num;
		using (FileStream fileStream = File.OpenRead(path))
		{
			num = fileStream.Read(array, 0, 4);
		}
		if (num >= 4 && array[0] == byte.MaxValue && array[1] == 254 && array[2] == 0 && array[3] == 0)
		{
			return new UTF32Encoding(bigEndian: false, byteOrderMark: false);
		}
		if (num >= 4 && array[0] == 0 && array[1] == 0 && array[2] == 254 && array[3] == byte.MaxValue)
		{
			return new UTF32Encoding(bigEndian: true, byteOrderMark: false);
		}
		if (num >= 2 && array[0] == byte.MaxValue && array[1] == 254)
		{
			return new UnicodeEncoding(bigEndian: false, byteOrderMark: false);
		}
		if (num >= 2 && array[0] == 254 && array[1] == byte.MaxValue)
		{
			return new UnicodeEncoding(bigEndian: true, byteOrderMark: false);
		}
		return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
	}

	private static void Wait()
	{
		AppDomain.CurrentDomain.AssemblyLoad += Loaded;
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			if (IsUnity(assemblies[i]))
			{
				Listen();
				return;
			}
		}
		Note.Line("Waiting for the game to load.");
	}

	private static void Loaded(object sender, AssemblyLoadEventArgs args)
	{
		if (IsUnity(args.LoadedAssembly))
		{
			Listen();
		}
	}

	private static bool IsUnity(Assembly a)
	{
		try
		{
			return a.GetName().Name == "UnityEngine.CoreModule";
		}
		catch (Exception)
		{
			return false;
		}
	}

	[MethodImpl(MethodImplOptions.NoInlining)]
	private static void Listen()
	{
		if (Interlocked.Exchange(ref _listening, 1) != 0)
		{
			return;
		}
		AppDomain.CurrentDomain.AssemblyLoad -= Loaded;
		try
		{
			Scenes.Listen();
			Note.Line("The game is loading. Mods will start with its first scene.");
		}
		catch (Exception ex)
		{
			Note.Line("Keel couldn't watch for the game's first scene, so no mods will start: " + ex);
		}
	}

	internal static void StartMods(string scene)
	{
		Note.Line("The first scene, " + scene + ", has loaded.");
		string[] directories;
		try
		{
			directories = Directory.GetDirectories(_home);
		}
		catch (Exception ex)
		{
			Note.Line("Keel couldn't look in " + _home + ": " + ex.Message);
			return;
		}
		Array.Sort(directories, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
		_mods.Clear();
		string[] array = directories;
		foreach (string text in array)
		{
			if (File.Exists(Path.Combine(text, Path.GetFileName(text) + ".dll")))
			{
				_mods.Add(text);
			}
		}
		if (_mods.Count == 0)
		{
			Note.Line("There are no mods in " + _home + ".");
			return;
		}
		if (!_resolving)
		{
			_resolving = true;
			AppDomain.CurrentDomain.AssemblyResolve += FromModFolders;
		}
		LoadShared();
		HashSet<string> hashSet = (_bepinex ? BepInExPlugins() : new HashSet<string>());
		List<KeyValuePair<string, MethodInfo>> list = new List<KeyValuePair<string, MethodInfo>>();
		foreach (string mod in _mods)
		{
			string fileName = Path.GetFileName(mod);
			if (hashSet.Contains(fileName + ".dll"))
			{
				Note.Line(fileName + " is in BepInEx's plugins folder too, so BepInEx runs that copy and this one stays off.");
				continue;
			}
			try
			{
				string text2 = Path.Combine(mod, fileName + ".dll");
				Assembly assembly = Assembly.LoadFrom(text2);
				string location = assembly.Location;
				if (!string.IsNullOrEmpty(location) && !string.Equals(Path.GetFullPath(location), Path.GetFullPath(text2), StringComparison.OrdinalIgnoreCase))
				{
					Note.Line(fileName + " is already loaded from " + location + ", so the copy in " + mod + " stays off.");
				}
				else
				{
					Type type = assembly.GetType("Keel.Entry");
					MethodInfo methodInfo = ((type == null) ? null : type.GetMethod("Start", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null));
					if (methodInfo == null)
					{
						Note.Line(fileName + ".dll isn't built on Keel, so it was left alone.");
					}
					else
					{
						list.Add(new KeyValuePair<string, MethodInfo>(mod, methodInfo));
					}
				}
			}
			catch (Exception e)
			{
				Note.Line(fileName + " couldn't be loaded: " + Inner(e));
			}
		}
		if (list.Count > 0)
		{
			Modded();
		}
		foreach (KeyValuePair<string, MethodInfo> item in list)
		{
			string fileName2 = Path.GetFileName(item.Key);
			try
			{
				Note.Line((string)item.Value.Invoke(null, new object[1] { item.Key }));
			}
			catch (Exception e2)
			{
				Note.Line(fileName2 + " failed to start: " + Inner(e2));
			}
		}
	}

	private static HashSet<string> BepInExPlugins()
	{
		HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		string text = Path.Combine(Path.Combine(_game, "BepInEx"), "plugins");
		if (Directory.Exists(text))
		{
			Collect(text, hashSet, 0);
		}
		return hashSet;
	}

	private static void Collect(string folder, HashSet<string> names, int depth)
	{
		try
		{
			string[] files = Directory.GetFiles(folder, "*.dll");
			foreach (string path in files)
			{
				names.Add(Path.GetFileName(path));
			}
		}
		catch (Exception ex)
		{
			Note.Line("Keel couldn't look in " + folder + ": " + ex.Message);
		}
		if (depth < 16)
		{
			string[] directories;
			try
			{
				directories = Directory.GetDirectories(folder);
			}
			catch (Exception)
			{
				return;
			}
			string[] files = directories;
			for (int i = 0; i < files.Length; i++)
			{
				Collect(files[i], names, depth + 1);
			}
		}
	}

	private static void Modded()
	{
		try
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (!(assembly.GetName().Name != "assembly_valheim"))
				{
					Type type = assembly.GetType("Game");
					FieldInfo fieldInfo = ((type == null) ? null : type.GetField("isModded", BindingFlags.Static | BindingFlags.Public));
					if (fieldInfo == null || fieldInfo.FieldType != typeof(bool))
					{
						Note.Line("The game has no isModded flag, so its menu won't say it's modded.");
						return;
					}
					fieldInfo.SetValue(null, true);
					Note.Line("Told the game that it's modded.");
					return;
				}
			}
			Note.Line("The game's code wasn't loaded, so Keel couldn't tell it that it's modded.");
		}
		catch (Exception ex)
		{
			Note.Line("Keel couldn't tell the game that it's modded: " + ex.Message);
		}
	}

	private static void LoadShared()
	{
		if (_sharedLoaded)
		{
			return;
		}
		_sharedLoaded = true;
		HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		foreach (string mod in _mods)
		{
			hashSet.Add(Path.GetFileName(mod) + ".dll");
		}
		SortedDictionary<string, List<string>> sortedDictionary = new SortedDictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
		foreach (string mod2 in _mods)
		{
			string[] files;
			try
			{
				files = Directory.GetFiles(mod2, "*.dll");
			}
			catch (Exception)
			{
				continue;
			}
			string[] array = files;
			foreach (string text in array)
			{
				string fileName = Path.GetFileName(text);
				if (!hashSet.Contains(fileName) && !string.Equals(fileName, "Keel.dll", StringComparison.OrdinalIgnoreCase) && !fileName.StartsWith("Keel.Core.", StringComparison.OrdinalIgnoreCase))
				{
					if (!sortedDictionary.TryGetValue(fileName, out var value))
					{
						value = (sortedDictionary[fileName] = new List<string>());
					}
					value.Add(text);
				}
			}
		}
		foreach (KeyValuePair<string, List<string>> item in sortedDictionary)
		{
			if (item.Value.Count < 2)
			{
				continue;
			}
			string text2 = null;
			Version version = null;
			foreach (string item2 in item.Value)
			{
				Version version2;
				try
				{
					version2 = AssemblyName.GetAssemblyName(item2).Version;
				}
				catch (Exception)
				{
					continue;
				}
				if (text2 == null || (version2 != null && (version == null || version2.CompareTo(version) > 0)))
				{
					text2 = item2;
					version = version2;
				}
			}
			if (text2 != null)
			{
				try
				{
					Assembly.LoadFrom(text2);
					Note.Line(item.Key + " is in more than one mod's folder, so Keel loads its highest version, " + ((version == null) ? "which has none" : version.ToString()) + ", from " + Path.GetDirectoryName(text2) + ", for all of them.");
				}
				catch (Exception e)
				{
					Note.Line("Keel couldn't load " + text2 + ", which more than one mod keeps: " + Inner(e).Message);
				}
			}
		}
	}

	private static Assembly FromModFolders(object sender, ResolveEventArgs args)
	{
		try
		{
			string name = new AssemblyName(args.Name).Name;
			string text = null;
			Version version = null;
			foreach (string mod in _mods)
			{
				string text2 = Path.Combine(mod, name + ".dll");
				if (File.Exists(text2))
				{
					Version version2;
					try
					{
						version2 = AssemblyName.GetAssemblyName(text2).Version;
					}
					catch (Exception)
					{
						continue;
					}
					if (text == null || (version2 != null && (version == null || version2.CompareTo(version) > 0)))
					{
						text = text2;
						version = version2;
					}
				}
			}
			if (text != null)
			{
				return Assembly.LoadFrom(text);
			}
		}
		catch (Exception)
		{
		}
		return null;
	}

	private static Exception Inner(Exception e)
	{
		if (!(e is TargetInvocationException) || e.InnerException == null)
		{
			return e;
		}
		return e.InnerException;
	}
}
internal sealed class ModState
{
	private static readonly MethodInfo BindAsT = typeof(ModState).GetMethod("BindAs", BindingFlags.Instance | BindingFlags.NonPublic);

	private readonly string _name;

	private readonly string _seed;

	private readonly SettingsFile _settings;

	internal ModState(string id, string name, string version, string folder)
	{
		_name = name;
		string path = Path.Combine(folder, Safe(name) + ".cfg");
		if (!File.Exists(path))
		{
			string text = Path.Combine(Path.Combine(Path.Combine(GameFolder(folder), "BepInEx"), "config"), id + ".cfg");
			if (File.Exists(text))
			{
				_seed = text;
			}
		}
		_settings = new SettingsFile(path, new string[2]
		{
			"Settings for " + name + " " + version,
			"Mod ID: " + id
		}, delegate(string message)
		{
			Debug.LogWarning((object)(name + ": " + message));
		}, _seed);
	}

	internal void Begun()
	{
		if (_seed != null)
		{
			Info(_name + " starts from the settings BepInEx kept in " + _seed + ", and keeps its own from now on, in " + _settings.FilePath + ".");
		}
	}

	internal void Info(string message)
	{
		Debug.Log((object)message);
	}

	internal void Warn(string message)
	{
		Debug.LogWarning((object)message);
	}

	internal bool GetSaving()
	{
		return _settings.Saving;
	}

	internal void SetSaving(bool on)
	{
		_settings.Saving = on;
	}

	internal void Done()
	{
		_settings.Save();
	}

	internal Delegate[] Bind(string section, string key, Type type, object fallback, string about, object limits)
	{
		if (type == null)
		{
			throw new ArgumentNullException("type");
		}
		try
		{
			return (Delegate[])BindAsT.MakeGenericMethod(type).Invoke(this, new object[5] { section, key, fallback, about, limits });
		}
		catch (TargetInvocationException ex)
		{
			if (ex.InnerException == null)
			{
				throw;
			}
			ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
			throw;
		}
	}

	private Delegate[] BindAs<T>(string section, string key, object fallback, string about, object limits)
	{
		Func<T, T> clamp = null;
		string limits2 = null;
		if (limits is string[] array)
		{
			if (typeof(T) != typeof(string))
			{
				throw new ArgumentException("[" + section + "] " + key + " can only have allowed values if it's text.");
			}
			if (array.Length == 0)
			{
				throw new ArgumentException("[" + section + "] " + key + " needs at least one allowed value.");
			}
			string[] list = (string[])array.Clone();
			clamp = (Func<T, T>)(object)(Func<string, string>)((string v) => (Array.IndexOf(list, v) < 0) ? list[0] : v);
			limits2 = SettingsFile.ListLimits(list);
		}
		else if (limits is float[] array2)
		{
			if (typeof(T) != typeof(float) || array2.Length != 2)
			{
				throw new ArgumentException("[" + section + "] " + key + " can only have a range if it's a number, from a low end to a high end.");
			}
			float min = array2[0];
			float max = array2[1];
			if (min.CompareTo(max) >= 0)
			{
				throw new ArgumentException("[" + section + "] " + key + "'s low end has to be lower than its high end.");
			}
			clamp = (Func<T, T>)(object)(Func<float, float>)delegate(float v)
			{
				if (min.CompareTo(v) > 0)
				{
					return min;
				}
				return (max.CompareTo(v) < 0) ? max : v;
			};
			limits2 = SettingsFile.RangeLimits(min, max);
		}
		else if (limits != null)
		{
			throw new ArgumentException("[" + section + "] " + key + " has limits of a kind Keel doesn't know.");
		}
		return _settings.Add(section, key, (T)fallback, about, clamp, limits2);
	}

	private static string Safe(string name)
	{
		char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
		StringBuilder stringBuilder = new StringBuilder(name.Length);
		foreach (char c in name)
		{
			stringBuilder.Append((Array.IndexOf(invalidFileNameChars, c) >= 0) ? '_' : c);
		}
		return stringBuilder.ToString();
	}

	private static string GameFolder(string folder)
	{
		return Path.GetDirectoryName(Path.GetDirectoryName(Path.GetFullPath(folder).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) ?? string.Empty) ?? string.Empty;
	}
}
internal static class Note
{
	private static string _path;

	internal static void Open(string path)
	{
		_path = path;
	}

	internal static void Line(string text)
	{
		if (_path == null)
		{
			return;
		}
		try
		{
			File.AppendAllText(_path, DateTime.Now.ToString("HH:mm:ss", CultureInfo.InvariantCulture) + "  " + text + Environment.NewLine);
		}
		catch (Exception)
		{
		}
	}
}
internal static class Once
{
	private const string Prefix = "Keel.Started.";

	internal static bool Claim(string id, string name, string version, string starter)
	{
		AppDomain currentDomain = AppDomain.CurrentDomain;
		string name2 = "Keel.Started." + id;
		lock (typeof(AppDomain))
		{
			if (currentDomain.GetData(name2) != null)
			{
				return false;
			}
			currentDomain.SetData(name2, starter + " already started " + name + " " + version);
			return true;
		}
	}

	internal static string StaysOff(string id, string name, string version)
	{
		string text = AppDomain.CurrentDomain.GetData("Keel.Started." + id) as string;
		return name + " " + version + " stays off, because " + (text ?? "another copy is already running") + ".";
	}
}
internal static class Scenes
{
	[MethodImpl(MethodImplOptions.NoInlining)]
	internal static void Listen()
	{
		SceneManager.sceneLoaded += First;
	}

	private static void First(Scene scene, LoadSceneMode mode)
	{
		try
		{
			SceneManager.sceneLoaded -= First;
			Loader.StartMods(((Scene)(ref scene)).name);
		}
		catch (Exception ex)
		{
			Note.Line("Starting the mods failed: " + ex);
		}
	}
}
internal static class Services
{
	internal const string Key = "Keel.Core";

	internal const int Contract = 1;

	internal static IDictionary<string, object> Publish()
	{
		AppDomain currentDomain = AppDomain.CurrentDomain;
		lock (typeof(AppDomain))
		{
			if (currentDomain.GetData("Keel.Core") is IDictionary<string, object> result)
			{
				return result;
			}
			IDictionary<string, object> dictionary = new ReadOnlyDictionary<string, object>(new Dictionary<string, object>(StringComparer.Ordinal)
			{
				["version"] = Loader.Version,
				["contract"] = 1,
				["start"] = new Func<string, string, string, string, IDictionary<string, object>, IDictionary<string, object>>(Start)
			});
			currentDomain.SetData("Keel.Core", dictionary);
			return dictionary;
		}
	}

	private static IDictionary<string, object> Start(string id, string name, string version, string folder, IDictionary<string, object> about)
	{
		ModState modState = new ModState(id, name, version, folder);
		Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
		if (!Once.Claim(id, name, version, "Keel"))
		{
			dictionary["run"] = false;
			dictionary["reason"] = Once.StaysOff(id, name, version);
			return new ReadOnlyDictionary<string, object>(dictionary);
		}
		dictionary["run"] = true;
		dictionary["folder"] = folder;
		dictionary["starter"] = "Keel";
		dictionary["info"] = new Action<string>(modState.Info);
		dictionary["warn"] = new Action<string>(modState.Warn);
		dictionary["bind"] = new Func<string, string, Type, object, string, object, Delegate[]>(modState.Bind);
		dictionary["getSaving"] = new Func<bool>(modState.GetSaving);
		dictionary["setSaving"] = new Action<bool>(modState.SetSaving);
		dictionary["done"] = new Action(modState.Done);
		modState.Begun();
		return new ReadOnlyDictionary<string, object>(dictionary);
	}
}
internal sealed class SettingsFile
{
	private abstract class Row
	{
		internal string Section;

		internal string Key;

		internal string About;

		internal Type Type;

		internal string Limits;

		internal Delegate[] Made;

		internal abstract string Text();

		internal abstract string FallbackText();
	}

	private sealed class Row<T> : Row
	{
		internal T Fallback;

		internal T Value;

		internal Func<T, T> Clamp;

		internal override string Text()
		{
			return Toml.Write(Value, Type);
		}

		internal override string FallbackText()
		{
			return Toml.Write(Fallback, Type);
		}
	}

	private readonly string _path;

	private readonly string[] _header;

	private readonly Action<string> _warn;

	private readonly List<Row> _rows = new List<Row>();

	private readonly List<KeyValuePair<string, string>> _readOrder = new List<KeyValuePair<string, string>>();

	private readonly Dictionary<string, string> _read = new Dictionary<string, string>(StringComparer.Ordinal);

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

	private bool _unreadable;

	private bool _saving = true;

	private bool _toldWrite;

	private static readonly char[] Refused = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' };

	internal string FilePath => _path;

	internal bool Saving
	{
		get
		{
			return _saving;
		}
		set
		{
			if (_saving != value)
			{
				_saving = value;
				if (value)
				{
					Save();
				}
			}
		}
	}

	internal SettingsFile(string path, string[] header, Action<string> warn, string seed)
	{
		_path = path;
		_header = header;
		_warn = warn;
		Read(seed ?? path, seed == null);
	}

	internal Delegate[] Add<T>(string section, string key, T fallback, string about, Func<T, T> clamp, string limits)
	{
		Name(section, "section");
		Name(key, "key");
		Type typeFromHandle = typeof(T);
		if (!Toml.Supports(typeFromHandle))
		{
			throw new NotSupportedException("Keel can't keep a setting of type " + typeFromHandle.Name + ".");
		}
		string text = Id(section, key);
		foreach (Row row2 in _rows)
		{
			if (!(Id(row2.Section, row2.Key) != text))
			{
				if (row2.Type != typeFromHandle)
				{
					throw new InvalidCastException("[" + section + "] " + key + " is already a setting of type " + row2.Type.Name + ", not " + typeFromHandle.Name + ".");
				}
				return row2.Made;
			}
		}
		Row<T> row = new Row<T>();
		row.Section = section;
		row.Key = key;
		row.About = about;
		row.Type = typeFromHandle;
		row.Limits = limits;
		row.Clamp = clamp;
		row.Fallback = ((clamp == null) ? fallback : clamp(fallback));
		row.Value = row.Fallback;
		if (_read.TryGetValue(text, out var value))
		{
			_claimed.Add(text);
			if (Toml.TryRead(value, typeFromHandle, out var value2))
			{
				row.Value = ((clamp == null) ? ((T)value2) : clamp((T)value2));
			}
			else if (_warn != null)
			{
				_warn("[" + section + "] " + key + " = " + value + " can't be read, so it's back to its default, " + row.FallbackText() + ".");
			}
		}
		_rows.Add(row);
		Func<T> func = () => row.Value;
		Action<T> action = delegate(T v)
		{
			Set(row, v);
		};
		row.Made = new Delegate[2] { func, action };
		return row.Made;
	}

	private static void Name(string name, string what)
	{
		if (name == null)
		{
			throw new ArgumentNullException(what);
		}
		if (name != name.Trim())
		{
			throw new ArgumentException("A setting's " + what + " can't start or end with a space: \"" + name + "\".", what);
		}
		if (name.IndexOfAny(Refused) >= 0)
		{
			throw new ArgumentException("A setting's " + what + " can't hold = \\ \" ' [ ], a tab or a line break: \"" + name + "\".", what);
		}
	}

	private void Set<T>(Row<T> row, T value)
	{
		if (row.Clamp != null)
		{
			value = row.Clamp(value);
		}
		if (!EqualityComparer<T>.Default.Equals(row.Value, value))
		{
			row.Value = value;
			if (_saving)
			{
				Save();
			}
		}
	}

	private static string Id(string section, string key)
	{
		return section + "\n" + key;
	}

	private void Read(string from, bool own)
	{
		if (!File.Exists(from))
		{
			return;
		}
		string[] array;
		try
		{
			array = File.ReadAllLines(from);
		}
		catch (Exception ex)
		{
			_unreadable = own;
			if (_warn != null)
			{
				_warn("Couldn't read " + from + " (" + ex.Message + "), so the settings are at their defaults for now" + (own ? ", and that file is left as it is." : "."));
			}
			return;
		}
		string text = string.Empty;
		string[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			string text2 = array2[i].Trim();
			if (text2.StartsWith("#", StringComparison.Ordinal))
			{
				continue;
			}
			if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal))
			{
				text = text2.Substring(1, text2.Length - 2);
				continue;
			}
			string[] array3 = text2.Split(new char[1] { '=' }, 2);
			if (array3.Length == 2)
			{
				string text3 = array3[0].Trim();
				string key = Id(text, text3);
				if (!_read.ContainsKey(key))
				{
					_readOrder.Add(new KeyValuePair<string, string>(text, text3));
				}
				_read[key] = array3[1].Trim();
			}
		}
	}

	internal void Save()
	{
		if (_unreadable)
		{
			return;
		}
		string newLine = Environment.NewLine;
		StringBuilder stringBuilder = new StringBuilder(2048);
		string[] header = _header;
		foreach (string value in header)
		{
			stringBuilder.Append("## ").Append(value).Append(newLine);
		}
		stringBuilder.Append(newLine);
		SortedDictionary<string, List<KeyValuePair<Row, string>>> sortedDictionary = new SortedDictionary<string, List<KeyValuePair<Row, string>>>(StringComparer.Ordinal);
		foreach (Row row in _rows)
		{
			Into(sortedDictionary, row.Section).Add(new KeyValuePair<Row, string>(row, row.Key + " = " + row.Text()));
		}
		foreach (KeyValuePair<string, string> item in _readOrder)
		{
			string text = Id(item.Key, item.Value);
			if (!_claimed.Contains(text))
			{
				Into(sortedDictionary, item.Key).Add(new KeyValuePair<Row, string>(null, item.Value + " = " + _read[text]));
			}
		}
		foreach (KeyValuePair<string, List<KeyValuePair<Row, string>>> item2 in sortedDictionary)
		{
			stringBuilder.Append('[').Append(item2.Key).Append(']')
				.Append(newLine);
			foreach (KeyValuePair<Row, string> item3 in item2.Value)
			{
				stringBuilder.Append(newLine);
				if (item3.Key != null)
				{
					Describe(stringBuilder, item3.Key, newLine);
				}
				stringBuilder.Append(item3.Value).Append(newLine);
			}
			stringBuilder.Append(newLine);
		}
		try
		{
			string directoryName = Path.GetDirectoryName(_path);
			if (!string.IsNullOrEmpty(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			string text2 = _path + ".tmp";
			File.WriteAllText(text2, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			if (File.Exists(_path))
			{
				try
				{
					File.Replace(text2, _path, null);
					return;
				}
				catch (Exception)
				{
					File.Copy(text2, _path, overwrite: true);
					File.Delete(text2);
					return;
				}
			}
			File.Move(text2, _path);
		}
		catch (Exception ex2)
		{
			if (!_toldWrite && _warn != null)
			{
				_toldWrite = true;
				_warn("Couldn't save " + _path + ": " + ex2.Message);
			}
		}
	}

	private static List<KeyValuePair<Row, string>> Into(SortedDictionary<string, List<KeyValuePair<Row, string>>> sections, string name)
	{
		if (!sections.TryGetValue(name, out var value))
		{
			value = (sections[name] = new List<KeyValuePair<Row, string>>());
		}
		return value;
	}

	private static void Describe(StringBuilder b, Row row, string nl)
	{
		if (!string.IsNullOrEmpty(row.About))
		{
			string[] array = row.About.Split('\n');
			foreach (string text in array)
			{
				b.Append("## ").Append(text.TrimEnd('\r')).Append(nl);
			}
		}
		b.Append("# Setting type: ").Append(row.Type.Name).Append(nl);
		b.Append("# Default value: ").Append(row.FallbackText()).Append(nl);
		if (row.Limits != null)
		{
			b.Append(row.Limits).Append(nl);
		}
		else if (row.Type.IsEnum)
		{
			b.Append("# Acceptable values: ").Append(string.Join(", ", Enum.GetNames(row.Type))).Append(nl);
			if (row.Type.GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Length != 0)
			{
				b.Append("# More than one can be set at once, with commas between them.").Append(nl);
			}
		}
	}

	internal static string ListLimits(string[] allowed)
	{
		return "# Acceptable values: " + string.Join(", ", allowed);
	}

	internal static string RangeLimits(float min, float max)
	{
		return "# Acceptable value range: From " + min.ToString(NumberFormatInfo.InvariantInfo) + " to " + max.ToString(NumberFormatInfo.InvariantInfo);
	}
}
internal static class Toml
{
	private const string Escaped = "\\\"\n\r\t\0\a\b\v\f'";

	private const string Letters = "\\\"nrt0abvf'";

	private const int Written = 6;

	internal static bool Supports(Type type)
	{
		if (!(type == typeof(bool)) && !(type == typeof(int)) && !(type == typeof(float)) && !(type == typeof(string)) && !(type == typeof(Color)))
		{
			return type.IsEnum;
		}
		return true;
	}

	internal static string Write(object value, Type type)
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		if (type == typeof(bool))
		{
			if (!(bool)value)
			{
				return "false";
			}
			return "true";
		}
		if (type == typeof(int))
		{
			return ((int)value).ToString(NumberFormatInfo.InvariantInfo);
		}
		if (type == typeof(float))
		{
			return ((float)value).ToString(NumberFormatInfo.InvariantInfo);
		}
		if (type == typeof(string))
		{
			return Escape((string)value);
		}
		if (type == typeof(Color))
		{
			return Hex((Color)value);
		}
		if (type.IsEnum)
		{
			return value.ToString();
		}
		throw new NotSupportedException("Keel can't keep a setting of type " + type.Name + ".");
	}

	internal static bool TryRead(string text, Type type, out object value)
	{
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		value = null;
		if (text == null)
		{
			return false;
		}
		try
		{
			if (type == typeof(bool))
			{
				value = bool.Parse(text);
			}
			else if (type == typeof(int))
			{
				value = int.Parse(text, NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
			}
			else if (type == typeof(float))
			{
				value = float.Parse(text, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.InvariantInfo);
			}
			else if (type == typeof(string))
			{
				value = (LooksLikePath(text) ? text : Unescape(text));
			}
			else if (type == typeof(Color))
			{
				if (!TryHex(text, out var colour))
				{
					return false;
				}
				value = colour;
			}
			else
			{
				if (!type.IsEnum)
				{
					return false;
				}
				value = Enum.Parse(type, text, ignoreCase: true);
			}
			return true;
		}
		catch (FormatException)
		{
		}
		catch (OverflowException)
		{
		}
		catch (ArgumentException)
		{
		}
		return false;
	}

	private static bool LooksLikePath(string text)
	{
		int num = (text.StartsWith("\"", StringComparison.Ordinal) ? 1 : 0);
		if (text.Length < num + 3)
		{
			return false;
		}
		char c = text[num];
		if (!char.IsLetterOrDigit(c) && c != '_')
		{
			return false;
		}
		if (text[num + 1] != ':' || text[num + 2] != '\\')
		{
			return false;
		}
		return text.IndexOf("\\\\", num + 2, StringComparison.Ordinal) < 0;
	}

	private static string Hex(Color c)
	{
		//IL_0000: 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_003a: 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)
		return Byte(c.r).ToString("X2", CultureInfo.InvariantCulture) + Byte(c.g).ToString("X2", CultureInfo.InvariantCulture) + Byte(c.b).ToString("X2", CultureInfo.InvariantCulture) + Byte(c.a).ToString("X2", CultureInfo.InvariantCulture);
	}

	private static int Byte(float channel)
	{
		int num = (int)Math.Round(channel * 255f);
		if (num >= 0)
		{
			if (num <= 255)
			{
				return num;
			}
			return 255;
		}
		return 0;
	}

	private static bool TryHex(string text, out Color colour)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		colour = default(Color);
		string text2 = text.Trim().Trim('#', ' ');
		if (text2.Length == 3 || text2.Length == 4)
		{
			StringBuilder stringBuilder = new StringBuilder(8);
			string text3 = text2;
			foreach (char value in text3)
			{
				stringBuilder.Append(value).Append(value);
			}
			text2 = stringBuilder.ToString();
		}
		if (text2.Length == 6)
		{
			text2 += "FF";
		}
		if (text2.Length != 8)
		{
			return false;
		}
		if (!uint.TryParse(text2, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var result))
		{
			return false;
		}
		colour = Color32.op_Implicit(new Color32((byte)(result >> 24), (byte)(result >> 16), (byte)(result >> 8), (byte)result));
		return true;
	}

	private static string Escape(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return string.Empty;
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length + 8);
		foreach (char value in text)
		{
			int num = "\\\"\n\r\t\0\a\b\v\f'".IndexOf(value);
			if (num >= 0 && num < 6)
			{
				stringBuilder.Append('\\').Append("\\\"nrt0abvf'"[num]);
			}
			else
			{
				stringBuilder.Append(value);
			}
		}
		return stringBuilder.ToString();
	}

	private static string Unescape(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return text;
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length);
		for (int i = 0; i < text.Length; i++)
		{
			char c = text[i];
			if (c != '\\' || i + 1 == text.Length)
			{
				stringBuilder.Append(c);
				continue;
			}
			char value = text[++i];
			int num = "\\\"nrt0abvf'".IndexOf(value);
			if (num >= 0)
			{
				stringBuilder.Append("\\\"\n\r\t\0\a\b\v\f'"[num]);
			}
			else
			{
				stringBuilder.Append('\\').Append(value);
			}
		}
		return stringBuilder.ToString();
	}
}

Keel/Daywheel/Daywheel.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Daywheel;
using Keel;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: Main(typeof(Main))]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Daywheel")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.14.0")]
[assembly: AssemblyInformationalVersion("1.0.14")]
[assembly: AssemblyProduct("Daywheel")]
[assembly: AssemblyTitle("Daywheel")]
[assembly: AssemblyVersion("1.0.14.0")]
namespace Keel
{
	internal static class Bep
	{
		private sealed class BepHost : Host
		{
			private readonly Mod _mod;

			private readonly ConfigFile _config;

			private readonly Log _log;

			internal override string Starter => "BepInEx";

			internal override string Folder
			{
				get
				{
					string text = Path.Combine(Paths.ConfigPath, _mod.Name);
					Directory.CreateDirectory(text);
					return text;
				}
			}

			internal override Log Log => _log;

			internal override bool Saving
			{
				get
				{
					return _config.SaveOnConfigSet;
				}
				set
				{
					if (_config.SaveOnConfigSet != value)
					{
						_config.SaveOnConfigSet = value;
						if (value)
						{
							_config.Save();
						}
					}
				}
			}

			internal BepHost(Mod mod, ConfigFile config, ManualLogSource log)
			{
				_mod = mod;
				_config = config;
				_log = new Log((Action<string>)log.LogInfo, (Action<string>)log.LogWarning);
			}

			internal override Setting<T> Bind<T>(string section, string key, T fallback, string about)
			{
				if (!Types.Supported(typeof(T)))
				{
					throw new NotSupportedException("Keel can't keep a setting of type " + typeof(T).Name + ".");
				}
				ConfigEntry<T> entry = _config.Bind<T>(section, key, fallback, about);
				return new Setting<T>(() => entry.Value, delegate(T v)
				{
					entry.Value = v;
				});
			}

			internal override Setting<string> Bind(string section, string key, string fallback, string about, string[] allowed)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Expected O, but got Unknown
				ConfigEntry<string> entry = _config.Bind<string>(section, key, fallback, new ConfigDescription(about, (AcceptableValueBase)(object)new AcceptableValueList<string>(allowed), Array.Empty<object>()));
				return new Setting<string>(() => entry.Value, delegate(string v)
				{
					entry.Value = v;
				});
			}

			internal override Setting<float> Bind(string section, string key, float fallback, string about, float min, float max)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				ConfigEntry<float> entry = _config.Bind<float>(section, key, fallback, new ConfigDescription(about, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>()));
				return new Setting<float>(() => entry.Value, delegate(float v)
				{
					entry.Value = v;
				});
			}
		}

		internal static void Start(Mod mod, ConfigFile config, ManualLogSource log)
		{
			BepHost host = new BepHost(mod, config, log);
			if (!Once.Claim(mod, "BepInEx"))
			{
				log.LogInfo((object)Once.StaysOff(mod));
			}
			else
			{
				mod.Start(host);
			}
		}
	}
	internal static class Core
	{
		internal const string Version = "2.0.0";

		private const string Key = "Keel.Core";

		private const string CoreName = "Keel.Core.";

		private const int Needs = 1;

		internal static IDictionary<string, object> Find(string folder, out string why, out string loaded)
		{
			why = null;
			loaded = null;
			IDictionary<string, object> dictionary = AppDomain.CurrentDomain.GetData("Keel.Core") as IDictionary<string, object>;
			if (dictionary == null)
			{
				lock (typeof(AppDomain))
				{
					dictionary = AppDomain.CurrentDomain.GetData("Keel.Core") as IDictionary<string, object>;
					if (dictionary == null)
					{
						dictionary = Load(folder, out why, out loaded);
					}
				}
			}
			if (dictionary == null)
			{
				return null;
			}
			dictionary.TryGetValue("contract", out var value);
			dictionary.TryGetValue("version", out var value2);
			dictionary.TryGetValue("start", out var value3);
			if (!(value is int) || (int)value < 1 || !(value3 is Func<string, string, string, string, IDictionary<string, object>, IDictionary<string, object>>))
			{
				why = "it needs a newer Keel core than " + ((value2 as string) ?? "the one that's running") + ".";
				return null;
			}
			return dictionary;
		}

		private static IDictionary<string, object> Load(string folder, out string why, out string loaded)
		{
			why = null;
			loaded = null;
			string text = Path.GetDirectoryName(Path.GetFullPath(folder).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) ?? string.Empty;
			List<string> list = new List<string>();
			List<KeyValuePair<Version, string>> list2;
			try
			{
				list2 = Newest(text, Skipped(Path.Combine(text, "Keel.cfg")), list);
			}
			catch (Exception ex)
			{
				why = "Keel couldn't look for its core in " + text + ": " + ex.Message;
				return null;
			}
			foreach (KeyValuePair<Version, string> item in list2)
			{
				string fileName = Path.GetFileName(item.Value);
				bool flag = false;
				string text2;
				try
				{
					AssemblyName assemblyName = AssemblyName.GetAssemblyName(item.Value);
					if (assemblyName.Name != "Keel.Core" || !Same(assemblyName.Version, item.Key))
					{
						text2 = "it isn't the core its name says";
					}
					else
					{
						Assembly assembly = Assembly.LoadFrom(item.Value);
						flag = true;
						Version version = assembly.GetName().Version;
						Type type = (Same(version, item.Key) ? assembly.GetType("Keel.Services") : null);
						MethodInfo methodInfo = ((type == null) ? null : type.GetMethod("Publish", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
						IDictionary<string, object> dictionary = ((methodInfo == null) ? null : (methodInfo.Invoke(null, null) as IDictionary<string, object>));
						if (dictionary != null)
						{
							loaded = "It loaded Keel's core, " + fileName + ", itself" + ((list.Count == 0) ? "." : (", after passing over " + string.Join(", ", list.ToArray()) + "."));
							return dictionary;
						}
						text2 = (Same(version, item.Key) ? "it has no way in that this copy of Keel knows" : ("the game already has core " + Three(version) + " loaded"));
					}
				}
				catch (Exception)
				{
					text2 = (flag ? "it failed as it loaded" : "it couldn't be loaded");
				}
				list.Add(fileName + " (" + text2 + ")");
				if (flag)
				{
					break;
				}
			}
			why = ((list.Count == 0) ? ("Keel's core isn't in " + text + ".") : ("none of the cores in " + text + " could be used: " + string.Join(", ", list.ToArray()) + "."));
			return null;
		}

		private static List<KeyValuePair<Version, string>> Newest(string home, List<string> skip, List<string> passed)
		{
			List<KeyValuePair<Version, string>> list = new List<KeyValuePair<Version, string>>();
			if (!Directory.Exists(home))
			{
				return list;
			}
			string[] files = Directory.GetFiles(home, "Keel.Core.*.dll");
			foreach (string text in files)
			{
				string fileName = Path.GetFileName(text);
				Version version = Named(fileName);
				if (version == null)
				{
					passed.Add(fileName + " (it isn't named like a core)");
				}
				else if (skip.Contains(Three(version)))
				{
					passed.Add(fileName + " (SkipCores names it)");
				}
				else
				{
					list.Add(new KeyValuePair<Version, string>(version, text));
				}
			}
			list.Sort(delegate(KeyValuePair<Version, string> a, KeyValuePair<Version, string> b)
			{
				int num = b.Key.CompareTo(a.Key);
				return (num == 0) ? string.CompareOrdinal(a.Value, b.Value) : num;
			});
			return list;
		}

		private static List<string> Skipped(string path)
		{
			List<string> list = new List<string>();
			try
			{
				if (!File.Exists(path))
				{
					return list;
				}
				string[] array = File.ReadAllLines(path);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.StartsWith("#", StringComparison.Ordinal))
					{
						continue;
					}
					int num = text.IndexOf('=');
					if (num < 0 || !string.Equals(text.Substring(0, num).Trim(), "SkipCores", StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					string[] array2 = text.Substring(num + 1).Split(new char[1] { ',' });
					for (int j = 0; j < array2.Length; j++)
					{
						string text2 = array2[j].Trim().Trim(new char[1] { '"' }).Trim();
						if (text2.StartsWith("Keel.Core.", StringComparison.OrdinalIgnoreCase))
						{
							text2 = text2.Substring("Keel.Core.".Length);
						}
						if (text2.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
						{
							text2 = text2.Substring(0, text2.Length - 4);
						}
						Version version = Named("Keel.Core." + text2 + ".dll");
						if (version != null)
						{
							list.Add(Three(version));
						}
					}
				}
			}
			catch (Exception)
			{
			}
			return list;
		}

		private static Version Named(string file)
		{
			if (file.Length <= "Keel.Core.".Length + 4 || !file.StartsWith("Keel.Core.", StringComparison.OrdinalIgnoreCase) || !file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			string[] array = file.Substring("Keel.Core.".Length, file.Length - "Keel.Core.".Length - 4).Split(new char[1] { '.' });
			if (array.Length != 3)
			{
				return null;
			}
			int[] array2 = new int[3];
			for (int i = 0; i < 3; i++)
			{
				string text = array[i];
				if (text.Length == 0 || text.Length > 9 || (text.Length > 1 && text[0] == '0'))
				{
					return null;
				}
				int num = 0;
				string text2 = text;
				foreach (char c in text2)
				{
					if (c < '0' || c > '9')
					{
						return null;
					}
					num = num * 10 + (c - 48);
				}
				array2[i] = num;
			}
			return new Version(array2[0], array2[1], array2[2]);
		}

		private static bool Same(Version v, Version named)
		{
			if (v != null && v.Major == named.Major && v.Minor == named.Minor)
			{
				return v.Build == named.Build;
			}
			return false;
		}

		private static string Three(Version v)
		{
			if (v == null)
			{
				return "no version";
			}
			return v.Major.ToString(CultureInfo.InvariantCulture) + "." + v.Minor.ToString(CultureInfo.InvariantCulture) + "." + Math.Max(v.Build, 0).ToString(CultureInfo.InvariantCulture);
		}
	}
	internal static class Entry
	{
		public static string Start(string folder)
		{
			MainAttribute mainAttribute = (MainAttribute)Attribute.GetCustomAttribute(typeof(Entry).Assembly, typeof(MainAttribute));
			if (mainAttribute == null || mainAttribute.Mod == null)
			{
				return typeof(Entry).Assembly.GetName().Name + " doesn't name its Mod class with [assembly: Keel.Main(...)], so it wasn't started.";
			}
			Mod mod = (Mod)Activator.CreateInstance(mainAttribute.Mod, nonPublic: true);
			string why;
			string loaded;
			IDictionary<string, object> dictionary = Core.Find(folder, out why, out loaded);
			if (dictionary == null)
			{
				return mod.Name + " " + mod.Version + " wasn't started, because " + why;
			}
			Dictionary<string, object> dictionary2 = new Dictionary<string, object>(StringComparer.Ordinal);
			dictionary2["keel"] = "2.0.0";
			IDictionary<string, object> dictionary3 = ((Func<string, string, string, string, IDictionary<string, object>, IDictionary<string, object>>)dictionary["start"])(mod.Id, mod.Name, mod.Version, folder, dictionary2);
			dictionary3.TryGetValue("run", out var value);
			if (!(value is bool) || !(bool)value)
			{
				dictionary3.TryGetValue("reason", out var value2);
				return (value2 as string) ?? (mod.Name + " " + mod.Version + " stays off.");
			}
			mod.Start(new CoreHost(dictionary3));
			dictionary3.TryGetValue("done", out var value3);
			if (value3 is Action)
			{
				((Action)value3)();
			}
			return mod.Name + " " + mod.Version + " started." + ((loaded == null) ? string.Empty : (" " + loaded));
		}
	}
	internal sealed class CoreHost : Host
	{
		private readonly string _starter;

		private readonly string _folder;

		private readonly Log _log;

		private readonly Func<string, string, Type, object, string, object, Delegate[]> _bind;

		private readonly Func<bool> _getSaving;

		private readonly Action<bool> _setSaving;

		internal override string Starter => _starter;

		internal override string Folder
		{
			get
			{
				Directory.CreateDirectory(_folder);
				return _folder;
			}
		}

		internal override Log Log => _log;

		internal override bool Saving
		{
			get
			{
				return _getSaving();
			}
			set
			{
				_setSaving(value);
			}
		}

		internal CoreHost(IDictionary<string, object> state)
		{
			_starter = (string)state["starter"];
			_folder = (string)state["folder"];
			_log = new Log((Action<string>)state["info"], (Action<string>)state["warn"]);
			_bind = (Func<string, string, Type, object, string, object, Delegate[]>)state["bind"];
			_getSaving = (Func<bool>)state["getSaving"];
			_setSaving = (Action<bool>)state["setSaving"];
		}

		internal override Setting<T> Bind<T>(string section, string key, T fallback, string about)
		{
			return Wrap<T>(_bind(section, key, typeof(T), fallback, about, null));
		}

		internal override Setting<string> Bind(string section, string key, string fallback, string about, string[] allowed)
		{
			return Wrap<string>(_bind(section, key, typeof(string), fallback, about, allowed ?? new string[0]));
		}

		internal override Setting<float> Bind(string section, string key, float fallback, string about, float min, float max)
		{
			return Wrap<float>(_bind(section, key, typeof(float), fallback, about, new float[2] { min, max }));
		}

		private static Setting<T> Wrap<T>(Delegate[] made)
		{
			return new Setting<T>((Func<T>)made[0], (Action<T>)made[1]);
		}
	}
	internal abstract class Host
	{
		internal abstract string Starter { get; }

		internal abstract string Folder { get; }

		internal abstract Log Log { get; }

		internal abstract bool Saving { get; set; }

		internal abstract Setting<T> Bind<T>(string section, string key, T fallback, string about);

		internal abstract Setting<string> Bind(string section, string key, string fallback, string about, string[] allowed);

		internal abstract Setting<float> Bind(string section, string key, float fallback, string about, float min, float max);
	}
	internal sealed class Log
	{
		private readonly Action<string> _info;

		private readonly Action<string> _warn;

		internal Log(Action<string> info, Action<string> warn)
		{
			_info = info;
			_warn = warn;
		}

		internal void Info(string message)
		{
			if (_info != null)
			{
				_info(message);
			}
		}

		internal void Warn(string message)
		{
			if (_warn != null)
			{
				_warn(message);
			}
		}
	}
	internal abstract class Mod
	{
		internal abstract string Id { get; }

		internal abstract string Name { get; }

		internal abstract string Version { get; }

		internal abstract void Start(Host host);
	}
	[AttributeUsage(AttributeTargets.Assembly)]
	internal sealed class MainAttribute : Attribute
	{
		internal Type Mod { get; }

		internal MainAttribute(Type mod)
		{
			Mod = mod;
		}
	}
	internal static class Once
	{
		private const string Prefix = "Keel.Started.";

		internal static bool Claim(Mod mod, string starter)
		{
			AppDomain currentDomain = AppDomain.CurrentDomain;
			string name = "Keel.Started." + mod.Id;
			lock (typeof(AppDomain))
			{
				if (currentDomain.GetData(name) != null)
				{
					return false;
				}
				currentDomain.SetData(name, starter + " already started " + mod.Name + " " + mod.Version);
				return true;
			}
		}

		internal static string StaysOff(Mod mod)
		{
			string text = AppDomain.CurrentDomain.GetData("Keel.Started." + mod.Id) as string;
			return mod.Name + " " + mod.Version + " stays off, because " + (text ?? "another copy is already running") + ".";
		}
	}
	internal sealed class Setting<T>
	{
		private readonly Func<T> _get;

		private readonly Action<T> _set;

		internal T Value
		{
			get
			{
				return _get();
			}
			set
			{
				_set(value);
			}
		}

		internal Setting(Func<T> get, Action<T> set)
		{
			_get = get;
			_set = set;
		}
	}
	internal static class Types
	{
		internal static bool Supported(Type type)
		{
			if (!(type == typeof(bool)) && !(type == typeof(int)) && !(type == typeof(float)) && !(type == typeof(string)) && !(type == typeof(Color)))
			{
				return type.IsEnum;
			}
			return true;
		}
	}
}
namespace Daywheel
{
	internal sealed class ColourField : MaskableGraphic
	{
		private const int Across = 24;

		private const int Up = 8;

		private float _strength = 1f;

		internal float Strength
		{
			get
			{
				return _strength;
			}
			set
			{
				value = Mathf.Clamp01(value);
				if (!(Mathf.Abs(value - _strength) < 0.002f))
				{
					_strength = value;
					((Graphic)this).SetVerticesDirty();
				}
			}
		}

		protected override void OnPopulateMesh(VertexHelper vh)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0074: Unknown result type (might be due to invalid IL or missing references)
			vh.Clear();
			Rect pixelAdjustedRect = ((Graphic)this).GetPixelAdjustedRect();
			Vector3 val = default(Vector3);
			for (int i = 0; i <= 8; i++)
			{
				float num = (float)i / 8f;
				for (int j = 0; j <= 24; j++)
				{
					float num2 = (float)j / 24f;
					((Vector3)(ref val))..ctor(((Rect)(ref pixelAdjustedRect)).xMin + num2 * ((Rect)(ref pixelAdjustedRect)).width, ((Rect)(ref pixelAdjustedRect)).yMin + num * ((Rect)(ref pixelAdjustedRect)).height, 0f);
					vh.AddVert(val, Color32.op_Implicit(Wheel.FromHsl(num2, _strength, num)), Vector4.op_Implicit(Vector2.zero));
				}
			}
			int num3 = 25;
			for (int k = 0; k < 8; k++)
			{
				for (int l = 0; l < 24; l++)
				{
					int num4 = k * num3 + l;
					vh.AddTriangle(num4, num4 + num3, num4 + num3 + 1);
					vh.AddTriangle(num4, num4 + num3 + 1, num4 + 1);
				}
			}
		}
	}
	internal static class Guard
	{
		private static readonly HashSet<string> _said = new HashSet<string>();

		internal static void Run(string name, Action action)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				if (!_said.Contains(name))
				{
					_said.Add(name);
					if (Main.Log != null)
					{
						Main.Log.Warn("Daywheel: " + name + " failed and was skipped. " + ex.GetType().Name + ": " + ex.Message);
					}
				}
			}
		}
	}
	internal sealed class Main : Mod
	{
		public const string Guid = "com.vysesdarkheart.daywheel";

		public const string Title = "Daywheel";

		public const string Ver = "1.0.14";

		internal static Setting<bool> Show;

		internal static Setting<bool> ShowDay;

		internal static Setting<Color> DayColor;

		internal static Setting<float> Size;

		internal static Setting<float> X;

		internal static Setting<float> Y;

		internal static Setting<string> MoveKey;

		internal static Setting<string> ThemeName;

		internal static Setting<float> Glow;

		internal static Log Log;

		private static Host _host;

		internal override string Id => "com.vysesdarkheart.daywheel";

		internal override string Name => "Daywheel";

		internal override string Version => "1.0.14";

		internal static void Saving(bool on)
		{
			if (_host != null)
			{
				_host.Saving = on;
			}
		}

		internal override void Start(Host host)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			_host = host;
			Log = host.Log;
			Show = host.Bind("Wheel", "Show", fallback: true, "Turns the wheel on or off.");
			ShowDay = host.Bind("Wheel", "ShowDayCount", fallback: true, "Shows the day number under the wheel.");
			DayColor = host.Bind<Color>("Wheel", "DayColor", Wheel.DayDefault, "The day number's colour, as a hex code: FFFFFF is white, FFD27A gold, 8B8477 the default. Two more digits on the end set how solid it is, from 00 (invisible) to FF (solid).");
			Size = host.Bind("Wheel", "Size", 62f, "Width, in the game's interface units, so it follows the game's UI scale.");
			X = host.Bind("Wheel", "X", -30f, "Distance from the right edge. A bigger negative number moves it left.");
			Y = host.Bind("Wheel", "Y", -250f, "Distance from the top edge. A bigger negative number moves it down. The minimap's size changes with screen resolution, so change this one if the two overlap.");
			MoveKey = host.Bind("Wheel", "MoveKey", "F8", "Press this to move the wheel, and press it again when you're done. Your character stands still in between, and a menu next to the wheel lists the keys. Put away a hammer, hoe or cultivator first. Any Unity key name, like F8 or Insert. A name Unity doesn't know means F8, and the log says so.");
			ThemeName = host.Bind("Look", "Theme", Themes.All[0].Name, "Which look to use, spelled exactly as listed. While you're moving the wheel, right-click or press End for the next one, and Home for the one before.", Themes.Names());
			Glow = host.Bind("Look", "Glow", 1f, "Glow strength. 1 is normal, 0 turns it off.", 0f, 2f);
			Log.Info("Daywheel 1.0.14 loaded, started by " + host.Starter + ".");
			Guard.Run("start", delegate
			{
				//IL_0005: 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_0010: Expected O, but got Unknown
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = new GameObject("Daywheel");
				Object.DontDestroyOnLoad((Object)val);
				((Object)val).hideFlags = (HideFlags)61;
				val.AddComponent<Wheel>();
			});
		}
	}
	[BepInPlugin("com.vysesdarkheart.daywheel", "Daywheel", "1.0.14")]
	[BepInProcess("valheim.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			Bep.Start(new Main(), ((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
		}
	}
	internal sealed class Theme
	{
		internal readonly string Name;

		internal readonly string Folder;

		internal readonly float Glow;

		internal Sprite HaloDay;

		internal Sprite HaloNight;

		internal Sprite Ring;

		internal Sprite MoonGlow;

		internal Sprite Fire;

		internal Sprite SunGlow;

		internal Sprite Sun;

		internal Sprite Moon;

		internal Sprite Mark;

		internal bool Tried;

		internal bool Ready;

		internal bool Softened;

		internal Theme(string name, string folder, float glow)
		{
			Name = name;
			Folder = folder;
			Glow = glow;
		}
	}
	internal static class Themes
	{
		internal static readonly Theme[] All = new Theme[7]
		{
			new Theme("Ember and moonstone", "ember-and-moonstone", 0.82f),
			new Theme("Northern twilight", "northern-twilight", 0.68f),
			new Theme("Rootbound forest", "rootbound-forest", 0.56f),
			new Theme("Dvergr lantern", "dvergr-lantern", 0.75f),
			new Theme("The wolf chase", "the-wolf-chase", 0.33f),
			new Theme("Mountain relic", "mountain-relic", 0.43f),
			new Theme("Ashlands", "ashlands", 1.06f)
		};

		internal const float Soften = 2.2f;

		private static Dictionary<string, string> _names;

		private static bool? _linear;

		private static bool _told;

		internal static string[] Names()
		{
			string[] array = new string[All.Length];
			for (int i = 0; i < All.Length; i++)
			{
				array[i] = All[i].Name;
			}
			return array;
		}

		internal static Theme Find(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				string b = name.Trim();
				for (int i = 0; i < All.Length; i++)
				{
					if (string.Equals(All[i].Name, b, StringComparison.OrdinalIgnoreCase))
					{
						return All[i];
					}
				}
			}
			return All[0];
		}

		internal static int IndexOf(Theme t)
		{
			for (int i = 0; i < All.Length; i++)
			{
				if (All[i] == t)
				{
					return i;
				}
			}
			return 0;
		}

		internal static bool Load(Theme t)
		{
			if (t == null)
			{
				return false;
			}
			if (t.Tried)
			{
				return t.Ready;
			}
			t.Tried = true;
			bool flag = Linear() && CanSoften();
			t.Ready = Read(t, flag);
			if (!t.Ready && flag)
			{
				Drop(t);
				flag = false;
				t.Ready = Read(t, soften: false);
			}
			t.Softened = t.Ready && flag;
			if (t.Ready)
			{
				Tell(t.Softened);
			}
			if (!t.Ready && Main.Log != null)
			{
				Main.Log.Warn("Daywheel: the " + t.Name + " look is missing a picture and was skipped.");
			}
			return t.Ready;
		}

		private static bool Read(Theme t, bool soften)
		{
			t.HaloDay = Picture(t.Folder, "halo-day", soften);
			t.HaloNight = Picture(t.Folder, "halo-night", soften);
			t.Ring = Picture(t.Folder, "ring", soften: false);
			t.MoonGlow = Picture(t.Folder, "glow-moon", soften);
			t.Fire = Picture(t.Folder, "glow-fire", soften);
			t.SunGlow = Picture(t.Folder, "glow-sun", soften);
			t.Sun = Picture(t.Folder, "sun", soften: false);
			t.Moon = Picture(t.Folder, "moon", soften: false);
			t.Mark = Picture(t.Folder, "marker", soften: false);
			if ((Object)(object)t.HaloDay != (Object)null && (Object)(object)t.HaloNight != (Object)null && (Object)(object)t.Ring != (Object)null && (Object)(object)t.MoonGlow != (Object)null && (Object)(object)t.Fire != (Object)null && (Object)(object)t.SunGlow != (Object)null && (Object)(object)t.Sun != (Object)null && (Object)(object)t.Moon != (Object)null)
			{
				return (Object)(object)t.Mark != (Object)null;
			}
			return false;
		}

		private static void Drop(Theme t)
		{
			Sprite[] array = (Sprite[])(object)new Sprite[9] { t.HaloDay, t.HaloNight, t.Ring, t.MoonGlow, t.Fire, t.SunGlow, t.Sun, t.Moon, t.Mark };
			foreach (Sprite val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					if ((Object)(object)val.texture != (Object)null)
					{
						Object.Destroy((Object)(object)val.texture);
					}
					Object.Destroy((Object)(object)val);
				}
			}
		}

		internal static bool Linear()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (_linear.HasValue)
			{
				return _linear.Value;
			}
			bool flag = false;
			try
			{
				flag = (int)QualitySettings.activeColorSpace == 1;
			}
			catch (Exception)
			{
			}
			_linear = flag;
			return flag;
		}

		private static void Tell(bool softened)
		{
			if (!_told && Main.Log != null)
			{
				_told = true;
				if (!Linear())
				{
					Main.Log.Info("Daywheel: the game mixes colours in gamma space, so the glow is drawn as it is.");
				}
				else if (softened)
				{
					Main.Log.Info("Daywheel: the game mixes colours in linear space, so the glow is adjusted to look as it was drawn.");
				}
				else
				{
					Main.Log.Warn("Daywheel: the game mixes colours in linear space, but the glow couldn't be adjusted, so it may look stronger than it was drawn.");
				}
			}
		}

		private static bool CanSoften()
		{
			try
			{
				return SystemInfo.SupportsTextureFormat((TextureFormat)17);
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static Sprite Picture(string folder, string layer, bool soften)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_0108: 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)
			if (!Resources().TryGetValue("themes/" + folder + "/" + layer + ".png", out var value))
			{
				return null;
			}
			byte[] array;
			using (Stream stream = typeof(Themes).Assembly.GetManifestResourceStream(value))
			{
				if (stream == null)
				{
					return null;
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array, !soften))
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			if (soften)
			{
				Texture2D val2 = Repack(val);
				Object.Destroy((Object)(object)val);
				if ((Object)(object)val2 == (Object)null)
				{
					return null;
				}
				val = val2;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			((Object)val).name = "Daywheel " + folder + " " + layer;
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			((Object)obj).name = ((Object)val).name;
			return obj;
		}

		private static Texture2D Repack(Texture2D drawn)
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			Texture2D val = null;
			try
			{
				Color32[] pixels = drawn.GetPixels32();
				Color[] array = (Color[])(object)new Color[pixels.Length];
				for (int i = 0; i < pixels.Length; i++)
				{
					Color32 val2 = pixels[i];
					array[i] = new Color(Mathf.GammaToLinearSpace((float)(int)val2.r / 255f), Mathf.GammaToLinearSpace((float)(int)val2.g / 255f), Mathf.GammaToLinearSpace((float)(int)val2.b / 255f), Mathf.Pow((float)(int)val2.a / 255f, 2.2f));
				}
				val = new Texture2D(((Texture)drawn).width, ((Texture)drawn).height, (TextureFormat)17, false, true);
				val.SetPixels(array);
				val.Apply(false, true);
				return val;
			}
			catch (Exception)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				return null;
			}
		}

		private static Dictionary<string, string> Resources()
		{
			if (_names != null)
			{
				return _names;
			}
			_names = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			string[] manifestResourceNames = typeof(Themes).Assembly.GetManifestResourceNames();
			foreach (string text in manifestResourceNames)
			{
				_names[text.Replace('\\', '/')] = text;
			}
			return _names;
		}
	}
	internal class Wheel : MonoBehaviour
	{
		private const float Dawn = 0.25f;

		private const float Dusk = 0.75f;

		private const float Twilight = 0.04f;

		private const float Orbit = 0.164f;

		private const double Tau = Math.PI * 2.0;

		internal static readonly Color DayDefault = Color32.op_Implicit(new Color32((byte)139, (byte)132, (byte)119, byte.MaxValue));

		private const float PickHeight = 40f;

		private const float PickGap = 6f;

		private const float PickAcross = 1f;

		private const float PickUp = 0.5f;

		private const float TapSeconds = 0.35f;

		private const float TapTravel = 6f;

		private const float HintSize = 16f;

		private const float HintPadX = 10f;

		private const float HintPadY = 7f;

		private const float HintGap = 6f;

		private const float HintEdge = 8f;

		private const string HintKeyHex = "#E6C27A";

		private static readonly Color HintText = Color32.op_Implicit(new Color32((byte)236, (byte)231, (byte)218, byte.MaxValue));

		private const float HintShade = 0.85f;

		private const float SamePress = 0.25f;

		private RectTransform _root;

		private RectTransform _ringRt;

		private RectTransform _moonGlowRt;

		private RectTransform _fireRt;

		private RectTransform _sunGlowRt;

		private RectTransform _sunRt;

		private RectTransform _moonRt;

		private RectTransform _markRt;

		private Image _haloDay;

		private Image _haloNight;

		private Image _ring;

		private Image _moonGlow;

		private Image _fire;

		private Image _sunGlow;

		private Image _sun;

		private Image _moon;

		private Image _mark;

		private RectTransform _under;

		private Canvas _canvas;

		private TMP_Text _label;

		private TMP_Text _hint;

		private RectTransform _hintRt;

		private ColourField _field;

		private RectTransform _fieldRt;

		private RectTransform _dotRt;

		private Image _dotFill;

		private Theme _theme;

		private string _worn;

		private bool _shown;

		private int _lastDay = -1;

		private Color _dayColor;

		private float _dayWidth;

		private readonly List<KeyValuePair<RectTransform, float>> _pieces = new List<KeyValuePair<RectTransform, float>>();

		private float _across;

		private bool _moving;

		private bool _held;

		private bool _over;

		private bool _picking;

		private float _pickFrom;

		private float _pickTravel;

		private float _pickH;

		private float _pickS = 1f;

		private float _pickL;

		private float _pickAlpha = 1f;

		private bool _pickFromDefault;

		private PlayerController _still;

		private readonly Dictionary<int, float> _lastPress = new Dictionary<int, float>();

		private const float DeltaToPixels = 20f;

		private static string _badKey;

		private void Update()
		{
			Guard.Run("wheel", Tick);
		}

		private void OnDestroy()
		{
			Guard.Run("wheel cleanup", Clear);
		}

		private void Tick()
		{
			//IL_01d2: 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_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_04de: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: 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_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ef: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			if ((Main.Show != null && !Main.Show.Value) || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Hud.instance == (Object)null || Hidden())
			{
				End();
				Show(on: false);
				return;
			}
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				End();
				Show(on: false);
			}
			else
			{
				if ((Object)(object)_root == (Object)null && !Build())
				{
					return;
				}
				string text = ((Main.ThemeName == null) ? null : Main.ThemeName.Value);
				if (_theme == null || !string.Equals(text, _worn, StringComparison.Ordinal))
				{
					if (!Wear(Themes.Find(text)))
					{
						End();
						Show(on: false);
						return;
					}
					_worn = text;
				}
				Show(on: true);
				Place();
				float num = Mathf.Clamp((Main.Size == null) ? 62f : Main.Size.Value, 24f, 400f);
				if (Mathf.Abs(num - _across) > 0.01f)
				{
					Fit(num);
				}
				if (_moving)
				{
					Move(0f, 0f);
				}
				Vector2 val = Keep(new Vector2((Main.X == null) ? (-30f) : Main.X.Value, (Main.Y == null) ? (-250f) : Main.Y.Value));
				if (_root.anchoredPosition != val)
				{
					_root.anchoredPosition = val;
				}
				if (_moving)
				{
					Aim();
					Swatch();
				}
				float num2 = 0f;
				try
				{
					num2 = instance.GetDayFraction();
				}
				catch (Exception)
				{
				}
				Vector3 localEulerAngles = default(Vector3);
				((Vector3)(ref localEulerAngles))..ctor(0f, 0f, num2 * 360f);
				((Transform)_ringRt).localEulerAngles = localEulerAngles;
				((Transform)_moonGlowRt).localEulerAngles = localEulerAngles;
				((Transform)_fireRt).localEulerAngles = localEulerAngles;
				float track = _across * 0.164f;
				Ride(_sunRt, 0.5f - num2, track);
				Ride(_sunGlowRt, 0.5f - num2, track);
				Ride(_moonRt, 0f - num2, track);
				double unscaledTimeAsDouble = Time.unscaledTimeAsDouble;
				float num3 = Daylight(num2);
				float num4 = _theme.Glow * ((Main.Glow == null) ? 1f : Mathf.Max(0f, Main.Glow.Value));
				float num5 = 0.58f + 0.14f * (float)Math.Sin(13.194689145077131 * unscaledTimeAsDouble) + 0.08f * (float)Math.Sin(24.504422698000386 * unscaledTimeAsDouble + 0.7) + 0.045f * (float)Math.Sin(45.867252742410976 * unscaledTimeAsDouble + 1.4);
				float num6 = 0.8f + 0.2f * (float)Math.Sin(unscaledTimeAsDouble * 0.8);
				float num7 = 0.84f + 0.16f * (float)Math.Sin(unscaledTimeAsDouble * 0.63 + 1.0);
				((Transform)_sunRt).localEulerAngles = new Vector3(0f, 0f, 0f - (float)(unscaledTimeAsDouble * 7.0 % 360.0));
				bool softened = _theme.Softened;
				Fade(_haloDay, Soft(num3 * num6 * 0.7f * num4, softened));
				Fade(_haloNight, Soft((1f - num3) * num6 * 0.7f * num4, softened));
				Fade(_moonGlow, Soft(num7 * (0.48f + 0.52f * (1f - num3)) * num4, softened));
				Fade(_fire, Soft((0.4f + 0.6f * num3) * num5 * 1.7f * num4, softened));
				Fade(_sunGlow, Soft((0.22f + 0.78f * num3) * num5 * num4, softened));
				Fade(_sun, 0.64f + 0.36f * num3);
				Fade(_moon, 0.76f + 0.24f * (1f - num3));
				if ((Object)(object)_label == (Object)null)
				{
					return;
				}
				if (Main.ShowDay != null && !Main.ShowDay.Value)
				{
					if (_label.text.Length > 0)
					{
						_label.text = string.Empty;
					}
					_lastDay = -1;
					return;
				}
				int num8 = 0;
				try
				{
					num8 = instance.GetDay();
				}
				catch (Exception)
				{
				}
				Color val2 = ((Main.DayColor == null) ? DayDefault : Main.DayColor.Value);
				if (num8 != _lastDay || !(val2 == _dayColor))
				{
					_lastDay = num8;
					_dayColor = val2;
					_label.text = "<color=#" + ColorUtility.ToHtmlStringRGBA(val2) + ">Day " + num8.ToString(CultureInfo.InvariantCulture) + "</color>";
					_dayWidth = _label.GetPreferredValues(_label.text).x;
				}
			}
		}

		private bool Wear(Theme want)
		{
			if (!Themes.Load(want))
			{
				want = null;
				for (int i = 0; i < Themes.All.Length; i++)
				{
					if (want != null)
					{
						break;
					}
					if (Themes.Load(Themes.All[i]))
					{
						want = Themes.All[i];
					}
				}
				if (want == null)
				{
					return false;
				}
			}
			_haloDay.sprite = want.HaloDay;
			_haloNight.sprite = want.HaloNight;
			_ring.sprite = want.Ring;
			_moonGlow.sprite = want.MoonGlow;
			_fire.sprite = want.Fire;
			_sunGlow.sprite = want.SunGlow;
			_sun.sprite = want.Sun;
			_moon.sprite = want.Moon;
			_mark.sprite = want.Mark;
			_theme = want;
			return true;
		}

		private static void Fade(Image img, float a)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)img).color = new Color(1f, 1f, 1f, Mathf.Clamp01(a));
		}

		private static float Soft(float a, bool softened)
		{
			a = Mathf.Clamp01(a);
			if (!softened)
			{
				return a;
			}
			return Mathf.Pow(a, 2.2f);
		}

		private void Place()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (Pressed(MoveKey()))
			{
				if (_moving)
				{
					End();
				}
				else
				{
					Begin();
				}
			}
			if (!_moving)
			{
				return;
			}
			if (GameScreenOpen() || Building(Player.m_localPlayer))
			{
				End();
				return;
			}
			if (Pressed((KeyCode)279))
			{
				Turn(1);
			}
			if (Pressed((KeyCode)278))
			{
				Turn(-1);
			}
			float num = Time.unscaledDeltaTime * 260f;
			if (Held((KeyCode)304) || Held((KeyCode)303))
			{
				num *= 3f;
			}
			if (Held((KeyCode)306) || Held((KeyCode)305))
			{
				num *= 0.22f;
			}
			float num2 = 0f;
			float num3 = 0f;
			if (Held((KeyCode)276))
			{
				num2 -= num;
			}
			if (Held((KeyCode)275))
			{
				num2 += num;
			}
			if (Held((KeyCode)273))
			{
				num3 += num;
			}
			if (Held((KeyCode)274))
			{
				num3 -= num;
			}
			if (num2 != 0f || num3 != 0f)
			{
				Move(num2, num3);
			}
			float num4 = 0f;
			if (Held((KeyCode)280) || Held((KeyCode)61) || Held((KeyCode)270))
			{
				num4 += num * 0.35f;
			}
			if (Held((KeyCode)281) || Held((KeyCode)45) || Held((KeyCode)269))
			{
				num4 -= num * 0.35f;
			}
			if (num4 != 0f && Main.Size != null)
			{
				Main.Size.Value = Mathf.Clamp(Main.Size.Value + num4, 24f, 400f);
			}
			Drag();
		}

		private void Move(float dx, float dy)
		{
			//IL_002b: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (Main.X != null && Main.Y != null)
			{
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(Main.X.Value, Main.Y.Value);
				Vector2 val2 = Keep(new Vector2(val.x + dx, val.y + dy));
				if (val2.x != val.x)
				{
					Main.X.Value = val2.x;
				}
				if (val2.y != val.y)
				{
					Main.Y.Value = val2.y;
				}
			}
		}

		private void Begin()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || GameScreenOpen())
			{
				return;
			}
			if (Building(localPlayer))
			{
				try
				{
					((Character)localPlayer).Message((MessageType)2, "Put your hammer, hoe or cultivator away to move the wheel.", 0, (Sprite)null, false);
					return;
				}
				catch (Exception)
				{
					return;
				}
			}
			try
			{
				localPlayer.SetControls(Vector3.zero, false, false, false, false, false, false, false, false, false, false, false);
			}
			catch (Exception)
			{
			}
			_still = null;
			try
			{
				PlayerController component = ((Component)localPlayer).GetComponent<PlayerController>();
				if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled)
				{
					((Behaviour)component).enabled = false;
					_still = component;
				}
			}
			catch (Exception)
			{
			}
			_moving = true;
			_held = false;
			Main.Saving(on: false);
			Shout();
			if ((Object)(object)_still == (Object)null && Main.Log != null)
			{
				Main.Log.Warn("Daywheel: couldn't pause your controls, so your character may move while you move the wheel.");
			}
		}

		private void End()
		{
			if (!_moving)
			{
				return;
			}
			_moving = false;
			_held = false;
			_picking = false;
			if (_over)
			{
				Hover(on: false);
			}
			try
			{
				if ((Object)(object)_still != (Object)null)
				{
					((Behaviour)_still).enabled = true;
				}
			}
			catch (Exception)
			{
			}
			_still = null;
			Main.Saving(on: true);
			Shout();
			if (Main.Log != null)
			{
				Main.Log.Info("Daywheel: the wheel is now at X " + Num(Main.X) + ", Y " + Num(Main.Y) + ", size " + Num(Main.Size) + ".");
			}
		}

		private void Drag()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_00b3: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			if (Clicked(1))
			{
				Turn(1);
			}
			if (Clicked(0))
			{
				_held = true;
			}
			if (_held && !Down(0))
			{
				_held = false;
			}
			if (_held != _over)
			{
				Hover(_held);
			}
			if (Clicked(2) && !_held)
			{
				PickStart();
			}
			if (_picking && !Down(2))
			{
				PickEnd();
			}
			Vector2 val = Moved();
			if (val.x != 0f || val.y != 0f)
			{
				float num = (((Object)(object)_under == (Object)null) ? 1f : ((Transform)_under).lossyScale.x);
				if (num < 0.01f)
				{
					num = 1f;
				}
				if (_held)
				{
					Move(val.x / num, val.y / num);
				}
				else if (_picking)
				{
					Pick(val / num);
				}
			}
		}

		private static Vector2 Moved()
		{
			//IL_0000: 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_000f: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return ZInput.GetMouseDelta() * 20f;
			}
			catch (Exception)
			{
				return Vector2.zero;
			}
		}

		private static string Num(Setting<float> e)
		{
			if (e != null)
			{
				return e.Value.ToString("0", CultureInfo.InvariantCulture);
			}
			return "?";
		}

		private void Turn(int by)
		{
			if (Main.ThemeName != null)
			{
				int num = Themes.All.Length;
				int num2 = (Themes.IndexOf(_theme) + by + num) % num;
				Main.ThemeName.Value = Themes.All[num2].Name;
				if (Main.Log != null)
				{
					Main.Log.Info("Daywheel: look is now " + Themes.All[num2].Name + ".");
				}
			}
		}

		private void PickStart()
		{
			//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_0023: 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_0056: 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)
			_picking = true;
			_pickFrom = Time.unscaledTime;
			_pickTravel = 0f;
			Color val = DayColour();
			ToHsl(val, out var h, out var s, out _pickL);
			if (s > 0.001f)
			{
				_pickH = h;
				_pickS = s;
			}
			_pickAlpha = val.a;
			_pickFromDefault = val == DayDefault;
		}

		private void Pick(Vector2 by)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			_pickTravel += ((Vector2)(ref by)).magnitude;
			if (!(_pickTravel < 6f))
			{
				bool flag = Held((KeyCode)304) || Held((KeyCode)303);
				if (_pickFromDefault && !flag)
				{
					_pickS = 1f;
				}
				_pickFromDefault = false;
				float num;
				if (!((Object)(object)_fieldRt == (Object)null))
				{
					Rect rect = _fieldRt.rect;
					num = Mathf.Max(40f, ((Rect)(ref rect)).width);
				}
				else
				{
					num = 200f;
				}
				float num2 = num;
				_pickH = Mathf.Repeat(_pickH + by.x * 1f / num2, 1f);
				float num3 = by.y * 0.5f / 40f;
				if (flag)
				{
					_pickS = Mathf.Clamp01(_pickS + num3);
				}
				else
				{
					_pickL = Mathf.Clamp01(_pickL + num3);
				}
				Color value = FromHsl(_pickH, _pickS, _pickL);
				value.a = _pickAlpha;
				if (Main.DayColor != null)
				{
					Main.DayColor.Value = value;
				}
			}
		}

		private void PickEnd()
		{
			//IL_0053: 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)
			_picking = false;
			if (_pickTravel < 6f && Time.unscaledTime - _pickFrom < 0.35f && Main.DayColor != null)
			{
				Main.DayColor.Value = DayDefault;
			}
			if (Main.Log != null)
			{
				Main.Log.Info("Daywheel: the day colour is now " + ColorUtility.ToHtmlStringRGB(DayColour()) + ".");
			}
		}

		private static Color DayColour()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (Main.DayColor != null)
			{
				return Main.DayColor.Value;
			}
			return DayDefault;
		}

		private void Swatch()
		{
			//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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_field == (Object)null || (Object)(object)_fieldRt == (Object)null || (Object)(object)_dotRt == (Object)null)
			{
				return;
			}
			Color val = DayColour();
			float num = _pickH;
			float num2 = _pickS;
			float l = _pickL;
			if (!_picking)
			{
				ToHsl(val, out var h, out var s, out l);
				if (s > 0.001f)
				{
					num = h;
					num2 = s;
				}
			}
			bool flag = (_picking ? _pickFromDefault : (val == DayDefault));
			_field.Strength = (flag ? 1f : num2);
			Rect rect = _fieldRt.rect;
			_dotRt.anchoredPosition = new Vector2(num * ((Rect)(ref rect)).width, l * ((Rect)(ref rect)).height);
			if ((Object)(object)_dotFill != (Object)null)
			{
				((Graphic)_dotFill).color = new Color(val.r, val.g, val.b, 1f);
			}
		}

		internal static Color FromHsl(float h, float s, float l)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			float num = (1f - Mathf.Abs(2f * l - 1f)) * s;
			float num2 = Mathf.Repeat(h, 1f) * 6f;
			float num3 = num * (1f - Mathf.Abs(num2 % 2f - 1f));
			float num4 = 0f;
			float num5 = 0f;
			float num6 = 0f;
			if (num2 < 1f)
			{
				num4 = num;
				num5 = num3;
			}
			else if (num2 < 2f)
			{
				num4 = num3;
				num5 = num;
			}
			else if (num2 < 3f)
			{
				num5 = num;
				num6 = num3;
			}
			else if (num2 < 4f)
			{
				num5 = num3;
				num6 = num;
			}
			else if (num2 < 5f)
			{
				num4 = num3;
				num6 = num;
			}
			else
			{
				num4 = num;
				num6 = num3;
			}
			float num7 = l - num * 0.5f;
			return new Color(num4 + num7, num5 + num7, num6 + num7, 1f);
		}

		private static void ToHsl(Color c, out float h, out float s, out float l)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_00a8: 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)
			float num = Mathf.Max(c.r, Mathf.Max(c.g, c.b));
			float num2 = Mathf.Min(c.r, Mathf.Min(c.g, c.b));
			l = (num + num2) * 0.5f;
			float num3 = num - num2;
			if (num3 < 0.0001f)
			{
				h = 0f;
				s = 0f;
				return;
			}
			s = Mathf.Clamp01(num3 / (1f - Mathf.Abs(2f * l - 1f)));
			if (num == c.r)
			{
				h = (c.g - c.b) / num3;
			}
			else if (num == c.g)
			{
				h = (c.b - c.r) / num3 + 2f;
			}
			else
			{
				h = (c.r - c.g) / num3 + 4f;
			}
			h = Mathf.Repeat(h / 6f, 1f);
		}

		private void Hover(bool on)
		{
			//IL_0034: 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)
			_over = on;
			if ((Object)(object)_markRt != (Object)null)
			{
				((Transform)_markRt).localScale = (Vector3)(on ? new Vector3(1.1f, 1.1f, 1f) : Vector3.one);
			}
		}

		private void Shout()
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_hint == (Object)null) && !((Object)(object)_hintRt == (Object)null))
			{
				((Component)_hintRt).gameObject.SetActive(_moving);
				if (_moving)
				{
					_hint.text = Line("Drag", "hold left mouse and move") + "\n" + Line("Nudge", "arrow keys (Shift for big steps, Ctrl for fine)") + "\n" + Line("Size", "Page Up bigger, Page Down smaller") + "\n" + Line("Look", "right-click or End, Home goes back") + "\n" + Line("Colour", "hold middle and move (Shift for strength)") + "\n" + Line("Default colour", "tap middle") + "\n" + Line("Done", ((object)MoveKey()/*cast due to .constrained prefix*/).ToString());
					Vector2 preferredValues = _hint.GetPreferredValues(_hint.text);
					_hintRt.sizeDelta = new Vector2(preferredValues.x + 20f, preferredValues.y + 6f + 40f + 14f);
				}
			}
		}

		private static string Line(string what, string how)
		{
			return "<color=#E6C27A>" + what + ":</color> " + how;
		}

		private static Color HintBox()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			float num = (Themes.Linear() ? (1f - Mathf.Pow(0.14999998f, 2.2f)) : 0.85f);
			return new Color(0f, 0f, 0f, num);
		}

		private void Aim()
		{
			//IL_0031: 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_0061: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: 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_018d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_hintRt == (Object)null) && !((Object)(object)_root == (Object)null) && !((Object)(object)_under == (Object)null))
			{
				Rect rect = _under.rect;
				if (!ScreenBounds(out var lo, out var hi))
				{
					lo = ((Rect)(ref rect)).min;
					hi = ((Rect)(ref rect)).max;
				}
				Vector2 val = new Vector2(((Rect)(ref rect)).xMax, ((Rect)(ref rect)).yMax) + _root.anchoredPosition;
				Vector2 sizeDelta = _hintRt.sizeDelta;
				float num = val.y - _across - DayRoom() - 6f;
				if (num - sizeDelta.y < lo.y + 8f)
				{
					num = val.y + 6f + sizeDelta.y;
				}
				float num2 = ((val.x - _across * 0.5f > (lo.x + hi.x) * 0.5f) ? val.x : (val.x - _across + sizeDelta.x));
				float num3 = lo.x + 8f + sizeDelta.x;
				float num4 = lo.y + 8f + sizeDelta.y;
				num2 = Mathf.Clamp(num2, num3, Mathf.Max(num3, hi.x - 8f));
				num = Mathf.Clamp(num, num4, Mathf.Max(num4, hi.y - 8f));
				_hintRt.anchoredPosition = new Vector2(num2, num) - val;
			}
		}

		private Vector2 Keep(Vector2 at)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0053: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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)
			if ((Object)(object)_under == (Object)null || !ScreenBounds(out var lo, out var hi))
			{
				return new Vector2(Mathf.Min(0f, at.x), Mathf.Min(0f, at.y));
			}
			Rect rect = _under.rect;
			float num = DaySpill();
			float num2 = lo.x - ((Rect)(ref rect)).xMax + _across + num;
			float num3 = hi.x - ((Rect)(ref rect)).xMax - num;
			float num4 = lo.y - ((Rect)(ref rect)).yMax + _across + DayRoom();
			float num5 = hi.y - ((Rect)(ref rect)).yMax;
			at.x = Mathf.Clamp(at.x, num2, Mathf.Max(num2, num3));
			at.y = Mathf.Clamp(at.y, num4, Mathf.Max(num4, num5));
			return at;
		}

		private float DayRoom()
		{
			if ((Main.ShowDay != null && !Main.ShowDay.Value) || !((Object)(object)_label != (Object)null))
			{
				return 0f;
			}
			return 2f + _label.fontSize * 1.3f;
		}

		private float DaySpill()
		{
			if ((Main.ShowDay != null && !Main.ShowDay.Value) || !((Object)(object)_label != (Object)null))
			{
				return 0f;
			}
			return Mathf.Max(0f, (_dayWidth - _across) * 0.5f);
		}

		private bool ScreenBounds(out Vector2 lo, out Vector2 hi)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			lo = Vector2.zero;
			hi = Vector2.zero;
			if ((Object)(object)_under == (Object)null)
			{
				return false;
			}
			try
			{
				Camera val = (((Object)(object)_canvas == (Object)null || (int)_canvas.renderMode == 0) ? null : _canvas.worldCamera);
				return RectTransformUtility.ScreenPointToLocalPointInRectangle(_under, Vector2.zero, val, ref lo) && RectTransformUtility.ScreenPointToLocalPointInRectangle(_under, new Vector2((float)Screen.width, (float)Screen.height), val, ref hi);
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static bool GameScreenOpen()
		{
			try
			{
				return InventoryGui.IsVisible() || StoreGui.IsVisible() || Menu.IsVisible() || Minimap.IsOpen() || Hud.IsPieceSelectionVisible();
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static bool Building(Player me)
		{
			try
			{
				return (Object)(object)me != (Object)null && ((Character)me).InPlaceMode();
			}
			catch (Exception)
			{
				return false;
			}
		}

		private bool Pressed(KeyCode k)
		{
			//IL_0004: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected I4, but got Unknown
			bool flag = false;
			bool flag2 = false;
			try
			{
				flag = Input.GetKeyDown(k);
			}
			catch (Exception)
			{
			}
			try
			{
				flag2 = ZInput.GetKeyDown(k, false);
			}
			catch (Exception)
			{
			}
			if (flag || flag2)
			{
				return Fresh((int)k);
			}
			return false;
		}

		private static bool Held(KeyCode k)
		{
			//IL_0000: 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)
			try
			{
				if (Input.GetKey(k))
				{
					return true;
				}
			}
			catch (Exception)
			{
			}
			try
			{
				return ZInput.GetKey(k, false);
			}
			catch (Exception)
			{
				return false;
			}
		}

		private bool Clicked(int button)
		{
			bool flag = false;
			try
			{
				flag = ZInput.GetMouseButtonDown(button);
			}
			catch (Exception)
			{
			}
			if (!flag)
			{
				try
				{
					flag = Input.GetMouseButtonDown(button);
				}
				catch (Exception)
				{
				}
			}
			if (flag)
			{
				return Fresh(-1 - button);
			}
			return false;
		}

		private static bool Down(int button)
		{
			try
			{
				if (ZInput.GetMouseButton(button))
				{
					return true;
				}
			}
			catch (Exception)
			{
			}
			try
			{
				return Input.GetMouseButton(button);
			}
			catch (Exception)
			{
				return false;
			}
		}

		private bool Fresh(int key)
		{
			float unscaledTime = Time.unscaledTime;
			if (_lastPress.TryGetValue(key, out var value) && unscaledTime - value < 0.25f)
			{
				return false;
			}
			_lastPress[key] = unscaledTime;
			return true;
		}

		private static KeyCode MoveKey()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (Main.MoveKey == null)
			{
				return (KeyCode)289;
			}
			string value = Main.MoveKey.Value;
			if (Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result))
			{
				return result;
			}
			if (!string.Equals(value, _badKey, StringComparison.Ordinal))
			{
				_badKey = value;
				if (Main.Log != null)
				{
					Main.Log.Warn("Daywheel: MoveKey \"" + value + "\" isn't a key name Unity knows, so F8 moves the wheel.");
				}
			}
			return (KeyCode)289;
		}

		private static void Ride(RectTransform rt, float part, float track)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rt == (Object)null))
			{
				float num = part * MathF.PI * 2f;
				rt.anchoredPosition = new Vector2(Mathf.Sin(num) * track, Mathf.Cos(num) * track);
			}
		}

		private static float Daylight(float now)
		{
			float num = Gap(now, 0.25f);
			if (Mathf.Abs(num) < 0.04f)
			{
				return Mathf.SmoothStep(0f, 1f, 0.5f + num / 0.08f);
			}
			float num2 = Gap(now, 0.75f);
			if (Mathf.Abs(num2) < 0.04f)
			{
				return Mathf.SmoothStep(0f, 1f, 0.5f - num2 / 0.08f);
			}
			if (!(now > 0.25f) || !(now < 0.75f))
			{
				return 0f;
			}
			return 1f;
		}

		private static float Gap(float a, float b)
		{
			float num = a - b;
			if (num > 0.5f)
			{
				num -= 1f;
			}
			if (num < -0.5f)
			{
				num += 1f;
			}
			return num;
		}

		private static bool Hidden()
		{
			try
			{
				return Hud.IsUserHidden() || ((Object)(object)Hud.instance != (Object)null && !Hud.instance.IsVisible());
			}
			catch (Exception)
			{
				return false;
			}
		}

		private bool Build()
		{
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Expected O, but got Unknown
			//IL_0495: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0503: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0522: Unknown result type (might be due to invalid IL or missing references)
			//IL_0529: Unknown result type (might be due to invalid IL or missing references)
			//IL_0534: Unknown result type (might be due to invalid IL or missing references)
			//IL_0549: Unknown result type (might be due to invalid IL or missing references)
			//IL_055d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0567: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fc: Expected O, but got Unknown
			//IL_062d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0647: Unknown result type (might be due to invalid IL or missing references)
			//IL_0661: Unknown result type (might be due to invalid IL or missing references)
			//IL_067b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0695: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_070a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0720: Unknown result type (might be due to invalid IL or missing references)
			MessageHud instance = MessageHud.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_messageText == (Object)null)
			{
				return false;
			}
			GameObject rootObject = Hud.instance.m_rootObject;
			if ((Object)(object)rootObject == (Object)null)
			{
				return false;
			}
			float num = ((Main.Size == null) ? 62f : Main.Size.Value);
			float num2 = ((Main.X == null) ? (-30f) : Main.X.Value);
			float num3 = ((Main.Y == null) ? (-250f) : Main.Y.Value);
			ref RectTransform under = ref _under;
			Transform transform = rootObject.transform;
			under = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)_under == (Object)null)
			{
				return false;
			}
			Canvas componentInParent = ((Component)_under).GetComponentInParent<Canvas>();
			_canvas = (((Object)(object)componentInParent == (Object)null) ? null : componentInParent.rootCanvas);
			_pieces.Clear();
			_theme = null;
			_worn = null;
			_lastDay = -1;
			_held = false;
			_over = false;
			_picking = false;
			GameObject val = new GameObject("Daywheel", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(rootObject.transform, false);
			_root = val.GetComponent<RectTransform>();
			_root.anchorMin = new Vector2(1f, 1f);
			_root.anchorMax = new Vector2(1f, 1f);
			_root.pivot = new Vector2(1f, 1f);
			_root.anchoredPosition = new Vector2(num2, num3);
			_root.sizeDelta = new Vector2(num, num);
			_haloDay = Add("HaloDay", 1f).Item2;
			_haloNight = Add("HaloNight", 1f).Item2;
			Tuple<RectTransform, Image> tuple = Add("Ring", 1f);
			_ringRt = tuple.Item1;
			_ring = tuple.Item2;
			Tuple<RectTransform, Image> tuple2 = Add("Moonglow", 1f);
			_moonGlowRt = tuple2.Item1;
			_moonGlow = tuple2.Item2;
			Tuple<RectTransform, Image> tuple3 = Add("Fire", 1f);
			_fireRt = tuple3.Item1;
			_fire = tuple3.Item2;
			Tuple<RectTransform, Image> tuple4 = Add("SunGlow", 0.47f);
			_sunGlowRt = tuple4.Item1;
			_sunGlow = tuple4.Item2;
			Tuple<RectTransform, Image> tuple5 = Add("Sun", 0.258f);
			_sunRt = tuple5.Item1;
			_sun = tuple5.Item2;
			Tuple<RectTransform, Image> tuple6 = Add("Moon", 0.222f);
			_moonRt = tuple6.Item1;
			_moon = tuple6.Item2;
			Tuple<RectTransform, Image> tuple7 = Add("Now", 1f);
			_markRt = tuple7.Item1;
			_mark = tuple7.Item2;
			GameObject val2 = new GameObject("Day", new Type[1] { typeof(RectTransform) });
			val2.SetActive(false);
			val2.transform.SetParent((Transform)(object)_root, false);
			RectTransform component = val2.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0f);
			component.anchorMax = new Vector2(0.5f, 0f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -2f);
			component.sizeDelta = new Vector2(120f, 20f);
			TextMeshProUGUI val3 = val2.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val3).font = instance.m_messageText.font;
			((TMP_Text)val3).fontSharedMaterial = instance.m_messageText.fontSharedMaterial;
			((TMP_Text)val3).fontSize = Mathf.Max(12f, instance.m_messageText.fontSize * 0.62f);
			((TMP_Text)val3).alignment = (TextAlignmentOptions)258;
			((TMP_Text)val3).textWrappingMode = (TextWrappingModes)0;
			((Graphic)val3).raycastTarget = false;
			((TMP_Text)val3).richText = true;
			val2.SetActive(true);
			_label = (TMP_Text)(object)val3;
			GameObject val4 = new GameObject("Hint", new Type[1] { typeof(RectTransform) });
			val4.SetActive(false);
			val4.transform.SetParent((Transform)(object)_root, false);
			_hintRt = val4.GetComponent<RectTransform>();
			_hintRt.anchorMin = new Vector2(1f, 1f);
			_hintRt.anchorMax = new Vector2(1f, 1f);
			_hintRt.pivot = new Vector2(1f, 1f);
			Image obj = val4.AddComponent<Image>();
			((Graphic)obj).color = HintBox();
			((Graphic)obj).raycastTarget = false;
			GameObject val5 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val5.SetActive(false);
			val5.transform.SetParent(val4.transform, false);
			RectTransform component2 = val5.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = new Vector2(10f, 53f);
			component2.offsetMax = new Vector2(-10f, -7f);
			TextMeshProUGUI val6 = val5.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val6).font = instance.m_messageText.font;
			((TMP_Text)val6).fontSharedMaterial = instance.m_messageText.fontSharedMaterial;
			((TMP_Text)val6).fontSize = 16f;
			((Graphic)val6).color = HintText;
			((TMP_Text)val6).alignment = (TextAlignmentOptions)257;
			((TMP_Text)val6).textWrappingMode = (TextWrappingModes)0;
			((Graphic)val6).raycastTarget = false;
			((TMP_Text)val6).richText = true;
			val5.SetActive(true);
			_hint = (TMP_Text)(object)val6;
			GameObject val7 = new GameObject("Colours", new Type[1] { typeof(RectTransform) });
			val7.transform.SetParent(val4.transform, false);
			_fieldRt = val7.GetComponent<RectTransform>();
			_fieldRt.anchorMin = new Vector2(0f, 0f);
			_fieldRt.anchorMax = new Vector2(1f, 0f);
			_fieldRt.pivot = new Vector2(0.5f, 0f);
			_fieldRt.offsetMin = new Vector2(10f, 7f);
			_fieldRt.offsetMax = new Vector2(-10f, 47f);
			_field = val7.AddComponent<ColourField>();
			((Graphic)_field).raycastTarget = false;
			_dotRt = Square((Transform)(object)_fieldRt, "Marker", 11f, Color.black, out var img);
			_dotRt.anchorMin = Vector2.zero;
			_dotRt.anchorMax = Vector2.zero;
			Square((Transform)(object)Square((Transform)(object)_dotRt, "Ring", 9f, Color.white, out img), "Fill", 5f, DayColour(), out _dotFill);
			Fit(num);
			_shown = true;
			Shout();
			return true;
		}

		private void Fit(float across)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			_across = across;
			if ((Object)(object)_root != (Object)null)
			{
				_root.sizeDelta = new Vector2(across, across);
			}
			for (int i = 0; i < _pieces.Count; i++)
			{
				RectTransform key = _pieces[i].Key;
				if (!((Object)(object)key == (Object)null))
				{
					float num = across * _pieces[i].Value;
					key.sizeDelta = new Vector2(num, num);
				}
			}
			if ((Object)(object)_label != (Object)null)
			{
				float num2 = Mathf.Clamp(across * 0.2f, 9f, 28f);
				if (_label.fontSize != num2)
				{
					_label.fontSize = num2;
					_lastDay = -1;
				}
			}
		}

		private Tuple<RectTransform, Image> Add(string name, float share)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0052: 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)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)_root, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			Image val2 = val.AddComponent<Image>();
			((Graphic)val2).raycastTarget = false;
			_pieces.Add(new KeyValuePair<RectTransform, float>(component, share));
			return new Tuple<RectTransform, Image>(component, val2);
		}

		private static RectTransform Square(Transform parent, string name, float size, Color colour, out Image img)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(size, size);
			img = val.AddComponent<Image>();
			((Graphic)img).color = colour;
			((Graphic)img).raycastTarget = false;
			return component;
		}

		private void Show(bool on)
		{
			if (!((Object)(object)_root == (Object)null) && _shown != on)
			{
				_shown = on;
				((Component)_root).gameObject.SetActive(on);
			}
		}

		private void Clear()
		{
			End();
			if (!((Object)(object)_root == (Object)null))
			{
				try
				{
					Object.Destroy((Object)(object)((Component)_root).gameObject);
				}
				catch (Exception)
				{
				}
				_root = null;
				_ringRt = null;
				_moonGlowRt = null;
				_fireRt = null;
				_sunGlowRt = null;
				_sunRt = null;
				_moonRt = null;
				_markRt = null;
				_haloDay = null;
				_haloNight = null;
				_ring = null;
				_moonGlow = null;
				_fire = null;
				_sunGlow = null;
				_sun = null;
				_moon = null;
				_mark = null;
				_label = null;
				_hint = null;
				_hintRt = null;
				_field = null;
				_fieldRt = null;
				_dotRt = null;
				_dotFill = null;
				_picking = false;
				_theme = null;
				_worn = null;
				_under = null;
				_canvas = null;
				_held = false;
				_over = false;
				_pieces.Clear();
			}
		}
	}
}