Decompiled source of HatLib v0.0.1

HatLib.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using Dusk;
using GameNetcodeStuff;
using HarmonyLib;
using HatLib.NetcodePatcher;
using HatLib.Patches;
using HatLib.Tools;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("HatLib")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1")]
[assembly: AssemblyProduct("HatLib")]
[assembly: AssemblyTitle("HatLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HatLib
{
	internal static class ConfigManager
	{
		internal static ConfigEntry<bool>? DebugLogs { get; private set; }

		internal static void Bind(ConfigFile config)
		{
			DebugLogs = config.Bind<bool>("Internal", "Debug Logs", false, "If true, allows debug logging");
		}
	}
	internal static class Log
	{
		internal static void Debug(string message)
		{
			if (ConfigManager.DebugLogs.Value)
			{
				Write((LogLevel)32, message);
			}
		}

		internal static void Info(string message)
		{
			Write((LogLevel)16, message);
		}

		internal static void Warn(string message)
		{
			Write((LogLevel)4, message);
		}

		internal static void Error(string message)
		{
			Write((LogLevel)2, message);
		}

		internal static void Fatal(string message)
		{
			Write((LogLevel)1, message);
		}

		private static void Write(LogLevel logLevel, string message)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Plugin.mls.Log(logLevel, (object)message);
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("MrHat.Lib", "HatLib", "0.0.1")]
	internal class Plugin : BaseUnityPlugin
	{
		internal const string modGUID = "MrHat.Lib";

		internal const string modName = "HatLib";

		internal const string modVersion = "0.0.1";

		private const string DawnLibGUID = "com.github.teamxiaolan.dawnlib";

		private const string DuskGUID = "com.github.teamxiaolan.dawnlib.dusk";

		internal static Harmony _harmony;

		internal static ManualLogSource mls;

		internal static Plugin instance;

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			instance = this;
			mls = Logger.CreateLogSource("MrHat.Lib");
			_harmony = new Harmony("MrHat.Lib");
			ConfigManager.Bind(((BaseUnityPlugin)this).Config);
			_harmony.PatchAll(typeof(GameNetworkManagerPatches));
			_harmony.PatchAll(typeof(StartOfRoundPatches));
			mls.LogInfo((object)"HatLib loaded");
		}
	}
	public class RoundEvents
	{
		public static event Action<StartOfRound>? OnRoundStart;

		public static event Action<StartOfRound>? OnRoundEnd;

		public static event Action<StartOfRound>? OnShipLeft;

		public static event Action<StartOfRound>? OnShipReadyToLand;

		public static event Action<StartOfRound>? OnShipItemsLoaded;

		public static event Action<StartOfRound>? OnShipUnlockablesSynced;

		public static event Action<StartOfRound>? OnPlayersLoadedReset;

		public static event Action<StartOfRound>? OnLocalDisconnect;

		public static event Action<StartOfRound>? OnDestroy;

		public static event Action? OnGameSaved;

		private RoundEvents()
		{
		}

		internal static void RoundStart(StartOfRound startOfRound)
		{
			RoundEvents.OnRoundStart?.Invoke(startOfRound);
		}

		internal static void RoundEnd(StartOfRound startOfRound)
		{
			RoundEvents.OnRoundEnd?.Invoke(startOfRound);
		}

		internal static void ShipLeft(StartOfRound startOfRound)
		{
			RoundEvents.OnShipLeft?.Invoke(startOfRound);
		}

		internal static void ShipReadyToLand(StartOfRound startOfRound)
		{
			RoundEvents.OnShipReadyToLand?.Invoke(startOfRound);
		}

		internal static void ShipItemsLoaded(StartOfRound startOfRound)
		{
			RoundEvents.OnShipItemsLoaded?.Invoke(startOfRound);
		}

		internal static void ShipUnlockablesSynced(StartOfRound startOfRound)
		{
			RoundEvents.OnShipUnlockablesSynced?.Invoke(startOfRound);
		}

		internal static void PlayersLoadedReset(StartOfRound startOfRound)
		{
			RoundEvents.OnPlayersLoadedReset?.Invoke(startOfRound);
		}

		internal static void Disconnect(StartOfRound startOfRound)
		{
			RoundEvents.OnLocalDisconnect?.Invoke(startOfRound);
		}

		internal static void Destroy(StartOfRound startOfRound)
		{
			RoundEvents.OnDestroy?.Invoke(startOfRound);
		}

		internal static void GameSaved()
		{
			RoundEvents.OnGameSaved?.Invoke();
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "HatLib";

		public const string PLUGIN_NAME = "HatLib";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}
namespace HatLib.Tools
{
	public static class AudioTools
	{
		public static bool PlayOneShot(AudioSource? source, AudioClip? clip)
		{
			if ((Object)(object)source == (Object)null || (Object)(object)clip == (Object)null)
			{
				return false;
			}
			source.PlayOneShot(clip);
			return true;
		}

		public static bool Load(AudioClip? clip)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if ((Object)(object)clip == (Object)null || (int)clip.loadState > 0)
			{
				return false;
			}
			return clip.LoadAudioData();
		}

		public static bool Unload(AudioClip? clip)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if ((Object)(object)clip == (Object)null || (int)clip.loadState != 2)
			{
				return false;
			}
			return clip.UnloadAudioData();
		}

		public static bool SwapClip(AudioSource? source, AudioClip? clip, bool play)
		{
			if ((Object)(object)source == (Object)null)
			{
				return false;
			}
			source.clip = clip;
			if (play && (Object)(object)clip != (Object)null)
			{
				source.Play();
			}
			return true;
		}

		public static bool Stop(AudioSource? source, bool zeroVolume = false)
		{
			if ((Object)(object)source == (Object)null)
			{
				return false;
			}
			if (zeroVolume)
			{
				source.volume = 0f;
			}
			source.Stop();
			return true;
		}

		public static int StopMany(bool zeroVolume = false, params AudioSource?[] sources)
		{
			if (sources == null)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < sources.Length; i++)
			{
				if (Stop(sources[i], zeroVolume))
				{
					num++;
				}
			}
			return num;
		}
	}
	public static class CoroutineTools
	{
		public static bool Start(MonoBehaviour owner, ref Coroutine? handle, IEnumerator job)
		{
			if ((Object)(object)owner == (Object)null || job == null || handle != null)
			{
				return false;
			}
			handle = owner.StartCoroutine(job);
			return true;
		}

		public static bool Stop(MonoBehaviour owner, ref Coroutine? handle)
		{
			if ((Object)(object)owner == (Object)null || handle == null)
			{
				return false;
			}
			owner.StopCoroutine(handle);
			handle = null;
			return true;
		}

		public static bool Restart(MonoBehaviour owner, ref Coroutine? handle, IEnumerator job)
		{
			Stop(owner, ref handle);
			return Start(owner, ref handle, job);
		}

		public static Coroutine? NextFrame(MonoBehaviour owner, Action action)
		{
			if ((Object)(object)owner == (Object)null || action == null)
			{
				return null;
			}
			return owner.StartCoroutine(NextFrameWait(action));
		}

		public static Coroutine? Delay(MonoBehaviour owner, float seconds, Action action)
		{
			if ((Object)(object)owner == (Object)null || action == null)
			{
				return null;
			}
			return owner.StartCoroutine(DelayWait(seconds, action));
		}

		private static IEnumerator NextFrameWait(Action action)
		{
			yield return null;
			action();
		}

		private static IEnumerator DelayWait(float seconds, Action action)
		{
			yield return (object)new WaitForSeconds(seconds);
			action();
		}
	}
	public static class DawnContractData
	{
		public static bool LoadString(NamespacedKey key, out string? raw)
		{
			raw = string.Empty;
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Debug($"Dawn contract string load skipped because no current contract exists for {key}");
				return false;
			}
			if (!((DataContainer)currentContract).TryGet<string>(key, ref raw))
			{
				Log.Debug($"Dawn contract string was not found for {key}");
				return false;
			}
			Log.Debug($"Dawn contract string loaded for {key}");
			return true;
		}

		public static bool WriteString(NamespacedKey key, string raw)
		{
			return Write(key, raw);
		}

		public static bool Load<T>(NamespacedKey key, out T? value)
		{
			value = default(T);
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Debug($"Dawn contract value load skipped because no current contract exists for {key}");
				return false;
			}
			if (!((DataContainer)currentContract).TryGet<T>(key, ref value))
			{
				Log.Debug($"Dawn contract value was not found for {key}");
				return false;
			}
			Log.Debug($"Dawn contract value loaded for {key}");
			return true;
		}

		public static bool Write<T>(NamespacedKey key, T value)
		{
			if (value == null)
			{
				Log.Warn($"Dawn contract value write skipped because value was null for {key}");
				return false;
			}
			if (!CanWrite())
			{
				Log.Warn($"Dawn contract value write skipped because this client is not the server for {key}");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn contract value write skipped because no current contract exists for {key}");
				return false;
			}
			using (((DataContainer)currentContract).CreateEditContext())
			{
				((DataContainer)currentContract).Set<T>(key, value);
			}
			Log.Debug($"Dawn contract value written for {key}");
			return true;
		}

		public static bool LoadJObject(NamespacedKey parentKey, NamespacedKey childKey, out JObject? value)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			value = new JObject();
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Debug($"Dawn contract child object load skipped because no current contract exists for {childKey}");
				return false;
			}
			ChildPersistentDataContainer val = default(ChildPersistentDataContainer);
			if (!((DataContainer)currentContract).TryGet<ChildPersistentDataContainer>(parentKey, ref val))
			{
				Log.Debug($"Dawn contract child container was not found for {parentKey}");
				return false;
			}
			if (!((DataContainer)val).TryGet<JObject>(childKey, ref value))
			{
				Log.Debug($"Dawn contract child object was not found for {childKey}");
				return false;
			}
			Log.Debug($"Dawn contract child object loaded for {childKey}");
			return true;
		}

		public static bool WriteJObject(NamespacedKey parentKey, NamespacedKey childKey, JObject value)
		{
			return Write<JObject>(parentKey, childKey, value);
		}

		public static bool Load<T>(NamespacedKey parentKey, NamespacedKey childKey, out T? value)
		{
			value = default(T);
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Debug($"Dawn contract child value load skipped because no current contract exists for {childKey}");
				return false;
			}
			ChildPersistentDataContainer val = default(ChildPersistentDataContainer);
			if (!((DataContainer)currentContract).TryGet<ChildPersistentDataContainer>(parentKey, ref val))
			{
				Log.Debug($"Dawn contract child container was not found for {parentKey}");
				return false;
			}
			if (!((DataContainer)val).TryGet<T>(childKey, ref value))
			{
				Log.Debug($"Dawn contract child value was not found for {childKey}");
				return false;
			}
			Log.Debug($"Dawn contract child value loaded for {childKey}");
			return true;
		}

		public static bool Write<T>(NamespacedKey parentKey, NamespacedKey childKey, T value)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			if (value == null)
			{
				Log.Warn($"Dawn contract child value write skipped because value was null for {childKey}");
				return false;
			}
			if (!CanWrite())
			{
				Log.Warn($"Dawn contract child value write skipped because this client is not the server for {childKey}");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn contract child value write skipped because no current contract exists for {childKey}");
				return false;
			}
			using (((DataContainer)currentContract).CreateEditContext())
			{
				ChildPersistentDataContainer val = default(ChildPersistentDataContainer);
				if (!((DataContainer)currentContract).TryGet<ChildPersistentDataContainer>(parentKey, ref val))
				{
					val = new ChildPersistentDataContainer(currentContract);
					((DataContainer)currentContract).Set<ChildPersistentDataContainer>(parentKey, val);
					Log.Debug($"Dawn contract child container created for {parentKey}");
				}
				((DataContainer)val).Set<T>(childKey, value);
			}
			Log.Debug($"Dawn contract child value written for {childKey}");
			return true;
		}

		public static bool Delete(NamespacedKey key)
		{
			if (!CanWrite())
			{
				Log.Warn($"Dawn contract value delete skipped because this client is not the server for {key}");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn contract value delete skipped because no current contract exists for {key}");
				return false;
			}
			using (((DataContainer)currentContract).CreateEditContext())
			{
				((DataContainer)currentContract).Remove(key);
			}
			Log.Debug($"Dawn contract value deleted for {key}");
			return true;
		}

		public static bool Delete(NamespacedKey parentKey, NamespacedKey childKey, bool deleteParentWhenEmpty = false)
		{
			if (!CanWrite())
			{
				Log.Warn($"Dawn contract child value delete skipped because this client is not the server for {childKey}");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn contract child value delete skipped because no current contract exists for {childKey}");
				return false;
			}
			using (((DataContainer)currentContract).CreateEditContext())
			{
				ChildPersistentDataContainer val = default(ChildPersistentDataContainer);
				if (!((DataContainer)currentContract).TryGet<ChildPersistentDataContainer>(parentKey, ref val))
				{
					Log.Debug($"Dawn contract child delete skipped because container was not found for {parentKey}");
					return false;
				}
				((DataContainer)val).Remove(childKey);
				Log.Debug($"Dawn contract child value deleted for {childKey}");
				if (deleteParentWhenEmpty && ((DataContainer)val).Count == 0)
				{
					((DataContainer)currentContract).Remove(parentKey);
					Log.Debug($"Dawn contract child container deleted for {parentKey}");
				}
			}
			return true;
		}

		private static bool CanWrite()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			return singleton != null && singleton.IsServer;
		}
	}
	public class DawnContractSync
	{
		private const float DelaySeconds = 1.25f;

		private static readonly WaitForSeconds DelayWait = new WaitForSeconds(1.25f);

		private readonly NamespacedKey dataKey;

		private readonly NamespacedKey requestKey;

		private readonly Func<string> writeData;

		private readonly Action<string> readData;

		private readonly bool saveOnGameSaved;

		private Coroutine? hostCoroutine;

		private Coroutine? clientCoroutine;

		private MonoBehaviour? hostOwner;

		private MonoBehaviour? clientOwner;

		private string rawData = string.Empty;

		private bool dataReceived;

		private bool listening;

		private bool HostRestoreFinished { get; set; } = true;

		private bool ClientDelayFinished { get; set; }

		public static DawnContractSync Register(NamespacedKey dataKey, Func<string> writeData, Action<string> readData, bool saveOnGameSaved = true)
		{
			DawnContractSync dawnContractSync = new DawnContractSync(dataKey, writeData, readData, saveOnGameSaved);
			dawnContractSync.Enable();
			return dawnContractSync;
		}

		public DawnContractSync(NamespacedKey dataKey, Func<string> writeData, Action<string> readData, bool saveOnGameSaved = true)
		{
			this.dataKey = dataKey ?? throw new ArgumentNullException("dataKey");
			requestKey = RequestKey(dataKey);
			this.writeData = writeData ?? throw new ArgumentNullException("writeData");
			this.readData = readData ?? throw new ArgumentNullException("readData");
			this.saveOnGameSaved = saveOnGameSaved;
		}

		public void Enable()
		{
			if (listening)
			{
				Log.Debug($"Dawn contract sync enable skipped because it is already enabled for {dataKey}");
				return;
			}
			listening = true;
			HatNet.Init();
			HatNet.RegisterClient(dataKey, DataReceived);
			HatNet.RegisterServer(requestKey, RequestReceived);
			RoundEvents.OnShipItemsLoaded += ShipItemsLoaded;
			RoundEvents.OnShipUnlockablesSynced += ShipUnlockablesSynced;
			RoundEvents.OnLocalDisconnect += Clear;
			RoundEvents.OnDestroy += Clear;
			if (saveOnGameSaved)
			{
				RoundEvents.OnGameSaved += SaveGame;
			}
			Log.Debug($"Dawn contract sync enabled for {dataKey}");
		}

		public void Disable()
		{
			if (!listening)
			{
				Log.Debug($"Dawn contract sync disable skipped because it is already disabled for {dataKey}");
				return;
			}
			listening = false;
			HatNet.UnregisterClient(dataKey, DataReceived);
			HatNet.UnregisterServer(requestKey, RequestReceived);
			RoundEvents.OnShipItemsLoaded -= ShipItemsLoaded;
			RoundEvents.OnShipUnlockablesSynced -= ShipUnlockablesSynced;
			RoundEvents.OnLocalDisconnect -= Clear;
			RoundEvents.OnDestroy -= Clear;
			RoundEvents.OnGameSaved -= SaveGame;
			Clear();
			Log.Debug($"Dawn contract sync disabled for {dataKey}");
		}

		public bool Save()
		{
			return Save(writeData() ?? string.Empty);
		}

		public bool Save(string data)
		{
			if (!HostRestoreFinished)
			{
				Log.Debug($"Dawn contract sync save skipped because restore is still running for {dataKey}");
				return false;
			}
			string raw = data ?? string.Empty;
			if (!DawnContractData.WriteString(dataKey, raw))
			{
				Log.Warn($"Dawn contract sync data could not be saved for {dataKey}");
				return false;
			}
			rawData = raw;
			dataReceived = true;
			Log.Debug($"Dawn contract sync data saved for {dataKey}");
			return true;
		}

		public bool SaveAndPublish()
		{
			if (!Save())
			{
				return false;
			}
			if (PublishRaw(rawData))
			{
				Log.Debug($"Dawn contract sync data saved and published for {dataKey}");
				return true;
			}
			Log.Warn($"Dawn contract sync data was saved but not published for {dataKey}");
			return false;
		}

		public bool Delete()
		{
			if (!HostRestoreFinished)
			{
				Log.Debug($"Dawn contract sync delete skipped because restore is still running for {dataKey}");
				return false;
			}
			if (!DawnContractData.Delete(dataKey))
			{
				Log.Warn($"Dawn contract sync data could not be deleted for {dataKey}");
				return false;
			}
			rawData = string.Empty;
			dataReceived = true;
			Log.Debug($"Dawn contract sync data deleted for {dataKey}");
			return true;
		}

		public bool Publish()
		{
			if (HostRestoreFinished)
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (singleton != null && singleton.IsServer)
				{
					rawData = writeData() ?? string.Empty;
					dataReceived = true;
					if (PublishRaw(rawData))
					{
						Log.Debug($"Dawn contract sync data published for {dataKey}");
						return true;
					}
					Log.Warn($"Dawn contract sync data could not be published for {dataKey}");
					return false;
				}
			}
			Log.Debug($"Dawn contract sync publish skipped for {dataKey}");
			return false;
		}

		public bool Request()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton == null || !singleton.IsListening)
			{
				Log.Debug($"Dawn contract sync request skipped because networking is unavailable for {dataKey}");
				return false;
			}
			if (HatNet.SendToServer(requestKey, string.Empty))
			{
				Log.Debug($"Dawn contract sync data requested for {dataKey}");
				return true;
			}
			Log.Warn($"Dawn contract sync data could not be requested for {dataKey}");
			return false;
		}

		internal void Clear()
		{
			StopHostCoroutine();
			StopClientCoroutine();
			HostRestoreFinished = true;
			ClientDelayFinished = false;
			rawData = string.Empty;
			dataReceived = false;
			Log.Debug($"Dawn contract sync transient data cleared for {dataKey}");
		}

		private static NamespacedKey RequestKey(NamespacedKey key)
		{
			return NamespacedKey.From(key.Namespace, key.Key + "_request");
		}

		private void SaveGame()
		{
			Save();
		}

		private void ShipItemsLoaded(StartOfRound startOfRound)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton != null && singleton.IsServer)
			{
				StopHostCoroutine();
				HostRestoreFinished = false;
				hostOwner = (MonoBehaviour?)(object)startOfRound;
				hostCoroutine = ((MonoBehaviour)startOfRound).StartCoroutine(HostRestoreAfterDelay());
				Log.Debug($"Dawn contract sync restore scheduled for {dataKey}");
			}
		}

		private void ShipUnlockablesSynced(StartOfRound startOfRound)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton == null || !singleton.IsServer)
			{
				StopClientCoroutine();
				ClientDelayFinished = false;
				clientOwner = (MonoBehaviour?)(object)startOfRound;
				clientCoroutine = ((MonoBehaviour)startOfRound).StartCoroutine(ClientRestoreAfterDelay());
				Log.Debug($"Dawn contract sync client restore scheduled for {dataKey}");
			}
		}

		private void Clear(StartOfRound startOfRound)
		{
			Clear();
		}

		private void RequestReceived(ulong senderClientId, string data)
		{
			if (!HostRestoreFinished)
			{
				return;
			}
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton != null && singleton.IsServer)
			{
				rawData = writeData() ?? string.Empty;
				dataReceived = true;
				if (HatNet.SendToClient(dataKey, senderClientId, rawData))
				{
					Log.Debug($"Dawn contract sync request answered for {dataKey}");
				}
			}
		}

		private void DataReceived(ulong senderClientId, string data)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton == null || !singleton.IsServer)
			{
				ReceiveData(data);
			}
		}

		private void ReceiveData(string data)
		{
			rawData = data ?? string.Empty;
			dataReceived = true;
			Log.Debug($"Dawn contract sync data received for {dataKey}");
			if (ClientDelayFinished)
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (singleton == null || !singleton.IsServer)
				{
					readData(rawData);
				}
			}
		}

		private IEnumerator HostRestoreAfterDelay()
		{
			yield return DelayWait;
			string savedData;
			bool loaded = DawnContractData.LoadString(dataKey, out savedData) && savedData != null;
			string contractData = (rawData = (loaded ? savedData : string.Empty));
			dataReceived = true;
			readData(contractData);
			if (loaded)
			{
				Log.Debug($"Dawn contract sync data loaded for {dataKey}");
			}
			else
			{
				Log.Debug($"Dawn contract sync data was missing for {dataKey}");
			}
			rawData = writeData() ?? string.Empty;
			PublishRaw(rawData);
			HostRestoreFinished = true;
			hostCoroutine = null;
			hostOwner = null;
			Log.Debug($"Dawn contract sync restore finished for {dataKey}");
		}

		private IEnumerator ClientRestoreAfterDelay()
		{
			yield return DelayWait;
			ClientDelayFinished = true;
			clientCoroutine = null;
			clientOwner = null;
			if (dataReceived)
			{
				readData(rawData);
				Log.Debug($"Dawn contract sync client data applied for {dataKey}");
			}
			else
			{
				Request();
			}
		}

		private bool PublishRaw(string data)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if (singleton == null || !singleton.IsServer)
			{
				return false;
			}
			return HatNet.SendToClients(dataKey, data ?? string.Empty);
		}

		private void StopHostCoroutine()
		{
			if (hostCoroutine != null && !((Object)(object)hostOwner == (Object)null))
			{
				hostOwner.StopCoroutine(hostCoroutine);
				hostCoroutine = null;
				hostOwner = null;
				Log.Debug($"Dawn contract sync restore stopped for {dataKey}");
			}
		}

		private void StopClientCoroutine()
		{
			if (clientCoroutine != null && !((Object)(object)clientOwner == (Object)null))
			{
				clientOwner.StopCoroutine(clientCoroutine);
				clientCoroutine = null;
				clientOwner = null;
				Log.Debug($"Dawn contract sync client restore stopped for {dataKey}");
			}
		}
	}
	public static class DawnFindResource
	{
		public static void Add<TInfo>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Action<TInfo> apply) where TInfo : INamespaced<TInfo>
		{
			if (registry == null)
			{
				Log.Error($"Dawn resource registry was missing for {key}");
				return;
			}
			if (apply == null)
			{
				Log.Error($"Dawn resource request was missing for {key}");
				return;
			}
			DawnFindResource.OnFreeze<TInfo>(registry, (Action)delegate
			{
				if (DawnFindResource.Get<TInfo>(registry, key, out TInfo info))
				{
					apply(info);
					Log.Debug($"Dawn resource request applied for {key}");
				}
			});
			Log.Debug($"Dawn resource request added for {key}");
		}

		public static void Add<TInfo, TValue>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Func<TInfo, TValue?> read, Action<TValue> apply) where TInfo : INamespaced<TInfo> where TValue : class
		{
			DawnFindResource.Add<TInfo, TValue>(registry, key, read, typeof(TValue).Name, apply);
		}

		public static void Add<TInfo, TValue>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Func<TInfo, TValue?> read, string name, Action<TValue> apply) where TInfo : INamespaced<TInfo> where TValue : class
		{
			if (registry == null)
			{
				Log.Error("Dawn resource registry was missing for " + name);
				return;
			}
			if (read == null)
			{
				Log.Error("Dawn resource lookup was missing for " + name);
				return;
			}
			if (apply == null)
			{
				Log.Error("Dawn resource request was missing for " + name);
				return;
			}
			DawnFindResource.OnFreeze<TInfo>(registry, (Action)delegate
			{
				if (DawnFindResource.Get<TInfo, TValue>(registry, key, read, name, out TValue value))
				{
					apply(value);
					Log.Debug("Dawn resource request applied for " + name);
				}
			});
			Log.Debug("Dawn resource request added for " + name);
		}

		public static void OnFreeze<TInfo>(Registry<TInfo> registry, Action action) where TInfo : INamespaced<TInfo>
		{
			if (registry == null)
			{
				Log.Error("Dawn registry was missing for " + typeof(TInfo).Name);
			}
			else if (action == null)
			{
				Log.Error("Dawn registry freeze action was missing for " + typeof(TInfo).Name);
			}
			else if (registry.IsFrozen)
			{
				Log.Debug("Dawn registry was already frozen for " + typeof(TInfo).Name);
				action();
			}
			else
			{
				registry.OnFreeze += action;
				Log.Debug("Dawn registry freeze action added for " + typeof(TInfo).Name);
			}
		}

		public static bool Get<TInfo>(Registry<TInfo> registry, NamespacedKey<TInfo> key, out TInfo info) where TInfo : INamespaced<TInfo>
		{
			info = default(TInfo);
			if (registry == null)
			{
				Log.Error($"Dawn resource registry was missing for {key}");
				return false;
			}
			if (registry.TryGetValue(key, ref info))
			{
				Log.Debug($"Dawn resource found for {key}");
				return true;
			}
			info = default(TInfo);
			Log.Warn($"Dawn resource was not found for {key}");
			return false;
		}

		public static bool Get<TInfo, TValue>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Func<TInfo, TValue?> read, out TValue value) where TInfo : INamespaced<TInfo> where TValue : class
		{
			return DawnFindResource.Get<TInfo, TValue>(registry, key, read, typeof(TValue).Name, out value);
		}

		public static bool Get<TInfo, TValue>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Func<TInfo, TValue?> read, string name, out TValue value) where TInfo : INamespaced<TInfo> where TValue : class
		{
			value = null;
			if (read == null)
			{
				Log.Error("Dawn resource lookup was missing for " + name);
				return false;
			}
			if (!DawnFindResource.Get<TInfo>(registry, key, out TInfo info))
			{
				return false;
			}
			TValue val = read(info);
			if (Missing(val))
			{
				Log.Warn("Dawn resource value was not found for " + name);
				return false;
			}
			value = val;
			Log.Debug("Dawn resource value found for " + name);
			return true;
		}

		private static bool Missing<TValue>([NotNullWhen(false)] TValue? value) where TValue : class
		{
			if (value == null)
			{
				return true;
			}
			Object val = (Object)(object)((value is Object) ? value : null);
			if (val != null && val == (Object)null)
			{
				return true;
			}
			return false;
		}
	}
	public class DuskConfigInjector(string dawnModGUID)
	{
		public readonly string dawnModGUID = dawnModGUID;

		public static T Get<T>(string dawnModGUID, string settingName)
		{
			if (string.IsNullOrWhiteSpace(dawnModGUID))
			{
				Log.Error("Dusk config read failed because the Dawn mod GUID was empty");
				return default(T);
			}
			if (string.IsNullOrWhiteSpace(settingName))
			{
				Log.Error("Dusk config read failed because the setting name was empty");
				return default(T);
			}
			DuskMod val = ((IEnumerable<DuskMod>)DuskMod.AllMods).FirstOrDefault((Func<DuskMod, bool>)((DuskMod duskMod) => duskMod.Plugin.GUID == dawnModGUID));
			if (val == null)
			{
				Log.Warn("Dusk config read failed because Dawn mod GUID '" + dawnModGUID + "' was not found");
				return default(T);
			}
			ConfigEntryBase val2 = ((IEnumerable<ConfigEntryBase>)val.ConfigEntries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase configEntry) => configEntry.Definition.Key == settingName));
			if (val2 == null)
			{
				Log.Warn("Dusk config setting '" + settingName + "' was not found");
				return default(T);
			}
			if (!(val2 is ConfigEntry<T> val3))
			{
				Log.Error("Dusk config setting '" + settingName + "' was not a " + typeof(T).Name);
				return default(T);
			}
			return val3.Value;
		}

		public ConfigEntry<T>? Bind<T>(string section, string settingName, T defaultValue, string description)
		{
			if (string.IsNullOrWhiteSpace(dawnModGUID))
			{
				Log.Error("DuskConfigInjector was created with an empty dawnModGUID");
				return null;
			}
			if (string.IsNullOrWhiteSpace(section))
			{
				Log.Error("Dusk config section was empty");
				return null;
			}
			if (string.IsNullOrWhiteSpace(settingName))
			{
				Log.Error("Dusk config key was empty");
				return null;
			}
			DuskMod val = ((IEnumerable<DuskMod>)DuskMod.AllMods).FirstOrDefault((Func<DuskMod, bool>)((DuskMod duskMod) => duskMod.Plugin.GUID == dawnModGUID));
			if (val == null)
			{
				Log.Warn("Dusk GUID was not found for '" + dawnModGUID + "'");
				return null;
			}
			ConfigContext val2 = val.ConfigManager.CreateConfigSection(section);
			try
			{
				return val2.Bind<T>(settingName, description, defaultValue);
			}
			finally
			{
				((IDisposable)val2)?.Dispose();
			}
		}
	}
	public static class FindItems
	{
		public static NamespacedKey<DawnItemInfo>? DawnKey(GrabbableObject item)
		{
			if ((Object)(object)item == (Object)null)
			{
				Log.Warn("Dawn item key read skipped because item was missing");
				return null;
			}
			if ((Object)(object)item.itemProperties == (Object)null)
			{
				Log.Warn("Dawn item key read skipped because item properties were missing");
				return null;
			}
			return ((DawnBaseInfo<DawnItemInfo>)(object)ItemExtensions.GetDawnInfo(item.itemProperties))?.TypedKey;
		}

		public static bool MatchesDawnKey(GrabbableObject item, NamespacedKey<DawnItemInfo> itemKey)
		{
			if (itemKey == null)
			{
				Log.Warn("Dawn item match skipped because item key was missing");
				return false;
			}
			return ((object)DawnKey(item))?.Equals((object?)itemKey) ?? false;
		}

		public static List<GrabbableObject> Active(Func<GrabbableObject, bool>? itemFilter = null)
		{
			GrabbableObject[] array = Object.FindObjectsByType<GrabbableObject>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			List<GrabbableObject> list = new List<GrabbableObject>();
			foreach (GrabbableObject val in array)
			{
				if (itemFilter == null || itemFilter(val))
				{
					list.Add(val);
				}
			}
			Log.Debug($"{list.Count} items found");
			return list;
		}

		public static List<GrabbableObject> Active(NamespacedKey<DawnItemInfo> itemKey, Func<GrabbableObject, bool>? itemFilter = null)
		{
			List<GrabbableObject> list = Active((Func<GrabbableObject, bool>?)((GrabbableObject item) => MatchesDawnKey(item, itemKey) && (itemFilter == null || itemFilter(item))));
			Log.Debug($"{list.Count} Dawn items found");
			return list;
		}

		public static GrabbableObject? ClosestTo(Vector3 position, float radius, Func<GrabbableObject, bool>? itemFilter = null)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject[] items = Object.FindObjectsByType<GrabbableObject>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			GrabbableObject val = ClosestTo(position, radius, items, itemFilter);
			Log.Debug(((Object)(object)val == (Object)null) ? "Closest item was not found" : "Closest item found");
			return val;
		}

		public static GrabbableObject? ClosestTo(NamespacedKey<DawnItemInfo> itemKey, Vector3 position, float radius, Func<GrabbableObject, bool>? itemFilter = null)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject[] items = Object.FindObjectsByType<GrabbableObject>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			GrabbableObject val = ClosestTo(itemKey, position, radius, items, itemFilter);
			Log.Debug(((Object)(object)val == (Object)null) ? "Closest Dawn item was not found" : "Closest Dawn item found");
			return val;
		}

		public static GrabbableObject? ClosestTo(Vector3 position, float radius, IReadOnlyList<GrabbableObject> items, Func<GrabbableObject, bool>? itemFilter = null)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			float num = radius * radius;
			GrabbableObject val = null;
			for (int i = 0; i < items.Count; i++)
			{
				GrabbableObject val2 = items[i];
				if (!((Object)(object)val2 == (Object)null) && (itemFilter == null || itemFilter(val2)))
				{
					Vector3 val3 = ((Component)val2).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (!(sqrMagnitude >= num))
					{
						num = sqrMagnitude;
						val = val2;
					}
				}
			}
			Log.Debug(((Object)(object)val == (Object)null) ? "Closest item was not found" : "Closest item found");
			return val;
		}

		public static GrabbableObject? ClosestTo(NamespacedKey<DawnItemInfo> itemKey, Vector3 position, float radius, IReadOnlyList<GrabbableObject> items, Func<GrabbableObject, bool>? itemFilter = null)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject val = ClosestTo(position, radius, items, (GrabbableObject item) => MatchesDawnKey(item, itemKey) && (itemFilter == null || itemFilter(item)));
			Log.Debug(((Object)(object)val == (Object)null) ? "Closest Dawn item was not found" : "Closest Dawn item found");
			return val;
		}
	}
	public delegate void HatNetMessageHandler(ulong senderClientId, string data);
	public static class HatNet
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__ServerMessageReceived;

			public static HandleNamedMessageDelegate <1>__ClientMessageReceived;
		}

		private const string ServerMessageName = "MrHat.Lib.HatNet.Server";

		private const string ClientMessageName = "MrHat.Lib.HatNet.Client";

		private static readonly Dictionary<string, List<HatNetMessageHandler>> ServerHandlers = new Dictionary<string, List<HatNetMessageHandler>>(StringComparer.Ordinal);

		private static readonly Dictionary<string, List<HatNetMessageHandler>> ClientHandlers = new Dictionary<string, List<HatNetMessageHandler>>(StringComparer.Ordinal);

		private static NetworkManager? registeredManager;

		private static bool registeredMessages;

		internal static void Init()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if (((singleton != null) ? singleton.CustomMessagingManager : null) != null && (!registeredMessages || !((Object)(object)registeredManager == (Object)(object)singleton)))
			{
				Shutdown();
				registeredManager = singleton;
				registeredMessages = true;
				CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
				object obj = <>O.<0>__ServerMessageReceived;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = ServerMessageReceived;
					<>O.<0>__ServerMessageReceived = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("MrHat.Lib.HatNet.Server", (HandleNamedMessageDelegate)obj);
				CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager;
				object obj2 = <>O.<1>__ClientMessageReceived;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = ClientMessageReceived;
					<>O.<1>__ClientMessageReceived = val2;
					obj2 = (object)val2;
				}
				customMessagingManager2.RegisterNamedMessageHandler("MrHat.Lib.HatNet.Client", (HandleNamedMessageDelegate)obj2);
				Log.Info("HatNet messages registered");
			}
		}

		internal static void Shutdown()
		{
			if (registeredMessages)
			{
				NetworkManager? obj = registeredManager;
				if (((obj != null) ? obj.CustomMessagingManager : null) != null)
				{
					registeredManager.CustomMessagingManager.UnregisterNamedMessageHandler("MrHat.Lib.HatNet.Server");
					registeredManager.CustomMessagingManager.UnregisterNamedMessageHandler("MrHat.Lib.HatNet.Client");
					registeredManager = null;
					registeredMessages = false;
					Log.Info("HatNet messages unregistered");
					return;
				}
			}
			registeredManager = null;
			registeredMessages = false;
		}

		public static void RegisterServer(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Register(ServerHandlers, key, handler))
			{
				Log.Debug($"HatNet server registered for {key}");
			}
		}

		public static void RegisterClient(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Register(ClientHandlers, key, handler))
			{
				Log.Debug($"HatNet client registered for {key}");
			}
		}

		public static void UnregisterServer(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Unregister(ServerHandlers, key, handler))
			{
				Log.Debug($"HatNet server unregistered for {key}");
			}
		}

		public static void UnregisterClient(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Unregister(ClientHandlers, key, handler))
			{
				Log.Debug($"HatNet client unregistered for {key}");
			}
		}

		public unsafe static bool SendToServer(NamespacedKey key, string data)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Init();
			NetworkManager val = registeredManager ?? NetworkManager.Singleton;
			if (val == null || !val.IsListening || val.CustomMessagingManager == null)
			{
				Log.Debug("HatNet server message was not sent because networking is unavailable");
				return false;
			}
			FastBufferWriter val2 = CreateWriter(key, data);
			try
			{
				val.CustomMessagingManager.SendNamedMessage("MrHat.Lib.HatNet.Server", 0uL, val2, (NetworkDelivery)4);
				return true;
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		public unsafe static bool SendToClients(NamespacedKey key, string data)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			Init();
			NetworkManager val = registeredManager ?? NetworkManager.Singleton;
			if (val == null || !val.IsListening || !val.IsServer || val.CustomMessagingManager == null)
			{
				Log.Debug("HatNet client message was not sent because the server is unavailable");
				return false;
			}
			FastBufferWriter val2 = CreateWriter(key, data);
			try
			{
				val.CustomMessagingManager.SendNamedMessageToAll("MrHat.Lib.HatNet.Client", val2, (NetworkDelivery)4);
				return true;
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		public unsafe static bool SendToClient(NamespacedKey key, ulong clientId, string data)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			Init();
			NetworkManager val = registeredManager ?? NetworkManager.Singleton;
			if (val == null || !val.IsListening || !val.IsServer || val.CustomMessagingManager == null)
			{
				Log.Debug("HatNet client message was not sent because the server is unavailable");
				return false;
			}
			FastBufferWriter val2 = CreateWriter(key, data);
			try
			{
				val.CustomMessagingManager.SendNamedMessage("MrHat.Lib.HatNet.Client", clientId, val2, (NetworkDelivery)4);
				return true;
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static bool Register(Dictionary<string, List<HatNetMessageHandler>> handlers, NamespacedKey key, HatNetMessageHandler handler)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (handler == null)
			{
				throw new ArgumentNullException("handler");
			}
			string key2 = ((object)key).ToString();
			if (!handlers.TryGetValue(key2, out List<HatNetMessageHandler> value))
			{
				value = (handlers[key2] = new List<HatNetMessageHandler>());
			}
			if (value.Contains(handler))
			{
				return false;
			}
			value.Add(handler);
			return true;
		}

		private static bool Unregister(Dictionary<string, List<HatNetMessageHandler>> handlers, NamespacedKey key, HatNetMessageHandler handler)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			if (handler == null)
			{
				throw new ArgumentNullException("handler");
			}
			string key2 = ((object)key).ToString();
			if (!handlers.TryGetValue(key2, out List<HatNetMessageHandler> value))
			{
				return false;
			}
			if (!value.Remove(handler))
			{
				return false;
			}
			if (value.Count == 0)
			{
				handlers.Remove(key2);
			}
			return true;
		}

		private static FastBufferWriter CreateWriter(NamespacedKey key, string data)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			string text = ((object)key).ToString();
			string text2 = data ?? string.Empty;
			int num = Math.Max(64, text.Length * 4 + text2.Length * 4 + 64);
			FastBufferWriter result = default(FastBufferWriter);
			((FastBufferWriter)(ref result))..ctor(num, (Allocator)2, -1);
			((FastBufferWriter)(ref result)).WriteValueSafe(text, false);
			((FastBufferWriter)(ref result)).WriteValueSafe(text2, false);
			return result;
		}

		private static void ServerMessageReceived(ulong senderClientId, FastBufferReader reader)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			MessageReceived(senderClientId, reader, ServerHandlers);
		}

		private static void ClientMessageReceived(ulong senderClientId, FastBufferReader reader)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			MessageReceived(senderClientId, reader, ClientHandlers);
		}

		private static void MessageReceived(ulong senderClientId, FastBufferReader reader, Dictionary<string, List<HatNetMessageHandler>> handlers)
		{
			string text = default(string);
			((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false);
			string data = default(string);
			((FastBufferReader)(ref reader)).ReadValueSafe(ref data, false);
			if (!handlers.TryGetValue(text, out List<HatNetMessageHandler> value))
			{
				Log.Debug("HatNet message ignored because no handler is registered for " + text);
				return;
			}
			HatNetMessageHandler[] array = value.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				array[i](senderClientId, data);
			}
		}
	}
	public static class LocalPlayerCollider
	{
		public static Collider? Current()
		{
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			PlayerControllerB localPlayerController = instance.localPlayerController;
			if ((Object)(object)localPlayerController == (Object)null)
			{
				return null;
			}
			return localPlayerController.playerCollider;
		}

		public static bool Matches(Collider other)
		{
			if ((Object)(object)other == (Object)null)
			{
				return false;
			}
			return (Object)(object)other == (Object)(object)Current();
		}
	}
	[DisallowMultipleComponent]
	public class LocalPlayerTrigger : MonoBehaviour
	{
		private Collider? playerCollider;

		private bool playerInside;

		public Collider? PlayerCollider => playerCollider ?? (playerCollider = LocalPlayerCollider.Current());

		public bool PlayerInside => playerInside;

		public event Action<Collider>? Entered;

		public event Action<Collider>? Exited;

		public static LocalPlayerTrigger? Arm(Collider? bounds)
		{
			if ((Object)(object)bounds == (Object)null)
			{
				return null;
			}
			bounds.isTrigger = true;
			Rigidbody val = ((Component)bounds).gameObject.GetComponent<Rigidbody>() ?? ((Component)bounds).gameObject.AddComponent<Rigidbody>();
			val.isKinematic = false;
			val.useGravity = false;
			val.constraints = (RigidbodyConstraints)126;
			LocalPlayerTrigger result = default(LocalPlayerTrigger);
			if (!((Component)bounds).TryGetComponent<LocalPlayerTrigger>(ref result))
			{
				result = ((Component)bounds).gameObject.AddComponent<LocalPlayerTrigger>();
			}
			return result;
		}

		private void OnDisable()
		{
			playerInside = false;
		}

		private void OnDestroy()
		{
			this.Entered = null;
			this.Exited = null;
			playerCollider = null;
			playerInside = false;
		}

		private void OnTriggerEnter(Collider other)
		{
			MarkEntered(other);
		}

		private void OnTriggerStay(Collider other)
		{
			MarkEntered(other);
		}

		private void OnTriggerExit(Collider other)
		{
			if (MatchesPlayer(other))
			{
				playerInside = false;
				this.Exited?.Invoke(other);
			}
		}

		private void MarkEntered(Collider other)
		{
			if (!playerInside && MatchesPlayer(other))
			{
				playerInside = true;
				this.Entered?.Invoke(other);
			}
		}

		private bool MatchesPlayer(Collider other)
		{
			if ((Object)(object)other == (Object)null)
			{
				return false;
			}
			Collider val = LocalPlayerCollider.Current();
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)playerCollider)
			{
				playerCollider = val;
			}
			return (Object)(object)other == (Object)(object)playerCollider;
		}
	}
	[Serializable]
	public class PlayerAnimatorControllerReplacement
	{
		public RuntimeAnimatorController animatorController = null;

		public RuntimeAnimatorController remoteAnimatorController = null;
	}
	public class PlayerAnimatorTools
	{
		private static readonly int SprintingHash = Animator.StringToHash("Sprinting");

		private static readonly int JumpingHash = Animator.StringToHash("Jumping");

		private static readonly int WalkingHash = Animator.StringToHash("Walking");

		private static readonly int CrouchingHash = Animator.StringToHash("crouching");

		private static readonly string[] RequiredPlayerLayers = new string[5] { "UpperBodyEmotes", "EmotesNoArms", "HoldingItemsRightHand", "HoldingItemsBothHands", "SpecialAnimations" };

		private Animator? animator;

		private RuntimeAnimatorController? originalController;

		private RuntimeAnimatorController? replacementController;

		public bool IsActive { get; private set; }

		public bool ApplyHeld(PlayerControllerB? player, PlayerAnimatorControllerReplacement? replacement)
		{
			if (IsActive)
			{
				return true;
			}
			if ((Object)(object)player == (Object)null || replacement == null)
			{
				return false;
			}
			RuntimeAnimatorController targetController = (((Object)(object)player == (Object)(object)GameNetworkManager.Instance.localPlayerController) ? replacement.animatorController : replacement.remoteAnimatorController);
			return Apply(player.playerBodyAnimator, targetController);
		}

		public bool Apply(Animator? targetAnimator, RuntimeAnimatorController? targetController)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (IsActive)
			{
				return true;
			}
			if ((Object)(object)targetAnimator == (Object)null || (Object)(object)targetController == (Object)null)
			{
				return false;
			}
			animator = targetAnimator;
			originalController = targetAnimator.runtimeAnimatorController;
			replacementController = targetController;
			AnimatorStateInfo currentAnimatorStateInfo = targetAnimator.GetCurrentAnimatorStateInfo(0);
			float normalizedTime = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime;
			bool flag = targetAnimator.GetBool(CrouchingHash);
			bool flag2 = targetAnimator.GetBool(WalkingHash);
			bool flag3 = targetAnimator.GetBool(JumpingHash);
			bool flag4 = targetAnimator.GetBool(SprintingHash);
			targetAnimator.runtimeAnimatorController = targetController;
			for (int i = 0; i < RequiredPlayerLayers.Length; i++)
			{
				if (targetAnimator.GetLayerIndex(RequiredPlayerLayers[i]) < 0)
				{
					targetAnimator.runtimeAnimatorController = originalController;
					Log.Warn("Player animator replacement missing layer " + RequiredPlayerLayers[i]);
					animator = null;
					originalController = null;
					replacementController = null;
					return false;
				}
			}
			targetAnimator.Rebind();
			targetAnimator.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, 0, normalizedTime);
			targetAnimator.SetBool(CrouchingHash, flag);
			targetAnimator.SetBool(WalkingHash, flag2);
			targetAnimator.SetBool(JumpingHash, flag3);
			targetAnimator.SetBool(SprintingHash, flag4);
			targetAnimator.Update(0f);
			IsActive = true;
			return true;
		}

		public void Restore()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (IsActive)
			{
				if ((Object)(object)animator != (Object)null && (Object)(object)animator.runtimeAnimatorController == (Object)(object)replacementController)
				{
					AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
					float normalizedTime = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime;
					bool flag = animator.GetBool(CrouchingHash);
					bool flag2 = animator.GetBool(WalkingHash);
					bool flag3 = animator.GetBool(JumpingHash);
					bool flag4 = animator.GetBool(SprintingHash);
					animator.runtimeAnimatorController = originalController;
					animator.Rebind();
					animator.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, 0, normalizedTime);
					animator.SetBool(CrouchingHash, flag);
					animator.SetBool(WalkingHash, flag2);
					animator.SetBool(JumpingHash, flag3);
					animator.SetBool(SprintingHash, flag4);
					animator.Update(0f);
				}
				animator = null;
				originalController = null;
				replacementController = null;
				IsActive = false;
			}
		}
	}
	public abstract class PlayerAnimatorReplacement : GrabbableObject
	{
		[Header("Player Animator")]
		[SerializeField]
		private PlayerAnimatorControllerReplacement playerAnimator = new PlayerAnimatorControllerReplacement();

		private readonly PlayerAnimatorTools playerAnimatorTools = new PlayerAnimatorTools();

		protected bool ApplyHeldPlayerAnimator()
		{
			return playerAnimatorTools.ApplyHeld(base.playerHeldBy, playerAnimator);
		}

		protected void RestoreHeldPlayerAnimator()
		{
			playerAnimatorTools.Restore();
		}

		protected override void __initializeVariables()
		{
			((GrabbableObject)this).__initializeVariables();
		}

		protected override void __initializeRpcs()
		{
			((GrabbableObject)this).__initializeRpcs();
		}

		protected internal override string __getTypeName()
		{
			return "PlayerAnimatorReplacement";
		}
	}
	public static class UnlockableTools
	{
		public static bool Bought(NamespacedKey<DawnUnlockableItemInfo> key)
		{
			if (key == null)
			{
				Log.Warn("Dawn unlockable bought check skipped because key was missing");
				return false;
			}
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				Log.Debug($"Dawn unlockable bought check skipped because no round exists for {key}");
				return false;
			}
			List<UnlockableItem> list = instance.unlockablesList?.unlockables;
			if (list == null)
			{
				Log.Debug($"Dawn unlockable bought check skipped because no unlockable list exists for {key}");
				return false;
			}
			for (int i = 0; i < list.Count; i++)
			{
				UnlockableItem val = list[i];
				if (val == null)
				{
					continue;
				}
				DawnUnlockableItemInfo dawnInfo = UnlockableItemExtensions.GetDawnInfo(val);
				if (dawnInfo != null && ((object)((DawnBaseInfo<DawnUnlockableItemInfo>)(object)dawnInfo).TypedKey).Equals((object?)key))
				{
					if (val.hasBeenUnlockedByPlayer)
					{
						Log.Debug($"Dawn unlockable bought check passed for {key}");
						return true;
					}
					Log.Debug($"Dawn unlockable bought check failed because unlockable is locked for {key}");
					return false;
				}
			}
			Log.Debug($"Dawn unlockable bought check failed because unlockable was not found for {key}");
			return false;
		}

		public static bool Bought(string namespacedKey)
		{
			if (string.IsNullOrWhiteSpace(namespacedKey))
			{
				Log.Warn("Dawn unlockable bought check skipped because key string was empty");
				return false;
			}
			NamespacedKey val = default(NamespacedKey);
			if (!NamespacedKey.TryParse(namespacedKey, ref val))
			{
				Log.Warn("Dawn unlockable bought check skipped because key string could not be parsed for " + namespacedKey);
				return false;
			}
			return Bought(val.AsTyped<DawnUnlockableItemInfo>());
		}
	}
}
namespace HatLib.Patches
{
	[HarmonyPatch(typeof(GameNetworkManager))]
	internal static class GameNetworkManagerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix()
		{
			HatNet.Init();
		}

