Decompiled source of Glitnir Timekeeper v3.0.0

Timekeeper.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Managers;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using ServerSync;
using TMPro;
using Timekeeper.Managers;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyProduct("Timekeeper")]
[assembly: AssemblyCompany("RustyMods")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("Timekeeper")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyConfiguration("")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<8a3d522f-b09c-4347-84a6-0e5db33282f8>Embedded]
	internal sealed class <8a3d522f-b09c-4347-84a6-0e5db33282f8>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<8a3d522f-b09c-4347-84a6-0e5db33282f8>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class <67c466d5-4fad-4396-9408-d64f6873a1f4>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <67c466d5-4fad-4396-9408-d64f6873a1f4>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <67c466d5-4fad-4396-9408-d64f6873a1f4>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	[<8a3d522f-b09c-4347-84a6-0e5db33282f8>Embedded]
	internal sealed class <82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace LocalizationManager
{
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	[PublicAPI]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
		private static BaseUnityPlugin _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out var value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out var value2))
			{
				text = value2.Aggregate(text, [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null)
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] [return: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(1)] (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (object _, EventArgs _) =>
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage());
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			//IL_01a6: Expected O, but got Unknown
			//IL_02a6: Expected O, but got Unknown
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string text = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' })[1];
				if (dictionary.ContainsKey(text))
				{
					Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
				}
				else
				{
					dictionary[text] = item;
				}
			}
			byte[] array = LoadTranslationFromAssembly("English");
			if (array == null)
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json.");
			}
			Dictionary<string, string> dictionary2;
			try
			{
				dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, string>>(Encoding.UTF8.GetString(array));
			}
			catch (JsonException val)
			{
				JsonException val2 = val;
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Invalid JSON in English localization file. " + ((Exception)(object)val2).Message);
			}
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty.");
			}
			string text2 = null;
			if (language != "English")
			{
				if (dictionary.ContainsKey(language))
				{
					text2 = File.ReadAllText(dictionary[language]);
				}
				else
				{
					byte[] array2 = LoadTranslationFromAssembly(language);
					if (array2 != null)
					{
						text2 = Encoding.UTF8.GetString(array2);
					}
				}
			}
			if (text2 == null && dictionary.ContainsKey("English"))
			{
				text2 = File.ReadAllText(dictionary["English"]);
			}
			if (text2 != null)
			{
				Dictionary<string, string> dictionary3;
				try
				{
					dictionary3 = JsonConvert.DeserializeObject<Dictionary<string, string>>(text2);
				}
				catch (JsonException val3)
				{
					JsonException val4 = val3;
					throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Invalid JSON in " + language + " localization file. " + ((Exception)(object)val4).Message);
				}
				foreach (KeyValuePair<string, string> item2 in dictionary3 ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string> { ".json" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		[return: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
		private static byte[] LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		public static byte[] ReadEmbeddedFileBytes([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(1)] string resourceFileName, Assembly containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
}
namespace Timekeeper
{
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	[BepInPlugin("RustyMods.Timekeeper", "Timekeeper", "1.0.0")]
	public class TimekeeperPlugin : BaseUnityPlugin
	{
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		internal const string ModName = "Timekeeper";

		internal const string ModVersion = "1.0.0";

		internal const string Author = "RustyMods";

		private const string ModGUID = "RustyMods.Timekeeper";

		private static readonly string ConfigFileName = "RustyMods.Timekeeper.cfg";

		private static readonly string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("RustyMods.Timekeeper");

		public static readonly ManualLogSource TimekeeperLogger;

		public static readonly ConfigSync ConfigSync;

		public static TimekeeperPlugin instance;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		public void Awake()
		{
			instance = this;
			Timekeeper.Setup();
			TimeMan.Setup();
			Localizer.Load();
			Webhook.Setup();
			CommandManager.Setup();
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				TimekeeperLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				TimekeeperLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				TimekeeperLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		public ConfigEntry<T> config<[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2);
			syncedConfigEntry.SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		public ConfigEntry<T> config<[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		static TimekeeperPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			TimekeeperLogger = Logger.CreateLogSource("Timekeeper");
			ConfigSync = new ConfigSync("RustyMods.Timekeeper")
			{
				DisplayName = "Timekeeper",
				CurrentVersion = "1.0.0",
				MinimumRequiredVersion = "1.0.0"
			};
			instance = null;
			_serverConfigLocked = null;
		}
	}
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	public static class Helpers
	{
		public static void SetText(this GameObject prefab, string childName, string text)
		{
			Transform val = Utils.FindChild(prefab.transform, childName, (IterativeSearchType)0);
			Text val2 = default(Text);
			if (!((Object)(object)val == (Object)null) && ((Component)val).TryGetComponent<Text>(ref val2))
			{
				val2.text = Localization.instance.Localize(text);
			}
		}

		public static void CopySpriteAndMaterial(this GameObject prefab, GameObject source, string childName, string sourceChildName = "")
		{
			Image component = ((Component)prefab.transform.Find(childName)).GetComponent<Image>();
			Image component2 = ((Component)source.transform.Find(Utility.IsNullOrWhiteSpace(sourceChildName) ? childName : sourceChildName)).GetComponent<Image>();
			component.sprite = component2.sprite;
			((Graphic)component).material = ((Graphic)component2).material;
		}

		public static void CopyButtonState(this GameObject prefab, GameObject source, string childName, string sourceChildName = "")
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			((Selectable)((Component)prefab.transform.Find(childName)).GetComponent<Button>()).spriteState = ((Selectable)((Component)source.transform.Find(Utility.IsNullOrWhiteSpace(sourceChildName) ? childName : sourceChildName)).GetComponent<Button>()).spriteState;
		}
	}
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	public class Timekeeper : MonoBehaviour
	{
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		private enum PanelType
		{
			Opaque,
			Transparent
		}

		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		[HarmonyPatch(typeof(Menu), "Start")]
		private static class Menu_Start_Patch
		{
			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			private static void Postfix(Menu __instance)
			{
				//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cd: Expected O, but got Unknown
				Sprite sprite = ((Component)((Component)((Component)__instance).transform.parent.Find("Inventory_screen")).GetComponent<InventoryGui>().m_trophieElementPrefab.transform.Find("icon_bkg")).GetComponent<Image>().sprite;
				GameObject val = Object.Instantiate<GameObject>(((Component)((Transform)__instance.menuEntriesParent).Find("Settings")).gameObject, (Transform)(object)__instance.menuEntriesParent);
				((Object)val).name = "Timekeeper";
				val.transform.SetAsFirstSibling();
				TMP_Text MenuLabel = val.GetComponentInChildren<TMP_Text>();
				MenuLabel.text = Localization.instance.Localize("$label_timekeeper");
				((UnityEventBase)val.GetComponent<Button>().onClick).RemoveAllListeners();
				((UnityEvent)val.GetComponent<Button>().onClick).AddListener(new UnityAction(OnOpen));
				GameObject sfxPrefab = __instance.m_settingsPrefab.GetComponentInChildren<ButtonSfx>().m_sfxPrefab;
				ButtonSfx[] componentsInChildren = m_root.GetComponentsInChildren<ButtonSfx>(true);
				foreach (ButtonSfx val2 in componentsInChildren)
				{
					val2.m_sfxPrefab = sfxPrefab;
				}
				m_item.GetComponent<ButtonSfx>().m_sfxPrefab = sfxPrefab;
				((Component)m_item.transform.Find("Background")).GetComponent<Image>().sprite = sprite;
				((Component)m_star.transform.Find("Day")).gameObject.SetActive(false);
				m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel");
				m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/TabContent");
				m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/HeaderLine");
				m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/Back");
				m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/Collect", "Panel/Ok");
				m_root.CopyButtonState(__instance.m_settingsPrefab, "Panel/Back");
				m_root.CopyButtonState(__instance.m_settingsPrefab, "Panel/Collect", "Panel/Ok");
				FontManager.SetFont(m_root.GetComponentsInChildren<Text>(true));
				FontManager.SetFont(m_item.GetComponentsInChildren<Text>(true));
				FontManager.SetFont(m_star.GetComponentsInChildren<Text>(true));
				m_root.AddComponent<Timekeeper>();
				Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, (Action)delegate
				{
					MenuLabel.text = Localization.instance.Localize("$label_timekeeper");
				});
			}
		}

		private static GameObject m_root;

		private static GameObject m_item;

		private static GameObject m_star;

		private static ConfigEntry<float> m_scale;

		private static ConfigEntry<PanelType> m_panelBackground;

		private static ConfigEntry<TimekeeperPlugin.Toggle> m_sendOnCollect;

		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
		private static Timekeeper instance;

		public Image m_panel = null;

		public Image m_darken = null;

		public Text m_title = null;

		public Text m_description = null;

		public Text m_timeLabel = null;

		public Text m_time = null;

		public GameObject m_tooltipParent = null;

		public VerticalLayoutGroup m_tooltipContent = null;

		public RectTransform m_tooltipRect = null;

		public Text m_tooltip = null;

		public RectTransform m_rewardListRoot = null;

		public Image m_lineFill = null;

		public RectTransform m_starListRoot = null;

		public Button m_collectButton = null;

		public Text m_collectButtonLabel = null;

		public Text m_backButtonLabel = null;

		private int m_selectedReward = -1;

		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
		private GameObject m_selectedRewardObject;

		private readonly Dictionary<int, float> m_fillLevels = new Dictionary<int, float>
		{
			[0] = 0f,
			[1] = 0.1f,
			[2] = 0.23f,
			[3] = 0.35f,
			[4] = 0.48f,
			[5] = 0.6f,
			[6] = 0.73f,
			[7] = 0.85f,
			[8] = 1f
		};

		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
		[method: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
		[field: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
		private event Action<string> OnCollect;

		public static void Setup()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			m_root = AssetManager.GetAssetBundle("timekeeperbundle").LoadAsset<GameObject>("Timekeeper_UI");
			m_item = AssetManager.GetAssetBundle("timekeeperbundle").LoadAsset<GameObject>("Timekeeper_Item");
			m_star = AssetManager.GetAssetBundle("timekeeperbundle").LoadAsset<GameObject>("Timekeeper_Star");
			m_scale = TimekeeperPlugin.instance.config("Settings", "Panel Scale", 1f, new ConfigDescription("Set scale of panel", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>()));
			m_panelBackground = TimekeeperPlugin.instance.config("Settings", "Background", PanelType.Opaque, "Set background panel");
			m_panelBackground.SettingChanged += [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (object _, EventArgs _) =>
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: 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)
				if (!((Object)(object)instance == (Object)null))
				{
					((Graphic)instance.m_panel).color = ((m_panelBackground.Value == PanelType.Opaque) ? Color.white : Color.clear);
					((Graphic)instance.m_darken).color = (Color)((m_panelBackground.Value == PanelType.Opaque) ? Color.clear : new Color(0f, 0f, 0f, 0.5f));
				}
			};
			RectTransform rect = m_root.GetComponent<RectTransform>();
			((Transform)rect).localScale = Vector3.one * m_scale.Value;
			m_scale.SettingChanged += [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (object _, EventArgs _) =>
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				((Transform)rect).localScale = Vector3.one * m_scale.Value;
				if ((Object)(object)instance != (Object)null)
				{
					((Transform)((Component)instance).GetComponent<RectTransform>()).localScale = Vector3.one * m_scale.Value;
				}
			};
			m_sendOnCollect = TimekeeperPlugin.instance.config("Discord", "On Collect", TimekeeperPlugin.Toggle.On, "If on, plugin will send message when player collects reward");
		}

		private static void OnOpen()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)Settings.instance))
			{
				Settings.instance.OnBack();
			}
			Object.Instantiate<GameObject>(m_root, ((Component)Menu.instance).transform);
			Menu.instance.m_closeMenuState = (CloseMenuState)0;
		}

		public void Awake()
		{
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Expected O, but got Unknown
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)instance != (Object)null)
			{
				Object.Destroy((Object)(object)instance);
			}
			instance = this;
			m_panel = ((Component)((Component)this).transform.Find("Panel")).GetComponent<Image>();
			m_darken = ((Component)((Component)this).transform.Find("Panel/darken")).GetComponent<Image>();
			m_title = ((Component)((Component)this).transform.Find("Panel/Title")).GetComponent<Text>();
			m_description = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Text")).GetComponent<Text>();
			m_timeLabel = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/TimeLabel")).GetComponent<Text>();
			m_time = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Time")).GetComponent<Text>();
			m_tooltipParent = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Tooltip")).gameObject;
			m_tooltipContent = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Tooltip/Viewport/Content")).GetComponent<VerticalLayoutGroup>();
			m_tooltip = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Tooltip/Viewport/Content/Text")).GetComponent<Text>();
			m_tooltipRect = ((Component)m_tooltip).GetComponent<RectTransform>();
			m_rewardListRoot = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/RewardList/Viewport/Content")).GetComponent<RectTransform>();
			m_lineFill = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Timeline/LineFill")).GetComponent<Image>();
			m_starListRoot = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Timeline/StarGroup")).GetComponent<RectTransform>();
			m_collectButton = ((Component)((Component)this).transform.Find("Panel/Collect")).GetComponent<Button>();
			((Selectable)m_collectButton).interactable = false;
			m_collectButtonLabel = ((Component)((Component)m_collectButton).transform.Find("Label")).GetComponent<Text>();
			m_backButtonLabel = ((Component)((Component)this).transform.Find("Panel/Back/Label")).GetComponent<Text>();
			Button component = ((Component)((Component)this).transform.Find("Panel/Back")).GetComponent<Button>();
			((UnityEvent)component.onClick).AddListener(new UnityAction(OnBack));
			Button component2 = ((Component)((Component)this).transform.Find("Panel/Collect")).GetComponent<Button>();
			((UnityEvent)component2.onClick).AddListener(new UnityAction(Collect));
			((Graphic)m_panel).color = ((m_panelBackground.Value == PanelType.Opaque) ? Color.white : Color.clear);
			((Graphic)m_darken).color = (Color)((m_panelBackground.Value == PanelType.Opaque) ? Color.clear : new Color(0f, 0f, 0f, 0.5f));
			m_title.text = Localization.instance.Localize("Glitnir $label_timekeeper");
			m_collectButtonLabel.text = Localization.instance.Localize("$label_collect");
			m_backButtonLabel.text = Localization.instance.Localize("$label_back");
			OnCollect += Webhook.SendNotice;
		}

		public void Start()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			LoadStars();
			LoadRewardItems();
			SetDescription();
			m_timeLabel.text = Localization.instance.Localize("$msg_active_for: ");
			m_tooltipParent.SetActive(false);
			m_tooltip.text = "";
			int day = TimeMan.GetDay();
			string text = day + ((day > 1) ? " $msg_days" : " $msg_day") + " " + TimeMan.GetTimeDisplay();
			m_time.text = Localization.instance.Localize(text);
			((Graphic)m_time).color = new Color(1f, 0.5f, 0f, 1f);
		}

		public void OnDestroy()
		{
			instance = null;
		}

		public void Update()
		{
			if (ZInput.GetKeyDown((KeyCode)27, true))
			{
				OnBack();
			}
		}

		public void SetDescription()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("$msg_welcome_back " + Player.m_localPlayer.GetPlayerName() + "!\n");
			stringBuilder.Append($"$msg_next_reward {TimeMan.GetNextRewardDay()}\n");
			m_description.text = Localization.instance.Localize(stringBuilder.ToString());
		}

		public void LoadStars()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			if (((Transform)m_starListRoot).childCount > 0)
			{
				foreach (Transform item in (Transform)m_starListRoot)
				{
					Transform val = item;
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			int day = TimeMan.GetDay();
			List<KeyValuePair<int, TimeMan.Reward>> list = (from r in TimeMan.GetRewards()
				orderby r.Key
				select r).ToList();
			int num = ((day > 0) ? GetCurrentChunkIndex(list, day) : 0);
			int num2 = num * 8;
			int num3 = Math.Min(num2 + 8, list.Count);
			int num4 = num3 - num2;
			KeyValuePair<int, TimeMan.Reward>[] array = new KeyValuePair<int, TimeMan.Reward>[num4];
			for (int i = 0; i < num4; i++)
			{
				array[i] = list[num2 + i];
			}
			if (num4 > 0)
			{
				float num5 = CalculateFillAmount(array, day, num4);
				if (Math.Abs(num5 - 1f) < 0.01f)
				{
					num++;
					num2 = num * 8;
					num3 = Math.Min(num2 + 8, list.Count);
					num4 = num3 - num2;
					if (num4 > 0)
					{
						if (array.Length != num4)
						{
							array = new KeyValuePair<int, TimeMan.Reward>[num4];
						}
						for (int j = 0; j < num4; j++)
						{
							array[j] = list[num2 + j];
						}
						num5 = CalculateFillAmount(array, day, num4);
					}
				}
				CreateStarsForRewards(array, num4, day);
				m_lineFill.fillAmount = num5;
			}
			else
			{
				m_lineFill.fillAmount = 0f;
			}
			CreatePlaceholderStars(8 - num4);
		}

		private void CreateStarsForRewards([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 0, 1 })] KeyValuePair<int, TimeMan.Reward>[] rewards, int count, int playerDay)
		{
			for (int i = 0; i < count; i++)
			{
				KeyValuePair<int, TimeMan.Reward> keyValuePair = rewards[i];
				GameObject val = Object.Instantiate<GameObject>(m_star, (Transform)(object)m_starListRoot);
				Text component = ((Component)val.transform.Find("Label")).GetComponent<Text>();
				GameObject gameObject = ((Component)val.transform.Find("Star/Star_Lit")).gameObject;
				component.text = keyValuePair.Key.ToString();
				if (playerDay >= keyValuePair.Key)
				{
					gameObject.SetActive(true);
				}
			}
		}

		private void CreatePlaceholderStars(int count)
		{
			for (int i = 0; i < count; i++)
			{
				GameObject val = Object.Instantiate<GameObject>(m_star, (Transform)(object)m_starListRoot);
				Text component = ((Component)val.transform.Find("Label")).GetComponent<Text>();
				GameObject gameObject = ((Component)val.transform.Find("Star/Star_Lit")).gameObject;
				component.text = "?";
				gameObject.SetActive(false);
			}
		}

		private static int GetCurrentChunkIndex([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 0, 1 })] List<KeyValuePair<int, TimeMan.Reward>> rewards, int playerDay)
		{
			int count = rewards.Count;
			int num = (count + 8 - 1) / 8;
			for (int i = 0; i < num; i++)
			{
				int num2 = i * 8;
				int num3 = Math.Min(num2 + 8, count);
				if (num2 >= count)
				{
					break;
				}
				int key = rewards[num3 - 1].Key;
				if (playerDay <= key)
				{
					return i;
				}
			}
			return Math.Max(0, (count - 1) / 8);
		}

		private float CalculateFillAmount([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 0, 1 })] KeyValuePair<int, TimeMan.Reward>[] chunkRewards, int playerDay, int count)
		{
			if (count == 0)
			{
				return 0f;
			}
			for (int i = 0; i < count; i++)
			{
				int key = chunkRewards[i].Key;
				if (playerDay > key)
				{
					continue;
				}
				if (playerDay == key)
				{
					return m_fillLevels[i + 1];
				}
				if (i == 0)
				{
					if (playerDay >= key)
					{
						return m_fillLevels[1];
					}
					float num = (float)(playerDay - 1) / (float)(key - 1);
					return Mathf.Lerp(m_fillLevels[0], m_fillLevels[1], num);
				}
				int key2 = chunkRewards[i - 1].Key;
				float num2 = (float)(playerDay - key2) / (float)(key - key2);
				return Mathf.Lerp(m_fillLevels[i], m_fillLevels[i + 1], num2);
			}
			return m_fillLevels[Math.Min(count, 8)];
		}

		public void LoadRewardItems()
		{
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Expected O, but got Unknown
			ItemDrop val = default(ItemDrop);
			foreach (KeyValuePair<int, TimeMan.Reward> item2 in from kv in TimeMan.GetRewards()
				orderby kv.Key
				select kv)
			{
				int day = item2.Key;
				if (TimeMan.IsRewardCollected(day))
				{
					continue;
				}
				TimeMan.Reward value = item2.Value;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(value.ItemPrefab);
				if (itemPrefab != null && itemPrefab.TryGetComponent<ItemDrop>(ref val))
				{
					bool canInteract = TimeMan.CanCollectReward(day) && !TimeMan.IsRewardCollected(day);
					GameObject item = Object.Instantiate<GameObject>(m_item, (Transform)(object)m_rewardListRoot);
					Button component = item.GetComponent<Button>();
					Text component2 = ((Component)item.transform.Find("Label")).GetComponent<Text>();
					Image component3 = ((Component)item.transform.Find("Background/Icon")).GetComponent<Image>();
					ItemData data = val.m_itemData.Clone();
					data.m_stack = value.Amount;
					data.m_quality = value.Quality;
					data.m_variant = value.Variant;
					component2.text = Localization.instance.Localize("$msg_day " + day);
					component3.sprite = val.m_itemData.GetIcon();
					((Graphic)component3).color = (canInteract ? Color.white : Color.black);
					((UnityEvent)component.onClick).AddListener((UnityAction)delegate
					{
						SetTooltip(data);
						m_selectedReward = day;
						((Selectable)m_collectButton).interactable = canInteract;
						m_selectedRewardObject = item;
					});
				}
			}
		}

		public void OnBack()
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
			if (Object.op_Implicit((Object)(object)Settings.instance))
			{
				Settings.instance.OnBack();
			}
		}

		public void Collect()
		{
			if (TimeMan.IsRewardCollected(m_selectedReward) || !TimeMan.GetRewards().TryGetValue(m_selectedReward, out var value))
			{
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(value.ItemPrefab);
			ItemDrop val = default(ItemDrop);
			if (itemPrefab == null || !itemPrefab.TryGetComponent<ItemDrop>(ref val))
			{
				return;
			}
			ItemData val2 = val.m_itemData.Clone();
			val2.m_dropPrefab = itemPrefab;
			val2.m_stack = value.Amount;
			val2.m_quality = value.Quality;
			val2.m_variant = value.Variant;
			if (!((Humanoid)Player.m_localPlayer).GetInventory().CanAddItem(val2, -1))
			{
				((Character)Player.m_localPlayer).Message((MessageType)1, "$inventory_full", 0, (Sprite)null);
				return;
			}
			((Humanoid)Player.m_localPlayer).GetInventory().AddItem(val2);
			if (m_sendOnCollect.Value == TimekeeperPlugin.Toggle.On)
			{
				this.OnCollect?.Invoke($"{Player.m_localPlayer.GetPlayerName()} $msg_has_collected {m_selectedReward}");
			}
			TimeMan.SetRewardCollected(m_selectedReward);
			m_tooltipParent.SetActive(false);
			m_selectedReward = -1;
			m_tooltip.text = "";
			((Selectable)m_collectButton).interactable = false;
			if ((Object)(object)m_selectedRewardObject != (Object)null)
			{
				Object.Destroy((Object)(object)m_selectedRewardObject);
			}
			((Character)Player.m_localPlayer).Message((MessageType)1, "$msg_added " + val2.m_shared.m_name, val2.m_stack, val2.GetIcon());
		}

		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		public void SetTooltip(ItemData item)
		{
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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)
			if (item == null)
			{
				m_tooltip.text = "";
			}
			else
			{
				m_tooltipParent.SetActive(true);
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("<color=yellow>" + item.m_shared.m_name + "</color>" + ((item.m_stack > 1) ? $" x{item.m_stack}" : "") + "\n\n");
				stringBuilder.Append(item.GetTooltip(-1) + "\n\n");
				m_tooltip.text = Localization.instance.Localize(stringBuilder.ToString());
			}
			Canvas.ForceUpdateCanvases();
			float textPreferredHeight = GetTextPreferredHeight(m_tooltip, m_tooltipRect);
			textPreferredHeight += (float)(((LayoutGroup)m_tooltipContent).padding.top + ((LayoutGroup)m_tooltipContent).padding.bottom);
			float num = 260f;
			float num2 = Mathf.Max(textPreferredHeight, num);
			float x = m_tooltipRect.sizeDelta.x;
			Vector2 sizeDelta = m_tooltipRect.sizeDelta;
			((Vector2)(ref sizeDelta)).Set(x, num2);
		}

		private static float GetTextPreferredHeight(Text text, RectTransform rect)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(text.text))
			{
				return 0f;
			}
			TextGenerator cachedTextGenerator = text.cachedTextGenerator;
			Rect rect2 = rect.rect;
			TextGenerationSettings generationSettings = text.GetGenerationSettings(((Rect)(ref rect2)).size);
			return cachedTextGenerator.GetPreferredHeight(text.text, generationSettings);
		}
	}
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	public static class TimeMan
	{
		[HarmonyPatch(typeof(Player), "SetControls")]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		private static class Player_SetControls_Patch
		{
			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			private static void Postfix(Player __instance, Vector3 movedir, bool attack, bool attackHold, bool secondaryAttack, bool secondaryAttackHold, bool block, bool blockHold, bool jump, bool crouch, bool run, bool autoRun, bool dodge)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					if (attack || attackHold || secondaryAttack || secondaryAttackHold || block || blockHold || jump || crouch || run || dodge || movedir != Vector3.zero)
					{
						m_active = true;
						m_timeSinceLastInput = Time.fixedDeltaTime;
					}
					else if (Time.fixedDeltaTime > m_timeSinceLastInput + m_afkDuration.Value)
					{
						m_active = false;
					}
					if (m_active)
					{
						m_activeTimer = Mathf.Max(0f, m_activeTimer);
						m_activeTimer += Mathf.Max(0f, Time.fixedDeltaTime);
						SendDayNotice();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		private static class Player_Load_Patch
		{
			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			private static void Postfix(Player __instance)
			{
				Load(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "Save")]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		private static class Player_Save_Patch
		{
			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			private static void Prefix(Player __instance)
			{
				Save(__instance);
			}
		}

		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		[HarmonyPatch(typeof(ZNet), "Awake")]
		private static class ZNet_Awake_Patch
		{
			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			private static void Postfix(ZNet __instance)
			{
				if (__instance.IsServer())
				{
					UpdateServerRewards();
				}
			}
		}

		[Serializable]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		public class Reward
		{
			public string ItemPrefab;

			public int Amount;

			public int Quality;

			public int Variant;

			public Reward(string item, int amount = 1, int quality = 1, int variant = 0)
			{
				ItemPrefab = item;
				Amount = amount;
				Quality = quality;
				Variant = variant;
			}
		}

		private const string RootFolderName = "Timekeeper";

		private const string FileName = "Rewards.json";

		private static readonly string RootFolderPath;

		private static readonly string FilePath;

		private static readonly CustomSyncedValue<string> ServerRewards;

		private static Dictionary<int, Reward> m_rewards;

		private static List<int> m_collectedRewards;

		private static bool m_active;

		private static float m_timeSinceLastInput;

		public static float m_activeTimer;

		private static int m_lastDay;

		private static ConfigEntry<float> m_afkDuration;

		private static ConfigEntry<TimekeeperPlugin.Toggle> m_sendDay;

		private static void SendDayNotice()
		{
			if (m_sendDay.Value != 0)
			{
				int day = GetDay();
				if (day != m_lastDay)
				{
					m_lastDay = day;
					Webhook.instance.SendNotification($"{Player.m_localPlayer.GetPlayerName()} $msg_has_been_active {day} $msg_days");
				}
			}
		}

		private static void UpdateServerRewards()
		{
			string value = JsonConvert.SerializeObject((object)m_rewards);
			ServerRewards.Value = value;
		}

		public static Dictionary<int, Reward> GetRewards()
		{
			return m_rewards;
		}

		public static int GetDay()
		{
			if (m_activeTimer < 0f)
			{
				TimekeeperPlugin.TimekeeperLogger.LogWarning((object)$"Active timer is negative: {m_activeTimer}, resetting to 0");
				m_activeTimer = 0f;
			}
			return Mathf.FloorToInt(m_activeTimer / 1800f);
		}

		private static float GetTimeOfDay()
		{
			return m_activeTimer % 1800f;
		}

		public static string GetTimeDisplay()
		{
			float timeOfDay = GetTimeOfDay();
			float num = 1800f;
			float num2 = num / 24f;
			float num3 = num2 / 60f;
			int num4 = Mathf.FloorToInt(timeOfDay / num2);
			int num5 = Mathf.FloorToInt(timeOfDay % num2 / num3);
			return $"{num4}:{num5:D2}";
		}

		public static void Clear(Player player)
		{
			player.m_customData.Remove("TimekeeperCollected");
			player.m_customData.Remove("TimekeeperTime");
			m_activeTimer = 0f;
			m_collectedRewards.Clear();
		}

		private static void Save(Player player)
		{
			player.m_customData["TimekeeperCollected"] = JsonConvert.SerializeObject((object)m_collectedRewards);
			player.m_customData["TimekeeperTime"] = m_activeTimer.ToString(CultureInfo.CurrentCulture);
		}

		private static void Load(Player player)
		{
			m_activeTimer = 0f;
			if (player.m_customData.TryGetValue("TimekeeperCollected", out var value))
			{
				try
				{
					List<int> list = JsonConvert.DeserializeObject<List<int>>(value);
					if (list != null)
					{
						m_collectedRewards = list;
					}
				}
				catch
				{
					TimekeeperPlugin.TimekeeperLogger.LogWarning((object)"Failed to parse collected timekeeper keys");
					player.m_customData.Remove("TimekeeperCollected");
				}
			}
			if (player.m_customData.TryGetValue("TimekeeperTime", out var value2) && float.TryParse(value2, out var result))
			{
				m_activeTimer = Mathf.Max(0f, result);
				m_lastDay = GetDay();
			}
		}

		public static bool IsRewardCollected(int key)
		{
			return m_collectedRewards.Contains(key);
		}

		public static void SetRewardCollected(int key)
		{
			m_collectedRewards.Add(key);
		}

		public static int GetNextRewardDay()
		{
			foreach (KeyValuePair<int, Reward> item in m_rewards.OrderBy([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (KeyValuePair<int, Reward> kvp) => kvp.Key))
			{
				if (item.Key <= GetDay())
				{
					continue;
				}
				return item.Key;
			}
			return -1;
		}

		public static bool CanCollectReward(int key)
		{
			return key <= GetDay();
		}

		public static void Setup()
		{
			m_afkDuration = TimekeeperPlugin.instance.config("Settings", "AFK Duration", 10f, "Set seconds until no input triggers AFK status");
			m_sendDay = TimekeeperPlugin.instance.config("Discord", "On New Day", TimekeeperPlugin.Toggle.Off, "If on, will send message when player reaches a new day");
			ServerRewards.ValueChanged += delegate
			{
				if ((!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer()) && !Utility.IsNullOrWhiteSpace(ServerRewards.Value))
				{
					Dictionary<int, Reward> dictionary3 = JsonConvert.DeserializeObject<Dictionary<int, Reward>>(ServerRewards.Value);
					if (dictionary3 != null)
					{
						m_rewards = dictionary3;
					}
				}
			};
			LoadDefaults();
			if (!Directory.Exists(RootFolderPath))
			{
				Directory.CreateDirectory(RootFolderPath);
			}
			if (!File.Exists(FilePath))
			{
				UpdateRewardFile();
			}
			else
			{
				try
				{
					Dictionary<int, Reward> dictionary = JsonConvert.DeserializeObject<Dictionary<int, Reward>>(File.ReadAllText(FilePath));
					if (dictionary != null)
					{
						m_rewards = dictionary;
					}
				}
				catch
				{
					TimekeeperPlugin.TimekeeperLogger.LogWarning((object)"Failed to parse file: Rewards.json");
				}
			}
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(RootFolderPath, "Rewards.json");
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
			fileSystemWatcher.Changed += OnFileChange;
			fileSystemWatcher.Created += OnFileChange;
			static void OnFileChange(object sender, FileSystemEventArgs args)
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsServer())
				{
					return;
				}
				TimekeeperPlugin.TimekeeperLogger.LogDebug((object)"Timekeeper config changed, reloading rewards");
				try
				{
					Dictionary<int, Reward> dictionary2 = JsonConvert.DeserializeObject<Dictionary<int, Reward>>(File.ReadAllText(FilePath));
					if (dictionary2 != null)
					{
						m_rewards = dictionary2;
					}
					UpdateServerRewards();
				}
				catch
				{
					TimekeeperPlugin.TimekeeperLogger.LogWarning((object)"Failed to parse file: Rewards.json");
				}
			}
		}

		private static void LoadDefaults()
		{
			m_rewards[1] = new Reward("Coins");
			m_rewards[2] = new Reward("Coins");
			m_rewards[4] = new Reward("Coins");
			m_rewards[6] = new Reward("Coins");
			m_rewards[8] = new Reward("Coins");
			m_rewards[10] = new Reward("Coins");
			m_rewards[12] = new Reward("Coins");
			m_rewards[14] = new Reward("Coins");
			m_rewards[16] = new Reward("Coins");
			m_rewards[18] = new Reward("Coins");
			m_rewards[21] = new Reward("Coins");
			m_rewards[24] = new Reward("Coins");
			m_rewards[27] = new Reward("Coins");
			m_rewards[30] = new Reward("Coins");
			m_rewards[33] = new Reward("Coins");
			m_rewards[36] = new Reward("Coins");
			m_rewards[39] = new Reward("Coins");
			m_rewards[42] = new Reward("Coins");
			m_rewards[45] = new Reward("Coins");
			m_rewards[48] = new Reward("Coins");
			m_rewards[51] = new Reward("Coins");
			m_rewards[54] = new Reward("Coins");
			m_rewards[57] = new Reward("Coins");
			m_rewards[60] = new Reward("Coins");
			m_rewards[63] = new Reward("Coins");
			m_rewards[66] = new Reward("Coins");
			m_rewards[69] = new Reward("Coins");
			m_rewards[72] = new Reward("Coins");
			m_rewards[75] = new Reward("Coins");
			m_rewards[78] = new Reward("Coins");
			m_rewards[81] = new Reward("Coins");
			m_rewards[84] = new Reward("Coins");
			m_rewards[87] = new Reward("Coins");
			m_rewards[90] = new Reward("Coins");
			m_rewards[94] = new Reward("Coins");
			m_rewards[98] = new Reward("Coins");
			m_rewards[102] = new Reward("Coins");
			m_rewards[106] = new Reward("Coins");
			m_rewards[110] = new Reward("Coins");
			m_rewards[114] = new Reward("Coins");
			m_rewards[118] = new Reward("Coins");
			m_rewards[122] = new Reward("Coins");
			m_rewards[126] = new Reward("Coins");
			m_rewards[130] = new Reward("Coins");
			m_rewards[134] = new Reward("Coins");
			m_rewards[138] = new Reward("Coins");
			m_rewards[142] = new Reward("Coins");
			m_rewards[146] = new Reward("Coins");
			m_rewards[150] = new Reward("Coins");
			m_rewards[154] = new Reward("Coins");
			m_rewards[158] = new Reward("Coins");
			m_rewards[162] = new Reward("Coins");
			m_rewards[166] = new Reward("Coins");
			m_rewards[170] = new Reward("Coins");
			m_rewards[174] = new Reward("Coins");
			m_rewards[178] = new Reward("Coins");
			m_rewards[182] = new Reward("Coins");
			m_rewards[187] = new Reward("Coins");
			m_rewards[192] = new Reward("Coins");
			m_rewards[197] = new Reward("Coins");
			m_rewards[202] = new Reward("Coins");
			m_rewards[207] = new Reward("Coins");
			m_rewards[212] = new Reward("Coins");
			m_rewards[217] = new Reward("Coins");
			m_rewards[222] = new Reward("Coins");
			m_rewards[227] = new Reward("Coins");
			m_rewards[232] = new Reward("Coins");
			m_rewards[237] = new Reward("Coins");
			m_rewards[242] = new Reward("Coins");
			m_rewards[247] = new Reward("Coins");
			m_rewards[252] = new Reward("Coins");
			m_rewards[257] = new Reward("Coins");
			m_rewards[262] = new Reward("Coins");
			m_rewards[267] = new Reward("Coins");
			m_rewards[272] = new Reward("Coins");
			m_rewards[277] = new Reward("Coins");
			m_rewards[282] = new Reward("Coins");
			m_rewards[287] = new Reward("Coins");
			m_rewards[292] = new Reward("Coins");
			m_rewards[297] = new Reward("Coins");
			m_rewards[302] = new Reward("Coins");
			m_rewards[307] = new Reward("Coins");
			m_rewards[312] = new Reward("Coins");
			m_rewards[317] = new Reward("Coins");
			m_rewards[322] = new Reward("Coins");
			m_rewards[326] = new Reward("Coins");
			m_rewards[330] = new Reward("Coins");
			m_rewards[334] = new Reward("Coins");
			m_rewards[338] = new Reward("Coins");
			m_rewards[341] = new Reward("Coins");
			m_rewards[344] = new Reward("Coins");
			m_rewards[347] = new Reward("Coins");
			m_rewards[350] = new Reward("Coins");
			m_rewards[353] = new Reward("Coins");
			m_rewards[356] = new Reward("Coins");
			m_rewards[358] = new Reward("Coins");
			m_rewards[360] = new Reward("Coins");
			m_rewards[362] = new Reward("Coins");
			m_rewards[364] = new Reward("Coins");
			m_rewards[365] = new Reward("Coins");
		}

		public static void AddReward(int day, Reward reward)
		{
			m_rewards[day] = reward;
		}

		public static void UpdateRewardFile()
		{
			string contents = JsonConvert.SerializeObject((object)m_rewards, (Formatting)1);
			File.WriteAllText(FilePath, contents);
		}

		static TimeMan()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			RootFolderPath = configPath + directorySeparatorChar + "Timekeeper";
			string rootFolderPath = RootFolderPath;
			directorySeparatorChar = Path.DirectorySeparatorChar;
			FilePath = rootFolderPath + directorySeparatorChar + "Rewards.json";
			ServerRewards = new CustomSyncedValue<string>(TimekeeperPlugin.ConfigSync, "ServerTimekeeperRewards", "");
			m_rewards = new Dictionary<int, Reward>();
			m_collectedRewards = new List<int>();
			m_activeTimer = 0f;
			m_lastDay = -1;
			m_afkDuration = null;
			m_sendDay = null;
		}
	}
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	public class Webhook : MonoBehaviour
	{
		[Serializable]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		public class DiscordWebhookData
		{
			public string content;

			public bool tts;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
			public Embed[] embeds;

			public string username;

			public string avatar_url;

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public DiscordWebhookData(string content)
			{
				this.content = Localization.instance.Localize(content);
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public DiscordWebhookData(params Embed[] embeds)
			{
				this.embeds = embeds;
			}
		}

		[Serializable]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		public class Embed
		{
			public string title;

			public string description;

			public string url;

			public string timestamp;

			public int? color;

			public Footer footer;

			public EmbedImage image;

			public EmbedImage thumbnail;

			public EmbedVideo video;

			public EmbedProvider provider;

			public EmbedAuthor author;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
			public EmbedField[] fields;

			public Embed()
			{
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public Embed(string title, string description)
			{
				this.title = Localization.instance.Localize(title);
				this.description = Localization.instance.Localize(description);
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public Embed(string title, params EmbedField[] fields)
			{
				this.title = title;
				this.fields = fields;
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public Embed(string description)
			{
				this.description = Localization.instance.Localize(description);
				timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public Embed(string title, List<EmbedField> fields)
				: this(title, fields.ToArray())
			{
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public void AddImage(string imageUrl)
			{
				if (!string.IsNullOrEmpty(imageUrl))
				{
					image = new EmbedImage(imageUrl);
				}
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public void AddThumbnail(string thumbnailUrl)
			{
				if (!string.IsNullOrEmpty(thumbnailUrl))
				{
					thumbnail = new EmbedImage(thumbnailUrl);
				}
			}

			public void SetColor(Color Color)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				color = ColorToInt(Color);
			}
		}

		[Serializable]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		[Description("Discord image json object")]
		public class EmbedImage
		{
			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
			public string url;

			public int width;

			public int height;

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public EmbedImage(string url, int width = 256, int height = 256)
			{
				this.url = url;
				this.width = width;
				this.height = height;
			}
		}

		[Serializable]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		public class EmbedVideo
		{
			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
			public string url;

			public int height;

			public int width;
		}

		[Serializable]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		public class EmbedProvider
		{
			public string name;

			public string url;
		}

		[Serializable]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		[Description("Discord author json object")]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		public class EmbedAuthor
		{
			public string name;

			public string icon_url;
		}

		[Serializable]
		[Description("Discord embed json object")]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		public class EmbedField
		{
			public string name;

			public string value;

			public bool inline;

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public EmbedField(string name, string value, bool inline = true)
			{
				this.name = Localization.instance.Localize(name);
				this.value = Localization.instance.Localize(value);
				this.inline = inline;
			}
		}

		[Serializable]
		[Description("Discord footer json object")]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		public class Footer
		{
			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
			public string text;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)]
			public string icon_url;

			public Footer(string text)
			{
				this.text = Localization.instance.Localize(text);
			}

			public void AddIcon(string url)
			{
				if (!string.IsNullOrEmpty(url))
				{
					icon_url = url;
				}
			}
		}

		[Serializable]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		[Description("Discord message json object")]
		public class Message
		{
			public string id;

			public string channel_id;

			public User author;

			public string content;

			public string timestamp;

			public string edited_timestamp;

			public bool tts;

			public bool mention_everyone;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
			public User[] mentions;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
			public User[] mention_roles;

			public int type;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
			public Embed[] embeds;
		}

		[Serializable]
		[Description("Discord user json object")]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		public class User
		{
			public string id;

			public string username;

			public string global_name;

			public string discriminator;

			public bool bot;

			public string avatar;

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public string GetDisplayName()
			{
				return ((!string.IsNullOrEmpty(global_name)) ? global_name : username) ?? string.Empty;
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			public string GetFullUsername()
			{
				return (!string.IsNullOrEmpty(discriminator) && discriminator != "0") ? (username + "#" + discriminator) : (username ?? string.Empty);
			}
		}

		private static ConfigEntry<string> m_webhookURL;

		public static Webhook instance;

		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
		[method: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
		[field: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })]
		public event Action<string> OnError;

		public static void Setup()
		{
			m_webhookURL = TimekeeperPlugin.instance.config("Discord", "Webhook URL", "", "Set webhook to receive notifications about timekeeper");
			((Component)TimekeeperPlugin.instance).gameObject.AddComponent<Webhook>();
		}

		public void Awake()
		{
			instance = this;
			OnError += HandleError;
		}

		private static void HandleError(string message)
		{
			TimekeeperPlugin.TimekeeperLogger.LogWarning((object)message);
		}

		public static void SendNotice(string message)
		{
			instance.SendNotification(message);
		}

		public void SendNotification(string message)
		{
			DiscordWebhookData data = new DiscordWebhookData(message);
			((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, m_webhookURL.Value));
		}

		public static void SendEmbedNotice(string title, string content, string thumbnail = "")
		{
			instance.SendEmbedMessage(title, content, thumbnail);
		}

		public void SendEmbedMessage(string title, string content, string thumbnail = "")
		{
			Embed embed = new Embed(title, content);
			embed.AddThumbnail(thumbnail);
			DiscordWebhookData data = new DiscordWebhookData(embed);
			((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, m_webhookURL.Value));
		}

		private IEnumerator SendWebhookMessage(DiscordWebhookData data, string webhookURL)
		{
			if (string.IsNullOrEmpty(webhookURL))
			{
				this.OnError?.Invoke("Webhook URL is not set!");
				yield break;
			}
			string jsonData = JsonConvert.SerializeObject((object)data);
			byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData);
			UnityWebRequest request = new UnityWebRequest(webhookURL, "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					string error = "Failed to send message: " + request.error + " - " + request.downloadHandler.text;
					this.OnError?.Invoke(error);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public static int ColorToInt(Color color)
		{
			//IL_0001: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.RoundToInt(color.r * 255f);
			int num2 = Mathf.RoundToInt(color.g * 255f);
			int num3 = Mathf.RoundToInt(color.b * 255f);
			return (num << 16) + (num2 << 8) + num3;
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	public static class RegisterAndCheckVersion
	{
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
		private static void Prefix(ZNetPeer peer, ref ZNet __instance)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			TimekeeperPlugin.TimekeeperLogger.LogDebug((object)"Registering version RPC handler");
			peer.m_rpc.Register<ZPackage>("Timekeeper_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_Timekeeper_Version);
			TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Invoking version check");
			ZPackage val = new ZPackage();
			val.Write("1.0.0");
			peer.m_rpc.Invoke("Timekeeper_VersionCheck", new object[1] { val });
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	public static class VerifyClient
	{
		private static bool Prefix(ZRpc rpc, ZPackage pkg, ref ZNet __instance)
		{
			if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc))
			{
				return true;
			}
			TimekeeperPlugin.TimekeeperLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") never sent version or couldn't due to previous disconnect, disconnecting"));
			rpc.Invoke("Error", new object[1] { 3 });
			return false;
		}

		private static void Postfix(ZNet __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "TimekeeperRequestAdminSync", new object[1] { (object)new ZPackage() });
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
	public class ShowConnectionError
	{
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
		private static void Postfix(FejdStartup __instance)
		{
			if (__instance.m_connectionFailedPanel.activeSelf)
			{
				__instance.m_connectionFailedError.fontSizeMax = 25f;
				__instance.m_connectionFailedError.fontSizeMin = 15f;
				TMP_Text connectionFailedError = __instance.m_connectionFailedError;
				connectionFailedError.text = connectionFailedError.text + "\n" + TimekeeperPlugin.ConnectionError;
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Disconnect")]
	public static class RemoveDisconnectedPeerFromVerified
	{
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
		private static void Prefix(ZNetPeer peer, ref ZNet __instance)
		{
			if (__instance.IsServer())
			{
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list"));
				RpcHandlers.ValidatedPeers.Remove(peer.m_rpc);
			}
		}
	}
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	public static class RpcHandlers
	{
		public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>();

		public static void RPC_Timekeeper_Version(ZRpc rpc, ZPackage pkg)
		{
			string text = pkg.ReadString();
			TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Version check, local: 1.0.0,  remote: " + text));
			if (text != "1.0.0")
			{
				TimekeeperPlugin.ConnectionError = "Timekeeper Installed: 1.0.0\n Needed: " + text;
				if (ZNet.instance.IsServer())
				{
					TimekeeperPlugin.TimekeeperLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") has incompatible version, disconnecting..."));
					rpc.Invoke("Error", new object[1] { 3 });
				}
			}
			else if (!ZNet.instance.IsServer())
			{
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Received same version from server!");
			}
			else
			{
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Adding peer (" + rpc.m_socket.GetHostName() + ") to validated list"));
				ValidatedPeers.Add(rpc);
			}
		}

		public static string ComputeHashForMod()
		{
			using SHA256 sHA = SHA256.Create();
			byte[] array = sHA.ComputeHash(File.ReadAllBytes(Assembly.GetExecutingAssembly().Location));
			StringBuilder stringBuilder = new StringBuilder();
			byte[] array2 = array;
			foreach (byte b in array2)
			{
				stringBuilder.Append(b.ToString("X2"));
			}
			return stringBuilder.ToString();
		}
	}
}
namespace Timekeeper.Managers
{
	public static class CommandManager
	{
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		public class CommandData
		{
			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
			[HarmonyPatch(typeof(Terminal), "updateSearch")]
			private static class Terminal_UpdateSearch_Patch
			{
				[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
				private static bool Prefix(Terminal __instance, string word)
				{
					if ((Object)(object)__instance.m_search == (Object)null)
					{
						return true;
					}
					string[] array = ((TMP_InputField)__instance.m_input).text.Split(new char[1] { ' ' });
					if (array.Length < 3)
					{
						return true;
					}
					if (array[0] != m_startCommand)
					{
						return true;
					}
					return HandleSearch(__instance, word, array);
				}
			}

			[HarmonyPatch(typeof(Terminal), "tabCycle")]
			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
			private static class Terminal_TabCycle_Patch
			{
				[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
				private static bool Prefix(Terminal __instance, string word, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] List<string> options, bool usePrefix)
				{
					if (options == null || options.Count == 0)
					{
						return true;
					}
					usePrefix = usePrefix && __instance.m_tabPrefix > '\0';
					if (usePrefix)
					{
						if (word.Length < 1 || word[0] != __instance.m_tabPrefix)
						{
							return true;
						}
						word = word.Substring(1);
					}
					return HandleTabCycle(__instance, word, options, usePrefix);
				}
			}

			public static readonly string m_startCommand = "timekeeper";

			public static readonly Dictionary<string, CommandData> m_commands = new Dictionary<string, CommandData>();

			public readonly string m_description;

			private readonly bool m_isSecret;

			private readonly bool m_adminOnly;

			private readonly Func<ConsoleEventArgs, bool> m_command;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1, 1 })]
			private readonly Func<List<string>> m_optionFetcher;

			public bool Run(ConsoleEventArgs args)
			{
				return !IsAdmin() || m_command(args);
			}

			private bool IsAdmin()
			{
				if (!Object.op_Implicit((Object)(object)ZNet.m_instance))
				{
					return true;
				}
				if (!m_adminOnly || ZNet.m_instance.LocalPlayerIsAdminOrHost())
				{
					return true;
				}
				Debug.LogWarning((object)"Admin only command");
				return false;
			}

			public bool IsSecret()
			{
				return m_isSecret;
			}

			public List<string> FetchOptions()
			{
				return (m_optionFetcher == null) ? new List<string>() : m_optionFetcher();
			}

			public bool HasOptions()
			{
				return m_optionFetcher != null;
			}

			public CommandData(string input, string description, Func<ConsoleEventArgs, bool> command, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1, 1 })] Func<List<string>> optionsFetcher = null, bool isSecret = false, bool adminOnly = false)
			{
				m_description = description;
				m_command = command;
				m_isSecret = isSecret;
				m_commands[input] = this;
				m_optionFetcher = optionsFetcher;
				m_adminOnly = adminOnly;
			}

			private static bool HandleSearch(Terminal __instance, string word, string[] strArray)
			{
				if (!m_commands.TryGetValue(strArray[1], out var value))
				{
					return true;
				}
				if (value.HasOptions() && strArray.Length == 3)
				{
					List<string> list = value.FetchOptions();
					string currentSearch = strArray[2];
					List<string> list2;
					if (!Utility.IsNullOrWhiteSpace(currentSearch))
					{
						int num = list.IndexOf(currentSearch);
						list2 = ((num != -1) ? list.GetRange(num, list.Count - num) : list);
						list2 = list2.FindAll((string x) => x.ToLower().Contains(currentSearch.ToLower()));
					}
					else
					{
						list2 = list;
					}
					if (list2.Count <= 0)
					{
						__instance.m_search.text = value.m_description;
					}
					else
					{
						__instance.m_lastSearch.Clear();
						__instance.m_lastSearch.AddRange(list2);
						__instance.m_lastSearch.Remove(word);
						__instance.m_search.text = "";
						int num2 = 10;
						int num3 = Math.Min(__instance.m_lastSearch.Count, num2);
						for (int i = 0; i < num3; i++)
						{
							string text = __instance.m_lastSearch[i];
							TMP_Text search = __instance.m_search;
							search.text = search.text + text + " ";
						}
						if (__instance.m_lastSearch.Count <= num2)
						{
							return false;
						}
						int num4 = __instance.m_lastSearch.Count - num2;
						TMP_Text search2 = __instance.m_search;
						search2.text += $"... {num4} more.";
					}
				}
				else
				{
					__instance.m_search.text = value.m_description;
				}
				return false;
			}

			private static bool HandleTabCycle(Terminal __instance, string word, List<string> options, bool usePrefix)
			{
				string text = ((TMP_InputField)__instance.m_input).text;
				string[] array = text.Split(new char[1] { ' ' });
				if (array.Length < 2 || !string.Equals(array[0], m_startCommand, StringComparison.CurrentCultureIgnoreCase) || !m_commands.ContainsKey(array[1].ToLower()))
				{
					return true;
				}
				if (__instance.m_tabCaretPosition == -1)
				{
					__instance.m_tabOptions.Clear();
					__instance.m_tabCaretPosition = ((TMP_InputField)__instance.m_input).caretPosition;
					word = word.ToLower();
					__instance.m_tabLength = word.Length;
					if (__instance.m_tabLength == 0)
					{
						__instance.m_tabOptions.AddRange(options);
					}
					else
					{
						foreach (string option in options)
						{
							if (option != null && option.Length > __instance.m_tabLength && option.Substring(0, __instance.m_tabLength).ToLower() == word)
							{
								__instance.m_tabOptions.Add(option);
							}
						}
					}
					__instance.m_tabOptions.Sort();
					__instance.m_tabIndex = -1;
				}
				if (__instance.m_tabOptions.Count == 0)
				{
					__instance.m_tabOptions.AddRange(__instance.m_lastSearch);
				}
				if (__instance.m_tabOptions.Count == 0)
				{
					return false;
				}
				if (++__instance.m_tabIndex >= __instance.m_tabOptions.Count)
				{
					__instance.m_tabIndex = 0;
				}
				if (__instance.m_tabCaretPosition - __instance.m_tabLength >= 0)
				{
					int num = 0;
					int num2 = 0;
					for (int i = 0; i < text.Length; i++)
					{
						if (text[i] == ' ')
						{
							num++;
							if (num == 2)
							{
								num2 = i + 1;
								break;
							}
						}
					}
					if (array.Length >= 3 && num2 > 0)
					{
						string text2 = text.Substring(0, num2);
						((TMP_InputField)__instance.m_input).text = text2 + __instance.m_tabOptions[__instance.m_tabIndex];
					}
					else if (array.Length == 2)
					{
						((TMP_InputField)__instance.m_input).text = text + " " + __instance.m_tabOptions[__instance.m_tabIndex];
					}
				}
				int tabCaretPositionEnd = (((TMP_InputField)__instance.m_input).caretPosition = ((TMP_InputField)__instance.m_input).text.Length);
				__instance.m_tabCaretPositionEnd = tabCaretPositionEnd;
				return false;
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEventFailable <>9__0_0;

			public static Func<KeyValuePair<string, CommandData>, bool> <>9__0_1;

			public static Func<KeyValuePair<string, CommandData>, string> <>9__0_2;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })]
			public static Func<ConsoleEventArgs, bool> <>9__0_3;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })]
			public static Func<ConsoleEventArgs, bool> <>9__0_4;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })]
			public static Func<ConsoleEventArgs, bool> <>9__0_5;

			[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })]
			public static Func<ConsoleEventArgs, bool> <>9__0_6;

			internal object <Setup>b__0_0(ConsoleEventArgs args)
			{
				if (args.Length < 2)
				{
					return false;
				}
				if (!CommandData.m_commands.TryGetValue(args[1], out var value))
				{
					return false;
				}
				return value.Run(args);
			}

			internal bool <Setup>b__0_1(KeyValuePair<string, CommandData> x)
			{
				return !x.Value.IsSecret();
			}

			internal string <Setup>b__0_2(KeyValuePair<string, CommandData> x)
			{
				return x.Key;
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			internal bool <Setup>b__0_3(ConsoleEventArgs args)
			{
				if (args.Length < 3)
				{
					return false;
				}
				if (!float.TryParse(args[2], out var result))
				{
					return false;
				}
				TimeMan.m_activeTimer += result;
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + result + " seconds to local player"));
				return true;
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			internal bool <Setup>b__0_4(ConsoleEventArgs _)
			{
				if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					return false;
				}
				TimeMan.Clear(Player.m_localPlayer);
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Cleared local player timekeeper data");
				return true;
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			internal bool <Setup>b__0_5(ConsoleEventArgs _)
			{
				if (!Object.op_Implicit((Object)(object)EnvMan.instance))
				{
					return false;
				}
				TimeMan.m_activeTimer += EnvMan.instance.m_dayLengthSec;
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + EnvMan.instance.m_dayLengthSec + " seconds to local player"));
				return true;
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
			internal bool <Setup>b__0_6(ConsoleEventArgs args)
			{
				if (args.Length < 5)
				{
					return false;
				}
				if (!int.TryParse(args[2], out var result))
				{
					return false;
				}
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(args[3].Trim());
				if (itemPrefab == null)
				{
					return false;
				}
				if (!int.TryParse(args[4], out var result2))
				{
					return false;
				}
				int num = 1;
				int num2 = 0;
				if (args.Length > 5)
				{
					num = (int.TryParse(args[5], out var result3) ? result3 : num);
				}
				if (args.Length > 6)
				{
					num2 = (int.TryParse(args[6], out var result4) ? result4 : num2);
				}
				TimeMan.Reward reward = new TimeMan.Reward(((Object)itemPrefab).name, result2, num, num2);
				TimeMan.AddReward(result, reward);
				TimeMan.UpdateRewardFile();
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Updated rewards");
				return true;
			}
		}

		public static void Setup()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			string startCommand = CommandData.m_startCommand;
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEventFailable val = delegate(ConsoleEventArgs args)
				{
					if (args.Length < 2)
					{
						return false;
					}
					CommandData value;
					return (!CommandData.m_commands.TryGetValue(args[1], out value)) ? ((object)false) : ((object)value.Run(args));
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			ConsoleCommand val2 = new ConsoleCommand(startCommand, "Use help to find commands", (ConsoleEventFailable)obj, false, false, false, false, false, new ConsoleOptionsFetcher(Enumerable.ToList), false, false, false);
			new CommandData("add", "adds seconds to player counter", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs args) =>
			{
				if (args.Length < 3)
				{
					return false;
				}
				if (!float.TryParse(args[2], out var result5))
				{
					return false;
				}
				TimeMan.m_activeTimer += result5;
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + result5 + " seconds to local player"));
				return true;
			}, null, isSecret: false, adminOnly: true);
			new CommandData("reset", "clears data from player save", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs _) =>
			{
				if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					return false;
				}
				TimeMan.Clear(Player.m_localPlayer);
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Cleared local player timekeeper data");
				return true;
			});
			new CommandData("add_day", "adds a full day (1800) to the player counter", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs _) =>
			{
				if (!Object.op_Implicit((Object)(object)EnvMan.instance))
				{
					return false;
				}
				TimeMan.m_activeTimer += EnvMan.instance.m_dayLengthSec;
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + EnvMan.instance.m_dayLengthSec + " seconds to local player"));
				return true;
			}, null, isSecret: false, adminOnly: true);
			new CommandData("add_reward", "[day] [itemName] [Amount] [Quality] [Variant], add a new reward", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs args) =>
			{
				if (args.Length < 5)
				{
					return false;
				}
				if (!int.TryParse(args[2], out var result))
				{
					return false;
				}
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(args[3].Trim());
				if (itemPrefab == null)
				{
					return false;
				}
				if (!int.TryParse(args[4], out var result2))
				{
					return false;
				}
				int num = 1;
				int num2 = 0;
				if (args.Length > 5)
				{
					num = (int.TryParse(args[5], out var result3) ? result3 : num);
				}
				if (args.Length > 6)
				{
					num2 = (int.TryParse(args[6], out var result4) ? result4 : num2);
				}
				TimeMan.Reward reward = new TimeMan.Reward(((Object)itemPrefab).name, result2, num, num2);
				TimeMan.AddReward(result, reward);
				TimeMan.UpdateRewardFile();
				TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Updated rewards");
				return true;
			}, null, isSecret: false, adminOnly: true);
		}
	}
}
namespace Managers
{
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	public static class AssetManager
	{
		private static readonly Dictionary<string, AssetBundle> m_assetBundles = new Dictionary<string, AssetBundle>();

		public static AssetBundle GetAssetBundle(string fileName)
		{
			if (m_assetBundles.TryGetValue(fileName, out var value))
			{
				return value;
			}
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string name = executingAssembly.GetManifestResourceNames().Single([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (string str) => str.EndsWith(fileName));
			using Stream stream = executingAssembly.GetManifestResourceStream(name);
			value = AssetBundle.LoadFromStream(stream);
			m_assetBundles[fileName] = value;
			return value;
		}
	}
	[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
	[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)]
	public static class FontManager
	{
		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)]
		public enum FontOptions
		{
			Norse,
			NorseBold,
			AveriaSerifLibre,
			AveriaSerifLibreBold,
			AveriaSerifLibreLight,
			LegacyRuntime
		}

		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)]
		private class TextFont
		{
			private readonly Text m_text;

			public TextFont(Text text, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] Font font)
			{
				m_text = text;
				Update(font);
				m_allTexts.Add(this);
			}

			[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
			public void Update(Font font)
			{
				m_text.font = font;
			}
		}

		[<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 2 })]
		private static readonly Dictionary<FontOptions, Font> m_fonts = new Dictionary<FontOptions, Font>();

		private static readonly List<TextFont> m_allTexts = new List<TextFont>();

		private static string GetFontName(FontOptions option)
		{
			if (1 == 0)
			{
			}
			string result = option switch
			{
				FontOptions.Norse => "Norse", 
				FontOptions.AveriaSerifLibre => "AveriaSerifLibre-Regular", 
				FontOptions.AveriaSerifLibreBold => "AveriaSerifLibre-Bold", 
				FontOptions.AveriaSerifLibreLight => "AveriaSerifLibre-Light", 
				FontOptions.NorseBold => "Norsebold", 
				FontOptions.LegacyRuntime => "LegacyRuntime", 
				_ => "AveriaSerifLibre-Regular", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		[<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)]
		public static Font GetFont(FontOptions option)
		{
			if (m_fonts.TryGetValue(option, out var value))
			{
				return value;
			}
			Font[] source = Resources.FindObjectsOfTypeAll<Font>();
			Font val = ((IEnumerable<Font>)source).FirstOrDefault((Func<Font, bool>)([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (Font x) => ((Object)x).name == GetFontName(option)));
			m_fonts[option] = val;
			return val;
		}

		public static void OnFontChange(object sender, EventArgs args)
		{
			Font font = GetFont(FontOptions.AveriaSerifLibre);
			foreach (TextFont allText in m_allTexts)
			{
				allText.Update(font);
			}
		}

		public static void SetFont(Text[] array)
		{
			foreach (Text text in array)
			{
				TextFont textFont = new TextFont(text, GetFont(FontOptions.AveriaSerifLibre));
			}
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ServerSync
{
	[PublicAPI]
	internal abstract class OwnConfigEntryBase
	{
		public object? LocalBaseValue;

		public bool SynchronizedConfig = true;

		public abstract ConfigEntryBase BaseConfig { get; }
	}
	[PublicAPI]
	internal class SyncedConfigEntry<T> : OwnConfigEntryBase
	{
		public readonly ConfigEntry<T> SourceConfig;

		public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;

		public T Value
		{
			get
			{
				return SourceConfig.Value;
			}
			set
			{
				SourceConfig.Value = value;
			}
		}

		public SyncedConfigEntry(ConfigEntry<T> sourceConfig)
		{
			SourceConfig = sourceConfig;
			base..ctor();
		}

		public void AssignLocalValue(T value)
		{
			if (LocalBaseValue == null)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal abstract class CustomSyncedValueBase
	{
		public object? LocalBaseValue;

		public readonly string Identifier;

		public readonly Type Type;

		private object? boxedValue;

		protected bool localIsOwner;

		public readonly int Priority;

		public object? BoxedValue
		{
			get
			{
				return boxedValue;
			}
			set
			{
				boxedValue = value;
				this.ValueChanged?.Invoke();
			}
		}

		public event Action? ValueChanged;

		protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
		{
			Priority = priority;
			Identifier = identifier;
			Type = type;
			configSync.AddCustomValue(this);
			localIsOwner = configSync.IsSourceOfTruth;
			configSync.SourceOfTruthChanged += delegate(bool truth)
			{
				localIsOwner = truth;
			};
		}
	}
	[PublicAPI]
	internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
			}
		}

		public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
			: base(configSync, identifier, typeof(T), priority)
		{
			Value = value;
		}

		public void AssignLocalValue(T value)
		{
			if (localIsOwner)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ConfigurationManagerAttributes
	{
		[UsedImplicitly]
		public bool? ReadOnly = false;
	}
	[PublicAPI]
	internal class ConfigSync
	{
		[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
		private static class SnatchCurrentlyHandlingRPC
		{
			public static ZRpc? currentRpc;

			[HarmonyPrefix]
			private static void Prefix(ZRpc __instance)
			{
				currentRpc = __instance;
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		internal static class RegisterRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance)
			{
				isServer = __instance.IsServer();
				foreach (ConfigSync configSync2 in configSyncs)
				{
					ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
					if (isServer)
					{
						configSync2.InitialSyncDone = true;
						Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections"));
					}
				}
				if (isServer)
				{
					((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
				}
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
					{
						new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = isAdmin
						}
					});
					ConfigSync configSync = configSyncs.First();
					if (configSync != null)
					{
						((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
					}
				}
				static IEnumerator WatchAdminListChanges()
				{
					MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
					SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
					List<string> CurrentList = new List<string>(adminList.GetList());
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!adminList.GetList().SequenceEqual(CurrentList))
						{
							CurrentList = new List<string>(adminList.GetList());
							List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p)
							{
								string hostName = p.m_rpc.GetSocket().GetHostName();
								return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName }));
							}).ToList();
							List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class RegisterClientRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (__instance.IsServer())
				{
					return;
				}
				foreach (ConfigSync configSync in configSyncs)
				{
					peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
				}
			}
		}

		private class ParsedConfigs
		{
			public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();

			public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private class ResetConfigsOnShutdown
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ProcessingServerUpdate = true;
				foreach (ConfigSync configSync in configSyncs)
				{
					configSync.resetConfigsFromServer();
					configSync.IsSourceOfTruth = true;
					configSync.InitialSyncDone = false;
				}
				ProcessingServerUpdate = false;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private class SendConfigsAfterLogin
		{
			private class BufferingSocket : ZPlayFabSocket, ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

				public readonly List<ZPackage> Package = new List<ZPackage>();

				public readonly ISocket Original;

				public BufferingSocket(ISocket original)
				{
					Original = original;
					((ZPlayFabSocket)this)..ctor();
				}

				public bool IsConnected()
				{
					return Original.IsConnected();
				}

				public ZPackage Recv()
				{
					return Original.Recv();
				}

				public int GetSendQueueSize()
				{
					return Original.GetSendQueueSize();
				}

				public int GetCurrentSendRate()
				{
					return Original.GetCurrentSendRate();
				}

				public bool IsHost()
				{
					return Original.IsHost();
				}

				public void Dispose()
				{
					Original.Dispose();
				}

				public bool GotNewData()
				{
					return Original.GotNewData();
				}

				public void Close()
				{
					Original.Close();
				}

				public string GetEndPointString()
				{
					return Original.GetEndPointString();
				}

				public void GetAndResetStats(out int totalSent, out int totalRecv)
				{
					Original.GetAndResetStats(ref totalSent, ref totalRecv);
				}

				public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
				{
					Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec);
				}

				public ISocket Accept()
				{
					return Original.Accept();
				}

				public int GetHostPort()
				{
					return Original.GetHostPort();
				}

				public bool Flush()
				{
					return Original.Flush();
				}

				public string GetHostName()
				{
					return Original.GetHostName();
				}

				public void VersionMatch()
				{
					if (finished)
					{
						Original.VersionMatch();
					}
					else
					{
						versionMatchQueued = Package.Count;
					}
				}

				public void Send(ZPackage pkg)
				{
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005d: Expected O, but got Unknown
					int pos = pkg.GetPos();
					pkg.SetPos(0);
					int num = pkg.ReadInt();
					if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished)
					{
						ZPackage val = new ZPackage(pkg.GetArray());
						val.SetPos(pos);
						Package.Add(val);
					}
					else
					{
						pkg.SetPos(pos);
						Original.Send(pkg);
					}
				}
			}

			[HarmonyPriority(800)]
			[HarmonyPrefix]
			private static void Prefix(ref Dictionary<Assembly, BufferingSocket>? __state, ZNet __instance, ZRpc rpc)
			{
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				if (!__instance.IsServer())
				{
					return;
				}
				BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket());
				AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket);
				object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
				ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
				if (val != null && (int)ZNet.m_onlineBackend > 0)
				{
					FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket");
					object? value = fieldInfo.GetValue(val);
					ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null);
					if (val2 != null)
					{
						typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId);
					}
					fieldInfo.SetValue(val, bufferingSocket);
				}
				if (__state == null)
				{
					__state = new Dictionary<Assembly, BufferingSocket>();
				}
				__state[Assembly.GetExecutingAssembly()] = bufferingSocket;
			}

			[HarmonyPostfix]
			private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
			{
				ZRpc rpc2 = rpc;
				ZNet __instance2 = __instance;
				Dictionary<Assembly, BufferingSocket> __state2 = __state;
				ZNetPeer peer;
				if (__instance2.IsServer())
				{
					object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
					peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (peer == null)
					{
						SendBufferedData();
					}
					else
					{
						((MonoBehaviour)__instance2).StartCoroutine(sendAsync());
					}
				}
				void SendBufferedData()
				{
					if (rpc2.GetSocket() is BufferingSocket bufferingSocket)
					{
						AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original);
						object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 });
						ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null);
						if (val != null)
						{
							AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original);
						}
					}
					BufferingSocket bufferingSocket2 = __state2[Assembly.GetExecutingAssembly()];
					bufferingSocket2.finished = true;
					for (int i = 0; i < bufferingSocket2.Package.Count; i++)
					{
						if (i == bufferingSocket2.versionMatchQueued)
						{
							bufferingSocket2.Original.VersionMatch();
						}
						bufferingSocket2.Original.Send(bufferingSocket2.Package[i]);
					}
					if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued)
					{
						bufferingSocket2.Original.VersionMatch();
					}
				}
				IEnumerator sendAsync()
				{
					foreach (ConfigSync configSync in configSyncs)
					{
						List<PackageEntry> entries = new List<PackageEntry>();
						if (configSync.CurrentVersion != null)
						{
							entries.Add(new PackageEntry
							{
								section = "Internal",
								key = "serverversion",
								type = typeof(string),
								value = configSync.CurrentVersion
							});
						}
						MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
						SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
						entries.Add(new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2]
							{
								adminList,
								rpc2.GetSocket().GetHostName()
							}))
						});
						ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false);
						yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package));
					}
					SendBufferedData();
				}
			}
		}

		private class PackageEntry
		{
			public string section = null;

			public string key = null;

			public Type type = null;

			public object? value;
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")]
		private static class PreventSavingServerInfo
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, ref string __result)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase))
				{
					return true;
				}
				__result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType);
				return false;
			}
		}

		[HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")]
		private static class PreventConfigRereadChangingValues
		{
			[HarmonyPrefix]
			private static bool Prefix(ConfigEntryBase __instance, string value)
			{
				OwnConfigEntryBase ownConfigEntryBase = configData(__instance);
				if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null)
				{
					return true;
				}
				try
				{
					ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}");
				}
				return false;
			}
		}

		private class InvalidDeserializationTypeException : Exception
		{
			public string expected = null;

			public string received = null;

			public string field = "";
		}

		public static bool Processin