Decompiled source of HatLib v0.0.3

HatLib.dll

Decompiled a week 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;
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.3.0")]
[assembly: AssemblyInformationalVersion("0.0.3")]
[assembly: AssemblyProduct("HatLib")]
[assembly: AssemblyTitle("HatLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.3.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;
		}
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("MrHat.Lib", "HatLib", "0.0.3")]
internal class Plugin : BaseUnityPlugin
{
	internal const string modGUID = "MrHat.Lib";

	internal const string modName = "HatLib";

	internal const string modVersion = "0.0.3";

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

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

	private readonly Harmony _harmony = new Harmony("MrHat.Lib");

	internal static ManualLogSource mls;

	internal static Plugin instance;

	private void Awake()
	{
		instance = this;
		mls = Logger.CreateLogSource("MrHat.Lib");
		ConfigManager.Bind(((BaseUnityPlugin)this).Config);
		_harmony.PatchAll(typeof(GameNetworkManagerPatches));
		_harmony.PatchAll(typeof(StartOfRoundPatches));
		mls.LogInfo((object)"HatLib loaded");
	}
}
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);
		}
	}
	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.3";
	}
}
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 DawnSaveData
	{
		public static bool ReadText(NamespacedKey key, out string? raw)
		{
			raw = string.Empty;
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Debug($"Dawn save missing for {key}; no save open");
				return false;
			}
			if (!((DataContainer)currentContract).TryGet<string>(key, ref raw))
			{
				Log.Debug($"Dawn save missing for {key}");
				return false;
			}
			Log.Debug($"Dawn save read for {key}");
			return true;
		}

		public static bool SaveText(NamespacedKey key, string raw)
		{
			return Save(key, raw);
		}

		public static bool Read<T>(NamespacedKey key, out T? value)
		{
			value = default(T);
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Debug($"Dawn save missing for {key}; no save open");
				return false;
			}
			if (!((DataContainer)currentContract).TryGet<T>(key, ref value))
			{
				Log.Debug($"Dawn save missing for {key}");
				return false;
			}
			Log.Debug($"Dawn save read for {key}");
			return true;
		}

		public static bool Save<T>(NamespacedKey key, T value)
		{
			if (value == null)
			{
				Log.Warn($"Dawn save skipped for {key}; value was null");
				return false;
			}
			if (!CanSave())
			{
				Log.Debug($"Dawn save skipped for {key}; host only");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn save skipped for {key}; no save open");
				return false;
			}
			using (((DataContainer)currentContract).CreateEditContext())
			{
				((DataContainer)currentContract).Set<T>(key, value);
			}
			Log.Debug($"Dawn save saved for {key}");
			return true;
		}

		public static bool ReadJson(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 save missing for {parentKey}/{childKey}; no save open");
				return false;
			}
			ChildPersistentDataContainer val = default(ChildPersistentDataContainer);
			if (!((DataContainer)currentContract).TryGet<ChildPersistentDataContainer>(parentKey, ref val))
			{
				Log.Debug($"Dawn save group missing for {parentKey}");
				return false;
			}
			if (!((DataContainer)val).TryGet<JObject>(childKey, ref value))
			{
				Log.Debug($"Dawn save JSON missing for {parentKey}/{childKey}");
				return false;
			}
			Log.Debug($"Dawn save JSON read for {parentKey}/{childKey}");
			return true;
		}

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

		public static bool Read<T>(NamespacedKey parentKey, NamespacedKey childKey, out T? value)
		{
			value = default(T);
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Debug($"Dawn save missing for {parentKey}/{childKey}; no save open");
				return false;
			}
			ChildPersistentDataContainer val = default(ChildPersistentDataContainer);
			if (!((DataContainer)currentContract).TryGet<ChildPersistentDataContainer>(parentKey, ref val))
			{
				Log.Debug($"Dawn save group missing for {parentKey}");
				return false;
			}
			if (!((DataContainer)val).TryGet<T>(childKey, ref value))
			{
				Log.Debug($"Dawn save missing for {parentKey}/{childKey}");
				return false;
			}
			Log.Debug($"Dawn save read for {parentKey}/{childKey}");
			return true;
		}

		public static bool Save<T>(NamespacedKey parentKey, NamespacedKey childKey, T value)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			if (value == null)
			{
				Log.Warn($"Dawn save skipped for {parentKey}/{childKey}; value was null");
				return false;
			}
			if (!CanSave())
			{
				Log.Debug($"Dawn save skipped for {parentKey}/{childKey}; host only");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn save skipped for {parentKey}/{childKey}; no save open");
				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 save group created for {parentKey}");
				}
				((DataContainer)val).Set<T>(childKey, value);
			}
			Log.Debug($"Dawn save saved for {parentKey}/{childKey}");
			return true;
		}

		public static bool Remove(NamespacedKey key)
		{
			if (!CanSave())
			{
				Log.Debug($"Dawn save remove skipped for {key}; host only");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn save remove skipped for {key}; no save open");
				return false;
			}
			using (((DataContainer)currentContract).CreateEditContext())
			{
				((DataContainer)currentContract).Remove(key);
			}
			Log.Debug($"Dawn save removed for {key}");
			return true;
		}

		public static bool Remove(NamespacedKey parentKey, NamespacedKey childKey, bool removeGroupWhenEmpty = false)
		{
			if (!CanSave())
			{
				Log.Debug($"Dawn save remove skipped for {parentKey}/{childKey}; host only");
				return false;
			}
			PersistentDataContainer currentContract = DawnLib.GetCurrentContract();
			if (currentContract == null)
			{
				Log.Warn($"Dawn save remove skipped for {parentKey}/{childKey}; no save open");
				return false;
			}
			using (((DataContainer)currentContract).CreateEditContext())
			{
				ChildPersistentDataContainer val = default(ChildPersistentDataContainer);
				if (!((DataContainer)currentContract).TryGet<ChildPersistentDataContainer>(parentKey, ref val))
				{
					Log.Debug($"Dawn save group missing for {parentKey}");
					return false;
				}
				((DataContainer)val).Remove(childKey);
				Log.Debug($"Dawn save removed for {parentKey}/{childKey}");
				if (removeGroupWhenEmpty && ((DataContainer)val).Count == 0)
				{
					((DataContainer)currentContract).Remove(parentKey);
					Log.Debug($"Dawn save group removed for {parentKey}");
				}
			}
			return true;
		}

		private static bool CanSave()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			return singleton != null && singleton.IsServer;
		}
	}
	public class DawnSaveSync
	{
		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> saveData;

		private readonly Action<string> acceptData;

		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 DawnSaveSync Bind(NamespacedKey dataKey, Func<string> saveData, Action<string> acceptData, bool saveOnGameSaved = true)
		{
			DawnSaveSync dawnSaveSync = new DawnSaveSync(dataKey, saveData, acceptData, saveOnGameSaved);
			dawnSaveSync.Enable();
			return dawnSaveSync;
		}

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

		public void Enable()
		{
			if (listening)
			{
				Log.Debug($"Dawn save sync already enabled for {dataKey}");
				return;
			}
			listening = true;
			HatNet.Init();
			HatNet.AddClientHandler(dataKey, DataReceived);
			HatNet.AddServerHandler(requestKey, RequestReceived);
			RoundEvents.OnShipItemsLoaded += ShipItemsLoaded;
			RoundEvents.OnShipUnlockablesSynced += ShipUnlockablesSynced;
			RoundEvents.OnLocalDisconnect += Clear;
			RoundEvents.OnDestroy += Clear;
			if (saveOnGameSaved)
			{
				RoundEvents.OnGameSaved += SaveGame;
			}
			Log.Debug($"Dawn save sync enabled for {dataKey}");
		}

		public void Disable()
		{
			if (!listening)
			{
				Log.Debug($"Dawn save sync already disabled for {dataKey}");
				return;
			}
			listening = false;
			HatNet.RemoveClientHandler(dataKey, DataReceived);
			HatNet.RemoveServerHandler(requestKey, RequestReceived);
			RoundEvents.OnShipItemsLoaded -= ShipItemsLoaded;
			RoundEvents.OnShipUnlockablesSynced -= ShipUnlockablesSynced;
			RoundEvents.OnLocalDisconnect -= Clear;
			RoundEvents.OnDestroy -= Clear;
			RoundEvents.OnGameSaved -= SaveGame;
			Clear();
			Log.Debug($"Dawn save sync disabled for {dataKey}");
		}

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

		public bool Save(string data)
		{
			if (!HostRestoreFinished)
			{
				Log.Debug($"Dawn save sync save skipped for {dataKey}; restore running");
				return false;
			}
			string raw = data ?? string.Empty;
			if (!DawnSaveData.SaveText(dataKey, raw))
			{
				return false;
			}
			rawData = raw;
			dataReceived = true;
			Log.Debug($"Dawn save sync saved for {dataKey}");
			return true;
		}

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

		public bool Remove()
		{
			if (!HostRestoreFinished)
			{
				Log.Debug($"Dawn save sync remove skipped for {dataKey}; restore running");
				return false;
			}
			if (!DawnSaveData.Remove(dataKey))
			{
				return false;
			}
			rawData = string.Empty;
			dataReceived = true;
			Log.Debug($"Dawn save sync removed for {dataKey}");
			return true;
		}

		public bool Publish()
		{
			if (HostRestoreFinished)
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (singleton != null && singleton.IsServer)
				{
					rawData = saveData() ?? string.Empty;
					dataReceived = true;
					if (PublishRaw(rawData))
					{
						Log.Debug($"Dawn save sync sent for {dataKey}");
						return true;
					}
					Log.Warn($"Dawn save sync send failed for {dataKey}");
					return false;
				}
			}
			Log.Debug($"Dawn save sync send skipped for {dataKey}");
			return false;
		}

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

		internal void Clear()
		{
			StopHostCoroutine();
			StopClientCoroutine();
			HostRestoreFinished = true;
			ClientDelayFinished = false;
			rawData = string.Empty;
			dataReceived = false;
			Log.Debug($"Dawn save sync 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 save 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 save 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 = saveData() ?? string.Empty;
				dataReceived = true;
				if (HatNet.SendToClient(dataKey, senderClientId, rawData))
				{
					Log.Debug($"Dawn save 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 save sync received for {dataKey}");
			if (ClientDelayFinished)
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (singleton == null || !singleton.IsServer)
				{
					acceptData(rawData);
				}
			}
		}

		private IEnumerator HostRestoreAfterDelay()
		{
			yield return DelayWait;
			string savedData;
			bool loaded = DawnSaveData.ReadText(dataKey, out savedData) && savedData != null;
			string savedText = (rawData = (loaded ? savedData : string.Empty));
			dataReceived = true;
			acceptData(savedText);
			if (loaded)
			{
				Log.Debug($"Dawn save sync read for {dataKey}");
			}
			else
			{
				Log.Debug($"Dawn save sync empty for {dataKey}");
			}
			rawData = saveData() ?? string.Empty;
			PublishRaw(rawData);
			HostRestoreFinished = true;
			hostCoroutine = null;
			hostOwner = null;
			Log.Debug($"Dawn save sync restore finished for {dataKey}");
		}

		private IEnumerator ClientRestoreAfterDelay()
		{
			yield return DelayWait;
			ClientDelayFinished = true;
			clientCoroutine = null;
			clientOwner = null;
			if (dataReceived)
			{
				acceptData(rawData);
				Log.Debug($"Dawn save sync client data accepted 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 save 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 save sync client restore stopped for {dataKey}");
			}
		}
	}
	public static class DawnFindResource
	{
		public static void Add<TInfo>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Action<TInfo> assign) where TInfo : INamespaced<TInfo>
		{
			if (registry == null)
			{
				Log.Error($"Dawn resource registry missing for {key}");
				return;
			}
			if (assign == null)
			{
				Log.Error($"Dawn resource action missing for {key}");
				return;
			}
			DawnFindResource.OnFreeze<TInfo>(registry, (Action)delegate
			{
				if (DawnFindResource.Resolve<TInfo>(registry, key, out TInfo info))
				{
					assign(info);
					Log.Debug($"Dawn resource assigned for {key}");
				}
			});
			Log.Debug($"Dawn resource queued for {key}");
		}

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

		public static void Add<TInfo, TValue>(Registry<TInfo> registry, NamespacedKey<TInfo> key, Func<TInfo, TValue?> read, string name, Action<TValue> assign) where TInfo : INamespaced<TInfo> where TValue : class
		{
			if (registry == null)
			{
				Log.Error("Dawn resource registry missing for " + name);
				return;
			}
			if (read == null)
			{
				Log.Error("Dawn resource reader missing for " + name);
				return;
			}
			if (assign == null)
			{
				Log.Error("Dawn resource action missing for " + name);
				return;
			}
			DawnFindResource.OnFreeze<TInfo>(registry, (Action)delegate
			{
				if (DawnFindResource.Resolve<TInfo, TValue>(registry, key, read, name, out TValue value))
				{
					assign(value);
					Log.Debug("Dawn resource assigned for " + name);
				}
			});
			Log.Debug("Dawn resource queued for " + name);
		}

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

		public static bool Resolve<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 missing for {key}");
				return false;
			}
			if (registry.TryGetValue(key, ref info))
			{
				Log.Debug($"Dawn resource resolved for {key}");
				return true;
			}
			info = default(TInfo);
			Log.Warn($"Dawn resource missing for {key}");
			return false;
		}

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

		public static bool Resolve<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 reader missing for " + name);
				return false;
			}
			if (!DawnFindResource.Resolve<TInfo>(registry, key, out TInfo info))
			{
				return false;
			}
			TValue val = read(info);
			if (Missing(val))
			{
				Log.Warn("Dawn resource value missing for " + name);
				return false;
			}
			value = val;
			Log.Debug("Dawn resource value resolved 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 Read<T>(string dawnModGUID, string settingName)
		{
			if (string.IsNullOrWhiteSpace(dawnModGUID))
			{
				Log.Error("Dusk config mod GUID missing");
				return default(T);
			}
			if (string.IsNullOrWhiteSpace(settingName))
			{
				Log.Error("Dusk config setting name missing");
				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 mod missing for " + dawnModGUID);
				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 missing for " + settingName);
				return default(T);
			}
			if (!(val2 is ConfigEntry<T> val3))
			{
				Log.Error("Dusk config setting type mismatch for " + settingName);
				return default(T);
			}
			return val3.Value;
		}

		public static T Read<T>(string dawnModGUID, string section, string settingName)
		{
			if (string.IsNullOrWhiteSpace(dawnModGUID))
			{
				Log.Error("Dusk config mod GUID missing");
				return default(T);
			}
			if (string.IsNullOrWhiteSpace(section))
			{
				Log.Error("Dusk config section missing");
				return default(T);
			}
			if (string.IsNullOrWhiteSpace(settingName))
			{
				Log.Error("Dusk config setting name missing");
				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 mod missing for " + dawnModGUID);
				return default(T);
			}
			ConfigEntryBase val2 = ((IEnumerable<ConfigEntryBase>)val.ConfigEntries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase configEntry) => configEntry.Definition.Section == section && configEntry.Definition.Key == settingName));
			if (val2 == null)
			{
				Log.Warn("Dusk config setting missing for " + section + "/" + settingName);
				return default(T);
			}
			if (!(val2 is ConfigEntry<T> val3))
			{
				Log.Error("Dusk config setting type mismatch for " + section + "/" + settingName);
				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("Dusk config mod GUID missing");
				return null;
			}
			if (string.IsNullOrWhiteSpace(section))
			{
				Log.Error("Dusk config section missing");
				return null;
			}
			if (string.IsNullOrWhiteSpace(settingName))
			{
				Log.Error("Dusk config setting key missing");
				return null;
			}
			DuskMod val = ((IEnumerable<DuskMod>)DuskMod.AllMods).FirstOrDefault((Func<DuskMod, bool>)((DuskMod duskMod) => duskMod.Plugin.GUID == dawnModGUID));
			if (val == null)
			{
				Log.Warn("Dusk mod missing 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 missing; item was null");
				return null;
			}
			if ((Object)(object)item.itemProperties == (Object)null)
			{
				Log.Warn("Dawn item key missing; item properties were null");
				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; item key was null");
				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);
				}
			}
			return list;
		}

		public static List<GrabbableObject> Active(NamespacedKey<DawnItemInfo> itemKey, Func<GrabbableObject, bool>? itemFilter = null)
		{
			return Active((Func<GrabbableObject, bool>?)((GrabbableObject item) => MatchesDawnKey(item, itemKey) && (itemFilter == null || itemFilter(item))));
		}

		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);
			return ClosestTo(position, radius, items, itemFilter);
		}

		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);
			return ClosestTo(itemKey, position, radius, items, itemFilter);
		}

		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 result = null;
			for (int i = 0; i < items.Count; i++)
			{
				GrabbableObject val = items[i];
				if (!((Object)(object)val == (Object)null) && (itemFilter == null || itemFilter(val)))
				{
					Vector3 val2 = ((Component)val).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude >= num))
					{
						num = sqrMagnitude;
						result = val;
					}
				}
			}
			return result;
		}

		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)
			return ClosestTo(position, radius, items, (GrabbableObject item) => MatchesDawnKey(item, itemKey) && (itemFilter == null || itemFilter(item)));
		}
	}
	public static class GrabbablePlacement
	{
		public static bool PlaceAt(GrabbableObject? item, Vector3 position, Quaternion rotation)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			((Component)item).transform.SetPositionAndRotation(position, rotation);
			item.startFallingPosition = position;
			item.targetFloorPosition = position;
			item.fallTime = 1f;
			item.hasHitGround = true;
			item.reachedFloorTarget = true;
			return true;
		}

		public static bool DropFrom(GrabbableObject? item, Vector3 startPosition, Vector3 floorPosition)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			Transform parent = ((Component)item).transform.parent;
			if ((Object)(object)parent != (Object)null)
			{
				item.startFallingPosition = parent.InverseTransformPoint(startPosition);
				item.targetFloorPosition = parent.InverseTransformPoint(floorPosition);
			}
			else
			{
				item.startFallingPosition = startPosition;
				item.targetFloorPosition = floorPosition;
			}
			item.fallTime = 0f;
			item.hasHitGround = false;
			item.reachedFloorTarget = false;
			return true;
		}

		public static bool PlaceOn(GrabbableObject? item, Transform? surface, Vector3 localOffset)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (Object)(object)surface == (Object)null)
			{
				return false;
			}
			item.parentObject = null;
			((Component)item).transform.localScale = item.originalScale;
			((Component)item).transform.position = surface.TransformPoint(localOffset);
			item.targetFloorPosition = localOffset;
			item.startFallingPosition = localOffset + Vector3.up * 0.0001f;
			item.fallTime = 1f;
			item.hasHitGround = true;
			item.reachedFloorTarget = true;
			return true;
		}

		public static bool PlaceOn(GrabbableObject? item, Transform? parent, Transform? point)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (Object)(object)parent == (Object)null || (Object)(object)point == (Object)null)
			{
				return false;
			}
			item.parentObject = null;
			((Component)item).transform.localScale = item.originalScale;
			((Component)item).transform.SetParent(parent, true);
			((Component)item).transform.localScale = item.originalScale;
			((Component)item).transform.SetPositionAndRotation(point.position, point.rotation);
			item.startFallingPosition = (item.targetFloorPosition = ((Component)item).transform.localPosition) + Vector3.up * 0.0001f;
			item.fallTime = 1f;
			item.hasHitGround = true;
			item.reachedFloorTarget = true;
			return true;
		}

		public static bool PlaceLocal(GrabbableObject? item, Transform? parent, Vector3 localPosition, Quaternion localRotation)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (Object)(object)parent == (Object)null)
			{
				return false;
			}
			item.parentObject = null;
			((Component)item).transform.localScale = item.originalScale;
			((Component)item).transform.SetParent(parent, false);
			((Component)item).transform.SetLocalPositionAndRotation(localPosition, localRotation);
			((Component)item).transform.localScale = item.originalScale;
			item.targetFloorPosition = localPosition;
			item.startFallingPosition = localPosition + Vector3.up * 0.0001f;
			item.fallTime = 1f;
			item.hasHitGround = true;
			item.reachedFloorTarget = true;
			return true;
		}
	}
	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? messageManager;

		private static bool messagesReady;

		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 && (!messagesReady || !((Object)(object)messageManager == (Object)(object)singleton)))
			{
				Shutdown();
				messageManager = singleton;
				messagesReady = 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 ready");
			}
		}

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

		public static void AddServerHandler(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Add(ServerHandlers, key, handler))
			{
				Log.Debug($"HatNet server handler added for {key}");
			}
		}

		public static void AddClientHandler(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Add(ClientHandlers, key, handler))
			{
				Log.Debug($"HatNet client handler added for {key}");
			}
		}

		public static void RemoveServerHandler(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Remove(ServerHandlers, key, handler))
			{
				Log.Debug($"HatNet server handler removed for {key}");
			}
		}

		public static void RemoveClientHandler(NamespacedKey key, HatNetMessageHandler handler)
		{
			if (Remove(ClientHandlers, key, handler))
			{
				Log.Debug($"HatNet client handler removed 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 = messageManager ?? NetworkManager.Singleton;
			if (val == null || !val.IsListening || val.CustomMessagingManager == null)
			{
				Log.Debug("HatNet server message skipped; networking 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 = messageManager ?? NetworkManager.Singleton;
			if (val == null || !val.IsListening || !val.IsServer || val.CustomMessagingManager == null)
			{
				Log.Debug("HatNet client message skipped; server 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 = messageManager ?? NetworkManager.Singleton;
			if (val == null || !val.IsListening || !val.IsServer || val.CustomMessagingManager == null)
			{
				Log.Debug("HatNet client message skipped; server 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 Add(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 Remove(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 exists 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;
		}
	}
	public static class NetworkRefs
	{
		public static Coroutine? WhenReady(MonoBehaviour? owner, NetworkObjectReference reference, Action<NetworkObject>? action, float seconds = 8f, int frames = 0)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)owner == (Object)null || action == null)
			{
				return null;
			}
			return owner.StartCoroutine(Wait(reference, action, seconds, frames));
		}

		public static Coroutine? WhenReady<T>(MonoBehaviour? owner, NetworkObjectReference reference, Action<T>? action, float seconds = 8f, int frames = 0) where T : Component
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)owner == (Object)null || action == null)
			{
				return null;
			}
			return owner.StartCoroutine(Wait(reference, delegate(NetworkObject networkObject)
			{
				T obj = default(T);
				if (((Component)networkObject).TryGetComponent<T>(ref obj))
				{
					action(obj);
				}
			}, seconds, frames));
		}

		private static IEnumerator Wait(NetworkObjectReference reference, Action<NetworkObject> action, float seconds, int frames)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			NetworkObject networkObject = null;
			float startedAt = Time.realtimeSinceStartup;
			while (Time.realtimeSinceStartup - startedAt < seconds && !((NetworkObjectReference)(ref reference)).TryGet(ref networkObject, (NetworkManager)null))
			{
				yield return null;
			}
			if (!((Object)(object)networkObject == (Object)null))
			{
				for (int i = 0; i < frames; i++)
				{
					yield return null;
				}
				action(networkObject);
			}
		}
	}
	[Serializable]
	public class PlayerAnimatorSwap
	{
		public RuntimeAnimatorController localAnimator = null;

		public RuntimeAnimatorController remoteAnimator = 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? originalAnimator;

		private RuntimeAnimatorController? replacementAnimator;

		public bool IsActive { get; private set; }

		public bool SwapHeld(PlayerControllerB? player, PlayerAnimatorSwap? replacement)
		{
			if (IsActive)
			{
				return true;
			}
			if ((Object)(object)player == (Object)null || replacement == null)
			{
				return false;
			}
			RuntimeAnimatorController val = (((Object)(object)player == (Object)(object)GameNetworkManager.Instance.localPlayerController) ? replacement.localAnimator : replacement.remoteAnimator);
			return Swap(player.playerBodyAnimator, val);
		}

		public bool Swap(Animator? playerAnimator, RuntimeAnimatorController? replacementAnimator)
		{
			//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)playerAnimator == (Object)null || (Object)(object)replacementAnimator == (Object)null)
			{
				return false;
			}
			animator = playerAnimator;
			originalAnimator = playerAnimator.runtimeAnimatorController;
			this.replacementAnimator = replacementAnimator;
			AnimatorStateInfo currentAnimatorStateInfo = playerAnimator.GetCurrentAnimatorStateInfo(0);
			float normalizedTime = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime;
			bool flag = playerAnimator.GetBool(CrouchingHash);
			bool flag2 = playerAnimator.GetBool(WalkingHash);
			bool flag3 = playerAnimator.GetBool(JumpingHash);
			bool flag4 = playerAnimator.GetBool(SprintingHash);
			playerAnimator.runtimeAnimatorController = replacementAnimator;
			for (int i = 0; i < RequiredPlayerLayers.Length; i++)
			{
				if (playerAnimator.GetLayerIndex(RequiredPlayerLayers[i]) < 0)
				{
					playerAnimator.runtimeAnimatorController = originalAnimator;
					Log.Warn("Player animator swap missing layer " + RequiredPlayerLayers[i]);
					animator = null;
					originalAnimator = null;
					this.replacementAnimator = null;
					return false;
				}
			}
			playerAnimator.Rebind();
			playerAnimator.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, 0, normalizedTime);
			playerAnimator.SetBool(CrouchingHash, flag);
			playerAnimator.SetBool(WalkingHash, flag2);
			playerAnimator.SetBool(JumpingHash, flag3);
			playerAnimator.SetBool(SprintingHash, flag4);
			playerAnimator.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)replacementAnimator)
				{
					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 = originalAnimator;
					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;
				originalAnimator = null;
				replacementAnimator = null;
				IsActive = false;
			}
		}
	}
	public abstract class PlayerAnimatorReplacement : GrabbableObject
	{
		[Header("Player Animator")]
		[SerializeField]
		private PlayerAnimatorSwap playerAnimator = new PlayerAnimatorSwap();

		private readonly PlayerAnimatorTools playerAnimatorTools = new PlayerAnimatorTools();

		protected bool SwapHeldPlayerAnimator()
		{
			return playerAnimatorTools.SwapHeld(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 PrefabSpawns
	{
		public static bool Grabbable(Item? item, Vector3 position, Quaternion rotation, out GrabbableObject grabbable, out NetworkObject networkObject, Transform? parent = null)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			grabbable = null;
			networkObject = null;
			if ((Object)(object)item?.spawnPrefab == (Object)null)
			{
				return false;
			}
			return Grabbable(item.spawnPrefab, position, rotation, out grabbable, out networkObject, parent);
		}

		public static bool Grabbable(GameObject? prefab, Vector3 position, Quaternion rotation, out GrabbableObject grabbable, out NetworkObject networkObject, Transform? parent = null)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			grabbable = null;
			networkObject = null;
			if ((Object)(object)prefab == (Object)null)
			{
				return false;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, position, rotation, parent);
			GrabbableObject component = val.GetComponent<GrabbableObject>();
			NetworkObject component2 = val.GetComponent<NetworkObject>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return false;
			}
			grabbable = component;
			networkObject = component2;
			return true;
		}

		public static T? Component<T>(T? prefab, Vector3 position, Quaternion rotation, Transform? parent = null) where T : Component
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return default(T);
			}
			return Object.Instantiate<T>(prefab, position, rotation, parent);
		}

		public static GameObject? GameObject(GameObject? prefab, Vector3 position, Quaternion rotation, Transform? parent = null)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			return Object.Instantiate<GameObject>(prefab, position, rotation, parent);
		}
	}
	public static class UnlockableTools
	{
		public static bool Bought(NamespacedKey<DawnUnlockableItemInfo> key)
		{
			if (key == null)
			{
				Log.Warn("Dawn unlockable check skipped; key was null");
				return false;
			}
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				Log.Debug($"Dawn unlockable check skipped for {key}; no round");
				return false;
			}
			List<UnlockableItem> list = instance.unlockablesList?.unlockables;
			if (list == null)
			{
				Log.Debug($"Dawn unlockable check skipped for {key}; no unlockable list");
				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 for {key}");
						return true;
					}
					Log.Debug($"Dawn unlockable locked for {key}");
					return false;
				}
			}
			Log.Debug($"Dawn unlockable missing for {key}");
			return false;
		}

		public static bool Bought(string namespacedKey)
		{
			if (string.IsNullOrWhiteSpace(namespacedKey))
			{
				Log.Warn("Dawn unlockable check skipped; key text was empty");
				return false;
			}
			NamespacedKey val = default(NamespacedKey);
			if (!NamespacedKey.TryParse(namespacedKey, ref val))
			{
				Log.Warn("Dawn unlockable check skipped; key text was invalid 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
	{
	}
}