		[HarmonyPostfix]
		[HarmonyPatch("SaveGame")]
		private static void SaveGamePostfix()
		{
			RoundEvents.GameSaved();
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(StartOfRound __instance)
		{
			RoundEvents.RoundStart(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("EndOfGameClientRpc")]
		private static void EndOfGameClientRpcPostfix(StartOfRound __instance)
		{
			RoundEvents.RoundEnd(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("ShipHasLeft")]
		private static void ShipHasLeftPostfix(StartOfRound __instance)
		{
			RoundEvents.ShipLeft(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetShipReadyToLand")]
		private static void SetShipReadyToLandPostfix(StartOfRound __instance)
		{
			RoundEvents.ShipReadyToLand(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("LoadShipGrabbableItems")]
		private static void LoadShipGrabbableItemsPostfix(StartOfRound __instance)
		{
			RoundEvents.ShipItemsLoaded(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("SyncShipUnlockablesClientRpc")]
		private static void SyncShipUnlockablesClientRpcPostfix(StartOfRound __instance)
		{
			RoundEvents.ShipUnlockablesSynced(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("ResetPlayersLoadedValueClientRpc")]
		private static void ResetPlayersLoadedValueClientRpcPostfix(StartOfRound __instance)
		{
			RoundEvents.PlayersLoadedReset(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnLocalDisconnect")]
		private static void OnLocalDisconnectPostfix(StartOfRound __instance)
		{
			RoundEvents.Disconnect(__instance);
			HatNet.Shutdown();
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnDestroy")]
		private static void OnDestroyPostfix(StartOfRound __instance)
		{
			RoundEvents.Destroy(__instance);
			HatNet.Shutdown();
		}
	}
}
namespace __GEN
{
	internal class NetworkVariableSerializationHelper
	{
		[RuntimeInitializeOnLoadMethod]
		internal static void InitializeSerialization()
		{
		}
	}
}
namespace HatLib.NetcodePatcher
{
	[AttributeUsage(AttributeTargets.Module)]
	internal class NetcodePatchedAssemblyAttribute : Attribute
	{
	}
}