Decompiled source of Fusion v1.12.2

Mods/LabFusion.dll

Decompiled a month ago
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using GroovyCodecs.G711.aLaw;
using HarmonyLib;
using Il2Cpp;
using Il2CppCysharp.Threading.Tasks;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.InteropTypes.Fields;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Data;
using Il2CppSLZ.Interaction;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.AI;
using Il2CppSLZ.Marrow.Audio;
using Il2CppSLZ.Marrow.Circuits;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Forklift;
using Il2CppSLZ.Marrow.Forklift.Model;
using Il2CppSLZ.Marrow.Input;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.PuppetMasta;
using Il2CppSLZ.Marrow.SceneStreaming;
using Il2CppSLZ.Marrow.Utilities;
using Il2CppSLZ.Marrow.VFX;
using Il2CppSLZ.Marrow.VoidLogic;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.Marrow.Zones;
using Il2CppSLZ.Props;
using Il2CppSLZ.UI;
using Il2CppSLZ.VRMK;
using Il2CppSteamworks;
using Il2CppSystem;
using Il2CppSystem.Collections;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using Il2CppUltEvents;
using LabFusion;
using LabFusion.Audio;
using LabFusion.Bonelab;
using LabFusion.Bonelab.Extenders;
using LabFusion.Bonelab.Messages;
using LabFusion.Bonelab.Patching;
using LabFusion.Bonelab.Scene;
using LabFusion.Data;
using LabFusion.Data.Serializables;
using LabFusion.Downloading;
using LabFusion.Downloading.ModIO;
using LabFusion.Entities;
using LabFusion.Exceptions;
using LabFusion.Extensions;
using LabFusion.Grabbables;
using LabFusion.Marrow;
using LabFusion.Marrow.Circuits;
using LabFusion.Marrow.Combat;
using LabFusion.Marrow.Extenders;
using LabFusion.Marrow.Extensions;
using LabFusion.Marrow.Integration;
using LabFusion.Marrow.Messages;
using LabFusion.Marrow.Patching;
using LabFusion.Marrow.Pool;
using LabFusion.Marrow.Proxies;
using LabFusion.Marrow.Scene;
using LabFusion.Marrow.Serialization;
using LabFusion.Marrow.Zones;
using LabFusion.Math;
using LabFusion.Menu;
using LabFusion.Menu.Data;
using LabFusion.Menu.Gamemodes;
using LabFusion.MonoBehaviours;
using LabFusion.Network;
using LabFusion.Network.Proxy;
using LabFusion.Network.Serialization;
using LabFusion.Patching;
using LabFusion.Player;
using LabFusion.Preferences;
using LabFusion.Preferences.Client;
using LabFusion.Preferences.Server;
using LabFusion.RPC;
using LabFusion.Representation;
using LabFusion.SDK;
using LabFusion.SDK.Achievements;
using LabFusion.SDK.Cosmetics;
using LabFusion.SDK.Extenders;
using LabFusion.SDK.Gamemodes;
using LabFusion.SDK.Lobbies;
using LabFusion.SDK.Messages;
using LabFusion.SDK.Metadata;
using LabFusion.SDK.Modules;
using LabFusion.SDK.MonoBehaviours;
using LabFusion.SDK.Points;
using LabFusion.SDK.Scene;
using LabFusion.SDK.Triggers;
using LabFusion.Safety;
using LabFusion.Scene;
using LabFusion.Senders;
using LabFusion.UI;
using LabFusion.UI.Popups;
using LabFusion.Utilities;
using LabFusion.Voice;
using LabFusion.Voice.Unity;
using LabFusion.XML;
using LiteNetLib;
using LiteNetLib.Layers;
using LiteNetLib.Utils;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using Steamworks;
using Steamworks.Data;
using Steamworks.Ugc;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.Video;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LabFusion")]
[assembly: AssemblyFileVersion("1.12.2")]
[assembly: MelonInfo(typeof(FusionMod), "LabFusion", "1.12.2", "Lakatrazz", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonPriority(-10000)]
[assembly: MelonOptionalDependencies(new string[] { "Il2CppFacepunch.Steamworks.Win64" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.12.2.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
namespace LabFusion
{
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct FusionVersion
	{
		public const byte VersionMajor = 1;

		public const byte VersionMinor = 12;

		public const short VersionPatch = 2;

		public const string VersionString = "1.12.2";
	}
	public class FusionMod : MelonMod
	{
		public const string ModName = "LabFusion";

		public const string ModAuthor = "Lakatrazz";

		public const string GameDeveloper = "Stress Level Zero";

		public const string GameName = "BONELAB";

		public static readonly Version Version = new Version(1, 12, 2);

		private static bool _hasAutoUpdater = false;

		private static int _nextSyncableSendRate = 1;

		public static string Changelog { get; internal set; } = null;


		public static string[] Credits { get; internal set; } = null;


		public static FusionMod Instance { get; private set; }

		public static Assembly FusionAssembly { get; private set; }

		public override void OnEarlyInitializeMelon()
		{
			Instance = this;
			FusionAssembly = ((MelonBase)this).MelonAssembly.Assembly;
			ModDownloadManager.DeleteTemporaryDirectories();
			PersistentData.OnPathInitialize();
			SteamAPILoader.OnLoadSteamAPI();
			PDController.OnInitializeMelon();
			PointItemManager.HookEvents();
			RpcManager.OnInitialize();
		}

		public override void OnInitializeMelon()
		{
			FusionFileLoader.OnInitializeMelon();
			ListLoader.OnInitializeMelon();
			LocalPlayer.OnInitializeMelon();
			VoiceSourceManager.OnInitializeMelon();
			InitializeBaseModules();
			NativeMessageHandler.RegisterHandlersFromAssembly(FusionAssembly);
			GrabGroupHandler.RegisterHandlersFromAssembly(FusionAssembly);
			NetworkLayer.RegisterLayersFromAssembly(FusionAssembly);
			GamemodeRegistration.LoadGamemodes(FusionAssembly);
			PointItemManager.LoadItems(FusionAssembly);
			AchievementManager.LoadAchievements(FusionAssembly);
			RpcManager.LoadRpcs(FusionAssembly);
			EntityComponentManager.LoadComponents(FusionAssembly);
			LobbyFilterManager.LoadBuiltInFilters();
			NetworkEntityManager.OnInitializeManager();
			NetworkPlayerManager.OnInitializeManager();
			PopupManager.OnInitializeMelon();
			GamemodeManager.OnInitializeMelon();
			GamemodeConditionsChecker.OnInitializeMelon();
			GamemodeRoundManager.OnInitializeMelon();
			AssetWarehouse.OnReady(Action.op_Implicit((Action)delegate
			{
				CosmeticLoader.OnAssetWarehouseReady();
			}));
			FusionPreferences.OnInitializePreferences();
			FusionPermissions.OnInitializeMelon();
			LobbyInfoManager.OnInitialize();
			MenuCreator.OnInitializeMelon();
			FusionSceneManager.Internal_OnInitializeMelon();
			MultiplayerHooking.OnLoadingBegin += OnLoadingBegin;
			NetworkSceneManager.OnInitializeMelon();
			NetworkLayerManager.OnInitializeMelon();
		}

		private static void InitializeBaseModules()
		{
			ModuleManager.RegisterModule<SDKModule>();
			ModuleManager.RegisterModule<MarrowModule>();
			ModuleManager.RegisterModule<BonelabModule>();
		}

		public override void OnLateInitializeMelon()
		{
			PersistentAssetCreator.OnLateInitializeMelon();
			PlayerAdditionsHelper.OnInitializeMelon();
			_hasAutoUpdater = MelonTypeBase<MelonPlugin>.RegisteredMelons.Any((MelonPlugin p) => ((MelonBase)p).Info.Name.Contains("LabFusion Updater"));
			if (!_hasAutoUpdater)
			{
				Notifier.Send(new Notification
				{
					SaveToMenu = false,
					ShowPopup = true,
					Message = "You do not have the Fusion AutoUpdater installed in your plugins folder!\nIt is recommended to install it in order to stay up to date.",
					Type = NotificationType.WARNING
				});
			}
		}

		public override void OnDeinitializeMelon()
		{
			NetworkLayerManager.LogOut();
			FusionFileLoader.OnDeinitializeMelon();
			PointItemManager.UnhookEvents();
			PlayerAdditionsHelper.OnDeinitializeMelon();
			SteamAPILoader.OnFreeSteamAPI();
		}

		public override void OnPreferencesLoaded()
		{
			FusionPreferences.OnPreferencesLoaded();
		}

		public static void OnMainSceneInitialized()
		{
			_ = ((Scannable)FusionSceneManager.Level).Title;
			NetworkEntityManager.OnCleanupIds();
			RigData.OnCacheRigInfo();
			PersistentAssetCreator.OnMainSceneInitialized();
			ConstrainerUtilities.OnMainSceneInitialized();
			MultiplayerHooking.InvokeOnMainSceneInitialized();
			FusionPlayer.OnMainSceneInitialized();
		}

		public static void OnMainSceneInitializeDelayed()
		{
			if (RigData.HasPlayer)
			{
				((Il2CppObjectBase)RigData.Refs.RigManager.ControllerRig).TryCast<OpenControllerRig>().quickmenuEnabled = true;
				PlayerRefs.Instance.PlayerBodyVitals.quickmenuEnabled = true;
				MenuCreator.CreateMenu();
			}
		}

		private void OnLoadingBegin()
		{
			ModIOThumbnailDownloader.ClearCache();
		}

		public override void OnUpdate()
		{
			NetworkInfo.BytesDown = 0;
			NetworkInfo.BytesUp = 0;
			ModIODownloader.UpdateQueue();
			TimeUtilities.OnEarlyUpdate();
			FusionSceneManager.Internal_UpdateScene();
			PopupManager.OnUpdate();
			float deltaTime = TimeUtilities.DeltaTime;
			NetworkPlayerManager.OnUpdate(deltaTime);
			if (TimeUtilities.IsMatchingFrame(_nextSyncableSendRate))
			{
				int bytesUp = NetworkInfo.BytesUp;
				NetworkEntityManager.OnUpdate(deltaTime);
				_nextSyncableSendRate = SendRateTable.GetObjectSendRate(NetworkInfo.BytesUp - bytesUp);
			}
			FusionPlayer.OnUpdate();
			VoiceHelper.OnVoiceChatUpdate();
			InternalLayerHelpers.OnUpdateLayer();
			MultiplayerHooking.InvokeOnUpdate();
			GamemodeManager.OnUpdate();
			DelayUtilities.OnProcessDelays();
		}

		public override void OnFixedUpdate()
		{
			TimeUtilities.OnEarlyFixedUpdate();
			LocalPlayer.OnFixedUpdate();
			PDController.OnFixedUpdate();
			float fixedDeltaTime = TimeUtilities.FixedDeltaTime;
			NetworkPlayerManager.OnFixedUpdate(fixedDeltaTime);
			NetworkEntityManager.OnFixedUpdate(fixedDeltaTime);
			MultiplayerHooking.InvokeOnFixedUpdate();
			GamemodeManager.OnFixedUpdate();
		}

		public override void OnLateUpdate()
		{
			float deltaTime = TimeUtilities.DeltaTime;
			NetworkPlayerManager.OnLateUpdate(deltaTime);
			NetworkEntityManager.OnLateUpdate(deltaTime);
			InternalLayerHelpers.OnLateUpdateLayer();
			MultiplayerHooking.InvokeOnLateUpdate();
			GamemodeManager.OnLateUpdate();
		}
	}
}
namespace LabFusion.Voice
{
	public interface IVoiceManager
	{
		List<IVoiceSpeaker> VoiceSpeakers { get; }

		bool CanTalk { get; }

		bool CanHear { get; }

		string[] InputDevices { get; }

		IVoiceSpeaker GetSpeaker(PlayerID id);

		void RemoveSpeaker(PlayerID id);

		IVoiceReceiver GetReceiver();

		void Enable();

		void Disable();

		void UpdateManager();

		void ClearManager();
	}
	public abstract class VoiceManager : IVoiceManager
	{
		protected List<IVoiceSpeaker> _voiceSpeakers = new List<IVoiceSpeaker>();

		private IVoiceReceiver _receiver;

		private bool _hasDisabledVoice = true;

		public List<IVoiceSpeaker> VoiceSpeakers => _voiceSpeakers;

		public virtual bool CanTalk => true;

		public virtual bool CanHear => true;

		public virtual string[] InputDevices => Array.Empty<string>();

		public void Enable()
		{
			_receiver = OnCreateReceiverOrDefault();
			_receiver?.Enable();
		}

		public void Disable()
		{
			if (_receiver != null)
			{
				_receiver.Disable();
				_receiver = null;
			}
			ClearManager();
		}

		protected bool TryGetSpeaker(PlayerID id, out IVoiceSpeaker speaker)
		{
			speaker = null;
			for (int i = 0; i < VoiceSpeakers.Count; i++)
			{
				IVoiceSpeaker voiceSpeaker = VoiceSpeakers[i];
				if (voiceSpeaker.ID == id)
				{
					speaker = voiceSpeaker;
					return true;
				}
			}
			return false;
		}

		protected abstract IVoiceSpeaker OnCreateSpeaker(PlayerID id);

		protected abstract IVoiceReceiver OnCreateReceiverOrDefault();

		public IVoiceSpeaker GetSpeaker(PlayerID id)
		{
			if (TryGetSpeaker(id, out var speaker))
			{
				return speaker;
			}
			IVoiceSpeaker voiceSpeaker = OnCreateSpeaker(id);
			VoiceSpeakers.Add(voiceSpeaker);
			return voiceSpeaker;
		}

		public IVoiceReceiver GetReceiver()
		{
			return _receiver;
		}

		public void UpdateManager()
		{
			UpdateSpeakers();
			UpdateReceiver();
		}

		private void UpdateSpeakers()
		{
			for (int i = 0; i < VoiceSpeakers.Count; i++)
			{
				VoiceSpeakers[i].Update();
			}
		}

		private void UpdateReceiver()
		{
			if (_receiver != null && CanTalk)
			{
				if (NetworkInfo.HasServer && !VoiceInfo.IsMuted)
				{
					_receiver.UpdateVoice(enabled: true);
					_hasDisabledVoice = false;
				}
				else if (!_hasDisabledVoice)
				{
					_receiver.UpdateVoice(enabled: false);
					_hasDisabledVoice = true;
				}
				if (_receiver.HasVoiceActivity())
				{
					PlayerSender.SendPlayerVoiceChat(_receiver.GetEncodedData());
				}
			}
		}

		public void RemoveSpeaker(PlayerID id)
		{
			IVoiceSpeaker voiceSpeaker = null;
			foreach (IVoiceSpeaker voiceSpeaker2 in VoiceSpeakers)
			{
				if (voiceSpeaker2.ID == id)
				{
					voiceSpeaker = voiceSpeaker2;
					break;
				}
			}
			if (voiceSpeaker != null)
			{
				voiceSpeaker.Cleanup();
				_voiceSpeakers.Remove(voiceSpeaker);
			}
		}

		public void ClearManager()
		{
			foreach (IVoiceSpeaker voiceSpeaker in VoiceSpeakers)
			{
				voiceSpeaker.Cleanup();
			}
			_voiceSpeakers.Clear();
		}
	}
	public interface IVoiceReceiver
	{
		float GetVoiceAmplitude();

		bool HasVoiceActivity();

		byte[] GetEncodedData();

		void UpdateVoice(bool enabled);

		void Enable();

		void Disable();
	}
	public interface IVoiceSpeaker
	{
		PlayerID ID { get; }

		float Volume { get; set; }

		float Amplitude { get; set; }

		void OnVoiceDataReceived(byte[] data);

		void Update();

		void Cleanup();
	}
	public abstract class VoiceSpeaker : IVoiceSpeaker
	{
		protected PlayerID _id;

		protected float _volume = 1f;

		public PlayerID ID => _id;

		public float Volume
		{
			get
			{
				return _volume;
			}
			set
			{
				_volume = value;
			}
		}

		public abstract float Amplitude { get; set; }

		public virtual void Update()
		{
		}

		public abstract void OnVoiceDataReceived(byte[] data);

		public abstract void Cleanup();
	}
	public class JawFlapper
	{
		public const float MaxAngle = 40f;

		private float _voiceLoudness;

		public float GetAngle()
		{
			return _voiceLoudness * 40f;
		}

		public void ClearJaw()
		{
			_voiceLoudness = 0f;
		}

		public void UpdateJaw(float amplitude, float deltaTime)
		{
			float b = ManagedMathf.Clamp01(amplitude * 2f);
			_voiceLoudness = ManagedMathf.Lerp(_voiceLoudness, b, Smoothing.CalculateDecay(12f, deltaTime));
		}
	}
	public static class VoiceConverter
	{
		public static readonly ALawEncoder G711Encoder = new ALawEncoder();

		public static readonly ALawDecoder G711Decoder = new ALawDecoder();

		public static void CopySamples(float[] from, short[] to, int sampleCount)
		{
			for (int i = 0; i < sampleCount; i++)
			{
				to[i] = ConvertSample(from[i]);
			}
		}

		public static void CopySamples(short[] from, float[] to, int sampleCount)
		{
			for (int i = 0; i < sampleCount; i++)
			{
				to[i] = ConvertSample(from[i]);
			}
		}

		public static short ConvertSample(float sample)
		{
			return (short)(sample * 32767f);
		}

		public static float ConvertSample(short sample)
		{
			return (float)sample / 32767f;
		}

		public static byte[] Encode(short[] samples)
		{
			return Compress(G711Encoder.Process(samples));
		}

		public static short[] Decode(byte[] bytes)
		{
			return G711Decoder.Process(Decompress(bytes));
		}

		public static byte[] Compress(byte[] data)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.SmallestSize);
			deflateStream.Write(data, 0, data.Length);
			deflateStream.Close();
			return memoryStream.ToArray();
		}

		public static byte[] Decompress(byte[] data)
		{
			using MemoryStream stream = new MemoryStream(data);
			using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			deflateStream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}
	}
	public static class VoiceHelper
	{
		public static void OnVoiceChatUpdate()
		{
			VoiceInfo.VoiceManager?.UpdateManager();
		}

		public static void OnVoiceDataReceived(PlayerID player, byte[] data)
		{
			if (!VoiceInfo.IsDeafened)
			{
				(VoiceInfo.VoiceManager?.GetSpeaker(player))?.OnVoiceDataReceived(data);
			}
		}
	}
	public static class VoiceInfo
	{
		public static IVoiceManager VoiceManager => NetworkLayerManager.Layer?.VoiceManager;

		public static bool CanTalk => (VoiceManager?.CanTalk).GetValueOrDefault();

		public static bool CanHear => (VoiceManager?.CanHear).GetValueOrDefault();

		public static string[] InputDevices
		{
			get
			{
				if (VoiceManager == null)
				{
					return Array.Empty<string>();
				}
				return VoiceManager.InputDevices;
			}
		}

		public static bool ShowMuteIndicator
		{
			get
			{
				if (NetworkInfo.HasServer && ClientSettings.VoiceChat.Muted.Value)
				{
					return ClientSettings.VoiceChat.MutedIndicator.Value;
				}
				return false;
			}
		}

		public static float VoiceAmplitude => (VoiceManager?.GetReceiver()?.GetVoiceAmplitude()).GetValueOrDefault();

		public static bool HasVoiceActivity => (VoiceManager?.GetReceiver()?.HasVoiceActivity()).GetValueOrDefault();

		public static bool IsMuted
		{
			get
			{
				if (!ClientSettings.VoiceChat.Muted.Value)
				{
					return IsDeafened;
				}
				return true;
			}
		}

		public static bool IsDeafened
		{
			get
			{
				if (FusionSceneManager.IsLoading())
				{
					return true;
				}
				if (!ClientSettings.VoiceChat.Deafened.Value)
				{
					return !ServerVoiceEnabled;
				}
				return true;
			}
		}

		public static bool ServerVoiceEnabled => LobbyInfoManager.LobbyInfo.VoiceChat;
	}
	[RegisterTypeInIl2Cpp]
	public class VoiceSource : MonoBehaviour
	{
		private bool _overrideFilter;

		private bool _muted;

		private bool _receivingInput;

		private float _timeSinceInput;

		private bool _wasPlaying;

		[HideFromIl2Cpp]
		public AudioSource AudioSource { get; private set; }

		[HideFromIl2Cpp]
		public AudioStreamFilter StreamFilter { get; private set; }

		public bool OverrideFilter
		{
			get
			{
				return _overrideFilter;
			}
			set
			{
				if (_overrideFilter != value)
				{
					_overrideFilter = value;
					((Behaviour)StreamFilter).enabled = Playing && !value;
				}
			}
		}

		[HideFromIl2Cpp]
		public float Amplitude { get; set; }

		public bool Muted
		{
			get
			{
				return _muted;
			}
			set
			{
				if (_muted != value)
				{
					_muted = value;
					ProcessPlaying();
				}
			}
		}

		public bool ReceivingInput
		{
			get
			{
				return _receivingInput;
			}
			set
			{
				if (_receivingInput != value)
				{
					_receivingInput = value;
					_timeSinceInput = 0f;
					ProcessPlaying();
				}
			}
		}

		public float TimeSinceInput => _timeSinceInput;

		public bool Playing
		{
			get
			{
				if (ReceivingInput)
				{
					return !Muted;
				}
				return false;
			}
		}

		public int ID { get; set; } = -1;


		[HideFromIl2Cpp]
		public static event Action<VoiceSource> OnVoiceEnabled;

		[HideFromIl2Cpp]
		public static event Action<VoiceSource> OnVoiceDisabled;

		public VoiceSource(IntPtr intPtr)
			: base(intPtr)
		{
		}

		private void Awake()
		{
			GetAudioSource();
			StopSources();
		}

		private void OnEnable()
		{
			VoiceSource.OnVoiceEnabled?.Invoke(this);
			ReceivingInput = false;
			((Behaviour)StreamFilter).enabled = true;
			((Behaviour)StreamFilter).enabled = false;
		}

		private void OnDisable()
		{
			VoiceSource.OnVoiceDisabled?.Invoke(this);
			ReceivingInput = false;
			((Behaviour)StreamFilter).enabled = false;
		}

		private void Update()
		{
			if (Playing)
			{
				if (StreamFilter.ReadingQueue.Count <= 0)
				{
					_timeSinceInput += Time.deltaTime;
				}
				if (_timeSinceInput > 1f)
				{
					ReceivingInput = false;
				}
			}
		}

		[HideFromIl2Cpp]
		private void ProcessPlaying()
		{
			if (_wasPlaying != Playing)
			{
				_wasPlaying = Playing;
				if (Playing)
				{
					PlaySources();
				}
				else
				{
					StopSources();
				}
			}
		}

		private void PlaySources()
		{
			((Behaviour)StreamFilter).enabled = !OverrideFilter;
			AudioSource.Play();
			Amplitude = 0f;
		}

		private void StopSources()
		{
			AudioSource.Stop();
			((Behaviour)StreamFilter).enabled = false;
			StreamFilter.ReadingQueue.Clear();
			Amplitude = 0f;
		}

		[HideFromIl2Cpp]
		private void GetAudioSource()
		{
			AudioSource component = ((Component)this).GetComponent<AudioSource>();
			if ((Object)(object)component != (Object)null)
			{
				AudioSource = component;
			}
			else
			{
				AudioSource = CreateAudioSource();
			}
			SetSourceSettings();
		}

		[HideFromIl2Cpp]
		private AudioSource CreateAudioSource()
		{
			AudioSource obj = ((Component)this).gameObject.AddComponent<AudioSource>();
			obj.volume = 1f;
			obj.spatialBlend = 1f;
			obj.dopplerLevel = 0.5f;
			obj.spread = 60f;
			return obj;
		}

		[HideFromIl2Cpp]
		private void SetSourceSettings()
		{
			AudioSource.loop = true;
			AudioSource.playOnAwake = false;
			AudioSource.outputAudioMixerGroup = null;
			StreamFilter = ((Component)this).gameObject.AddComponent<AudioStreamFilter>();
			AudioSource.clip = AudioInfo.CreateToneClip();
		}
	}
	public static class VoiceSourceManager
	{
		public static List<VoiceSource> ActiveVoices { get; } = new List<VoiceSource>();


		public static IEnumerable<VoiceSource> GetVoicesByID(int id)
		{
			return ActiveVoices.Where((VoiceSource voice) => voice.ID == id);
		}

		public static void EnqueueSample(IEnumerable<VoiceSource> sources, float sample)
		{
			foreach (VoiceSource source in sources)
			{
				try
				{
					source.StreamFilter.Enqueue(sample);
				}
				catch (Exception e)
				{
					FusionLogger.LogException("enqueueing VoiceSource sample", e);
				}
			}
		}

		public static void SetAmplitude(IEnumerable<VoiceSource> sources, float amplitude)
		{
			foreach (VoiceSource source in sources)
			{
				try
				{
					source.ReceivingInput = true;
					source.Amplitude = amplitude;
				}
				catch (Exception e)
				{
					FusionLogger.LogException("setting VoiceSource amplitude", e);
				}
			}
		}

		public static VoiceSource CreateVoiceSource(int id)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			return CreateVoiceSource(new GameObject($"Voice Source {id}"), id);
		}

		public static VoiceSource CreateVoiceSource(GameObject gameObject, int id)
		{
			VoiceSource voiceSource = gameObject.AddComponent<VoiceSource>();
			voiceSource.ID = id;
			return voiceSource;
		}

		internal static void OnInitializeMelon()
		{
			VoiceSource.OnVoiceEnabled += OnVoiceEnabled;
			VoiceSource.OnVoiceDisabled += OnVoiceDisabled;
		}

		private static void OnVoiceEnabled(VoiceSource source)
		{
			ActiveVoices.Add(source);
		}

		private static void OnVoiceDisabled(VoiceSource source)
		{
			ActiveVoices.RemoveAll((VoiceSource s) => (Object)(object)s == (Object)(object)source);
		}
	}
	public static class VoiceVolume
	{
		public const float DefaultSampleMultiplier = 10f;

		public const float MinimumVoiceVolume = 0.3f;

		public const float SilencingVolume = 0.1f;

		public const float TalkTimeoutTime = 1f;

		public static float GetVolumeMultiplier()
		{
			float num = Audio3dManager.audio_GlobalVolume * 0.1f;
			float num2 = Audio3dManager.audio_SFXVolume * 0.1f;
			float value = ClientSettings.VoiceChat.GlobalVolume.Value;
			return num * num2 * value;
		}
	}
}
namespace LabFusion.Voice.Unity
{
	public static class UnityVoice
	{
		public const int ClipLength = 1;

		private static bool _hasMicrophones;

		private static bool _checkedForMic;

		private static bool CheckForMicrophone()
		{
			try
			{
				_ = ((Il2CppArrayBase<string>)(object)Microphone.devices)[0];
				return true;
			}
			catch
			{
				return false;
			}
		}

		public static bool IsSupported()
		{
			if (!_checkedForMic)
			{
				_hasMicrophones = CheckForMicrophone();
				_checkedForMic = true;
			}
			return _hasMicrophones;
		}
	}
	public sealed class UnityVoiceManager : VoiceManager
	{
		public override bool CanTalk
		{
			get
			{
				if (!UnityVoice.IsSupported())
				{
					return false;
				}
				return true;
			}
		}

		public override string[] InputDevices
		{
			get
			{
				if (!UnityVoice.IsSupported())
				{
					return Array.Empty<string>();
				}
				return Il2CppArrayBase<string>.op_Implicit((Il2CppArrayBase<string>)(object)Microphone.devices);
			}
		}

		protected override IVoiceReceiver OnCreateReceiverOrDefault()
		{
			return new UnityVoiceReceiver();
		}

		protected override IVoiceSpeaker OnCreateSpeaker(PlayerID id)
		{
			return new UnityVoiceSpeaker(id);
		}
	}
	public sealed class UnityVoiceReceiver : IVoiceReceiver
	{
		private static readonly float[] SampleBuffer = new float[AudioInfo.OutputSampleRate];

		private byte[] _encodedData;

		private bool _hasVoiceActivity;

		private AudioClip _voiceClip;

		private int _lastSample;

		private float _amplitude;

		private float _lastTalkTime;

		private bool _loopedData;

		public float GetVoiceAmplitude()
		{
			return _amplitude;
		}

		public byte[] GetEncodedData()
		{
			return _encodedData;
		}

		public bool HasVoiceActivity()
		{
			return _hasVoiceActivity;
		}

		public static string GetValidMicrophoneName()
		{
			return ClientSettings.VoiceChat.InputDevice.Value;
		}

		private void ClearData()
		{
			_encodedData = null;
			_hasVoiceActivity = false;
			_amplitude = 0f;
		}

		public void UpdateVoice(bool enabled)
		{
			if (!UnityVoice.IsSupported())
			{
				ClearData();
				return;
			}
			string validMicrophoneName = GetValidMicrophoneName();
			if (Microphone.GetMicrophoneDeviceIDFromName(validMicrophoneName) == -1)
			{
				ClearData();
				return;
			}
			bool flag = Microphone.IsRecording(validMicrophoneName);
			if (enabled && !flag)
			{
				_voiceClip = Microphone.Start(validMicrophoneName, true, 1, AudioInfo.OutputSampleRate);
			}
			else if (!enabled && flag)
			{
				Microphone.End(validMicrophoneName);
			}
			if (!enabled || (Object)(object)_voiceClip == (Object)null)
			{
				ClearData();
				return;
			}
			int num = Microphone.GetPosition(validMicrophoneName);
			if (num < _lastSample)
			{
				_loopedData = true;
				num = AudioInfo.OutputSampleRate;
			}
			int num2 = num - _lastSample;
			if (num2 <= 0)
			{
				_hasVoiceActivity = false;
				return;
			}
			Il2CppStructArray<float> val = new Il2CppStructArray<float>((long)num2);
			_voiceClip.GetData(val, _lastSample);
			IntPtr pointer = ((Il2CppObjectBase)val).Pointer;
			int size = IntPtr.Size;
			if (_loopedData)
			{
				_lastSample = 0;
				_loopedData = false;
			}
			else
			{
				_lastSample = num;
			}
			float[] array = new float[num2];
			InteropUtilities.Copy(pointer, size, num2, array);
			bool isTalking = false;
			_amplitude = 0f;
			for (int i = 0; i < num2; i++)
			{
				float num3 = array[i] * 10f;
				SampleBuffer[i] = num3;
				_amplitude += System.Math.Abs(num3);
				if (!isTalking)
				{
					isTalking = System.Math.Abs(num3) >= 0.3f;
				}
			}
			if (num2 > 0)
			{
				_amplitude /= num2;
			}
			CheckTalkingTimeout(ref isTalking);
			_hasVoiceActivity = isTalking;
			if (!isTalking)
			{
				_amplitude = 0f;
				_encodedData = null;
				return;
			}
			SendToSources(SampleBuffer, num2);
			short[] array2 = new short[num2];
			VoiceConverter.CopySamples(array, array2, num2);
			_encodedData = VoiceConverter.Encode(array2);
		}

		private static void SendToSources(float[] buffer, int sampleCount)
		{
			IEnumerable<VoiceSource> voicesByID = VoiceSourceManager.GetVoicesByID(PlayerIDManager.LocalSmallID);
			if (voicesByID.Any())
			{
				float volumeMultiplier = VoiceVolume.GetVolumeMultiplier();
				float num = volumeMultiplier * volumeMultiplier;
				float num2 = 0f;
				for (int i = 0; i < sampleCount; i++)
				{
					float num3 = buffer[i] * num;
					VoiceSourceManager.EnqueueSample(voicesByID, num3);
					num2 += System.Math.Abs(num3);
				}
				VoiceSourceManager.SetAmplitude(voicesByID, num2);
			}
		}

		private void CheckTalkingTimeout(ref bool isTalking)
		{
			if (isTalking)
			{
				_lastTalkTime = TimeUtilities.TimeSinceStartup;
			}
			else
			{
				isTalking = TimeUtilities.TimeSinceStartup - _lastTalkTime <= 1f;
			}
		}

		public void Enable()
		{
		}

		public void Disable()
		{
			_encodedData = null;
			_hasVoiceActivity = false;
		}
	}
	public class UnityVoiceSpeaker : VoiceSpeaker
	{
		public override float Amplitude { get; set; }

		public UnityVoiceSpeaker(PlayerID id)
		{
			_id = id;
			ContactsList.OnContactUpdated += OnContactUpdated;
			OnContactUpdated(ContactsList.GetContact(id));
		}

		public override void Cleanup()
		{
			ContactsList.OnContactUpdated -= OnContactUpdated;
		}

		private void OnContactUpdated(Contact contact)
		{
			if (contact.id == _id.PlatformID)
			{
				base.Volume = contact.volume;
			}
		}

		public override void OnVoiceDataReceived(byte[] data)
		{
			short[] array = VoiceConverter.Decode(data);
			int num = array.Length;
			float[] array2 = new float[num];
			VoiceConverter.CopySamples(array, array2, num);
			float num2 = VoiceVolume.GetVolumeMultiplier() * base.Volume;
			float num3 = num2 * num2;
			float num4 = 0f;
			IEnumerable<VoiceSource> voicesByID = VoiceSourceManager.GetVoicesByID(base.ID.SmallID);
			for (int i = 0; i < num; i++)
			{
				float num5 = array2[i] * num3 * 10f;
				VoiceSourceManager.EnqueueSample(voicesByID, num5);
				num4 += System.Math.Abs(num5);
			}
			if (num > 0)
			{
				num4 /= (float)num;
			}
			Amplitude = num4;
			VoiceSourceManager.SetAmplitude(voicesByID, num4);
		}
	}
}
namespace LabFusion.Utilities
{
	public static class AssemblyUtilities
	{
		public static bool IsValid(this Assembly assembly)
		{
			if (assembly.FullName.Contains("System"))
			{
				return false;
			}
			return true;
		}

		public static bool IsValid(this Type type)
		{
			if (type.Name.Contains("Mono") && type.Name.Contains("Security"))
			{
				return false;
			}
			return true;
		}

		public static void LoadAllValid<T>(Assembly assembly, Action<Type> runOnValid)
		{
			if (!assembly.IsValid())
			{
				return;
			}
			Type[] types = assembly.GetTypes();
			foreach (Type type in types)
			{
				if (type.IsValid() && typeof(T).IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface)
				{
					try
					{
						runOnValid(type);
					}
					catch (Exception ex)
					{
						FusionLogger.Error(ex.Message);
					}
				}
			}
		}
	}
	public static class ConstrainerUtilities
	{
		private static Action _constrainerCreatedCallback;

		public const string ConstrainerAssetGUID = "bf9c97bf88c22dc4f981578e75d9aa12";

		public static bool PlayerConstraintsEnabled => LobbyInfoManager.LobbyInfo.PlayerConstraining;

		public static bool HasConstrainer => (Object)(object)GlobalConstrainer != (Object)null;

		public static Constrainer GlobalConstrainer { get; private set; }

		public static void OnMainSceneInitialized()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			SpawnableCrate crate = CrateFilterer.GetCrate<SpawnableCrate>(((ScannableReference)BonelabSpawnableReferences.ConstrainerReference).Barcode);
			if (!((Object)(object)crate == (Object)null))
			{
				if (!((Crate)crate).Pallet.IsInMarrowGame())
				{
					((Crate)crate).MainAsset = new MarrowAsset("bf9c97bf88c22dc4f981578e75d9aa12");
				}
				Action<GameObject> action = OnConstrainerLoaded;
				((CrateT<GameObject>)(object)crate).LoadAsset(Action<GameObject>.op_Implicit(action));
			}
		}

		private static void OnConstrainerLoaded(GameObject go)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)go == (Object)null)
			{
				_constrainerCreatedCallback = null;
				return;
			}
			GameObject obj = Object.Instantiate<GameObject>(go, new Vector3(1000f, 1000f, 1000f), QuaternionExtensions.identity);
			GlobalConstrainer = obj.GetComponent<Constrainer>();
			obj.SetActive(false);
			_constrainerCreatedCallback?.InvokeSafe("executing Constrainer Created callback");
			_constrainerCreatedCallback = null;
		}

		public static void HookConstrainerCreated(Action callback)
		{
			if (HasConstrainer)
			{
				callback?.Invoke();
			}
			else
			{
				_constrainerCreatedCallback = (Action)Delegate.Combine(_constrainerCreatedCallback, callback);
			}
		}
	}
	public static class DelayUtilities
	{
		private class FrameDelayInfo
		{
			public Action Action;

			public int Counter;
		}

		private static readonly List<FrameDelayInfo> _delays = new List<FrameDelayInfo>();

		public static void InvokeDelayed(Action action, int frames)
		{
			_delays.Add(new FrameDelayInfo
			{
				Action = action,
				Counter = frames
			});
		}

		public static void InvokeNextFrame(Action action)
		{
			InvokeDelayed(action, 1);
		}

		internal static void OnProcessDelays()
		{
			for (int num = _delays.Count - 1; num >= 0; num--)
			{
				FrameDelayInfo frameDelayInfo = _delays[num];
				if (frameDelayInfo.Counter <= 0)
				{
					try
					{
						frameDelayInfo.Action();
					}
					catch (Exception ex)
					{
						FusionLogger.Error(ex.ToString());
					}
					_delays.RemoveAt(num);
				}
				else
				{
					frameDelayInfo.Counter--;
				}
			}
		}
	}
	public static class DllTools
	{
		[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
		public static extern IntPtr LoadLibrary(string lpLibFileName);

		[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
		public static extern bool FreeLibrary(IntPtr hModule);

		[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
		public static extern uint GetLastError();
	}
	public readonly struct FrameBool
	{
		private readonly bool _value;

		private readonly int _frame;

		public bool Value
		{
			get
			{
				if (_value)
				{
					return Valid;
				}
				return false;
			}
		}

		public int Frame => _frame;

		public bool Valid => TimeUtilities.FrameCount == Frame;

		public FrameBool(bool value)
		{
			_value = value;
			_frame = TimeUtilities.FrameCount;
		}

		public static implicit operator bool(FrameBool value)
		{
			return value.Value;
		}

		public static implicit operator FrameBool(bool value)
		{
			return new FrameBool(value);
		}
	}
	public class FusionComponentCache<TSource, TComponent> where TSource : Object where TComponent : class
	{
		private readonly Dictionary<TSource, TComponent> _cache = new Dictionary<TSource, TComponent>((IEqualityComparer<TSource>?)new UnityComparer());

		public ICollection<TComponent> Components => _cache.Values;

		public TComponent Get(TSource source)
		{
			if (_cache.TryGetValue(source, out var value))
			{
				return value;
			}
			return null;
		}

		public bool TryGet(TSource source, out TComponent value)
		{
			return _cache.TryGetValue(source, out value);
		}

		public bool ContainsSource(TSource source)
		{
			return _cache.ContainsKey(source);
		}

		public void Add(TSource source, TComponent component)
		{
			if (_cache.ContainsKey(source))
			{
				_cache[source] = component;
			}
			else
			{
				_cache.Add(source, component);
			}
		}

		public void Remove(TSource source)
		{
			_cache.Remove(source);
		}
	}
	public static class FusionDevTools
	{
		public static bool DevToolsDisabled
		{
			get
			{
				if (GamemodeManager.IsGamemodeStarted && GamemodeManager.ActiveGamemode.DisableDevTools)
				{
					return true;
				}
				return false;
			}
		}

		public static bool DespawnConstrainer(PlayerID id)
		{
			FusionPermissions.FetchPermissionLevel(id, out var level, out var _);
			if (!FusionPermissions.HasSufficientPermissions(level, LobbyInfoManager.LobbyInfo.Constrainer))
			{
				return true;
			}
			return false;
		}

		public static bool DespawnDevTool(PlayerID id)
		{
			if (DevToolsDisabled)
			{
				return true;
			}
			FusionPermissions.FetchPermissionLevel(id, out var level, out var _);
			if (!FusionPermissions.HasSufficientPermissions(level, LobbyInfoManager.LobbyInfo.DevTools))
			{
				return true;
			}
			return false;
		}

		public static bool PreventSpawnGun(PlayerID id)
		{
			if (GamemodeManager.IsGamemodeStarted && GamemodeManager.ActiveGamemode.DisableSpawnGun)
			{
				return true;
			}
			FusionPermissions.FetchPermissionLevel(id, out var level, out var _);
			if (!FusionPermissions.HasSufficientPermissions(level, LobbyInfoManager.LobbyInfo.DevTools))
			{
				return true;
			}
			return false;
		}
	}
	internal static class FusionLogger
	{
		internal static void LogLine([CallerLineNumber] int lineNumber = 0)
		{
			Log($"FusionLogger.LogLine is only for debugging! Please remove from line {lineNumber}", ConsoleColor.Red);
		}

		internal static void Log(string txt, ConsoleColor txt_color = ConsoleColor.White)
		{
			((MelonBase)FusionMod.Instance).LoggerInstance.Msg(txt_color, txt);
		}

		internal static void Log(object obj, ConsoleColor txt_color = ConsoleColor.White)
		{
			((MelonBase)FusionMod.Instance).LoggerInstance.Msg(txt_color, obj);
		}

		internal static void Warn(string txt)
		{
			((MelonBase)FusionMod.Instance).LoggerInstance.Warning(txt);
		}

		internal static void Warn(object obj)
		{
			((MelonBase)FusionMod.Instance).LoggerInstance.Warning(obj);
		}

		internal static void Error(string txt)
		{
			((MelonBase)FusionMod.Instance).LoggerInstance.Error(txt);
		}

		internal static void ErrorLine(string txt, [CallerLineNumber] int lineNumber = 0)
		{
			((MelonBase)FusionMod.Instance).LoggerInstance.Error($"{txt} - Line: {lineNumber}");
		}

		internal static void Error(object obj)
		{
			((MelonBase)FusionMod.Instance).LoggerInstance.Error(obj);
		}

		internal static void LogException(string task, Exception e)
		{
			if (e.InnerException != null)
			{
				e = e.InnerException;
			}
			Error($"Failed {task} with reason: {e.Message}\nTrace:{e.StackTrace}");
		}
	}
	public delegate bool UserOverride(PlayerID id);
	public static class FusionOverrides
	{
		private static UserOverride _onValidateNametag;

		public static event UserOverride OnValidateNametag
		{
			add
			{
				_onValidateNametag = (UserOverride)Delegate.Combine(_onValidateNametag, value);
				ForceUpdateOverrides();
			}
			remove
			{
				_onValidateNametag = (UserOverride)Delegate.Remove(_onValidateNametag, value);
				ForceUpdateOverrides();
			}
		}

		public static event Action OnOverridesChanged;

		public static bool ValidateNametag(PlayerID id)
		{
			if (_onValidateNametag == null)
			{
				return true;
			}
			Delegate[] invocationList = _onValidateNametag.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				if (!((UserOverride)invocationList[i])(id))
				{
					return false;
				}
			}
			return true;
		}

		public static void ForceUpdateOverrides()
		{
			FusionOverrides.OnOverridesChanged.InvokeSafe("executing OnOverridesChanged");
		}
	}
	public static class FusionPlayer
	{
		public static readonly List<Transform> SpawnPoints = new List<Transform>();

		private static bool _brokeBounds = false;

		public static byte? LastAttacker { get; internal set; }

		internal static void OnMainSceneInitialized()
		{
			LastAttacker = null;
			if (_brokeBounds)
			{
				Physics.autoSimulation = true;
				_brokeBounds = false;
			}
		}

		internal static void OnUpdate()
		{
			if (!FusionSceneManager.IsLoading() && RigData.HasPlayer)
			{
				CheckFloatingPoint();
			}
		}

		private static void CheckFloatingPoint()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkTransformManager.IsInBounds(RigData.Refs.RigManager.physicsRig.feet.transform.position))
			{
				Physics.autoSimulation = false;
				_brokeBounds = true;
				if (NetworkInfo.HasServer && !NetworkInfo.IsHost)
				{
					NetworkHelper.Disconnect("Left Bounds");
				}
				SceneStreamer.Reload();
				Notifier.Send(new Notification
				{
					ShowPopup = true,
					Title = "Whoops! Sorry about that!",
					Type = NotificationType.WARNING,
					Message = "The scene was reloaded due to being sent far out of bounds.",
					PopupLength = 6f
				});
			}
		}

		public static bool TryGetLastAttacker(out PlayerID id)
		{
			id = null;
			if (!LastAttacker.HasValue)
			{
				return false;
			}
			id = PlayerIDManager.GetPlayerID(LastAttacker.Value);
			return id != null;
		}

		public static bool IsLocalPlayer(this RigManager rigManager)
		{
			if (!RigData.HasPlayer)
			{
				return true;
			}
			return (Object)(object)rigManager == (Object)(object)RigData.Refs.RigManager;
		}

		public static void SetSpawnPoints(params Transform[] points)
		{
			SpawnPoints.Clear();
			SpawnPoints.AddRange(points);
		}

		public static void ResetSpawnPoints()
		{
			SpawnPoints.Clear();
		}

		public static bool TryGetSpawnPoint(out Transform point)
		{
			point = null;
			SpawnPoints.RemoveAll((Transform t) => (Object)(object)t == (Object)null);
			if (SpawnPoints.Count > 0)
			{
				point = SpawnPoints.GetRandom();
				return true;
			}
			return false;
		}
	}
	public delegate bool UserAccessEvent(PlayerID playerId, out string reason);
	public delegate void ServerEvent();
	public delegate void UpdateEvent();
	public delegate void PlayerUpdate(PlayerID playerId);
	public delegate void PlayerAction(PlayerID playerId, PlayerActionType type, PlayerID otherPlayer = null);
	public static class MultiplayerHooking
	{
		public static event UserAccessEvent OnShouldAllowConnection;

		public static event ServerEvent OnStartedServer;

		public static event ServerEvent OnJoinedServer;

		public static event ServerEvent OnDisconnected;

		public static event PlayerUpdate OnPlayerJoined;

		public static event PlayerUpdate OnPlayerLeft;

		public static event PlayerAction OnPlayerAction;

		public static event UpdateEvent OnUpdate;

		public static event UpdateEvent OnFixedUpdate;

		public static event UpdateEvent OnLateUpdate;

		public static event UpdateEvent OnMainSceneInitialized;

		public static event UpdateEvent OnLoadingBegin;

		public static event UpdateEvent OnTargetLevelLoaded;

		internal static bool CheckShouldAllowConnection(PlayerID playerId, out string reason)
		{
			reason = "";
			if (MultiplayerHooking.OnShouldAllowConnection == null)
			{
				return true;
			}
			Delegate[] invocationList = MultiplayerHooking.OnShouldAllowConnection.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				if (!((UserAccessEvent)invocationList[i])(playerId, out reason))
				{
					return false;
				}
			}
			return true;
		}

		internal static void InvokeOnStartedServer()
		{
			MultiplayerHooking.OnStartedServer.InvokeSafe("executing OnStartedServer hook");
		}

		internal static void InvokeOnJoinedServer()
		{
			MultiplayerHooking.OnJoinedServer.InvokeSafe("executing OnJoinedServer hook");
		}

		internal static void InvokeOnDisconnected()
		{
			MultiplayerHooking.OnDisconnected.InvokeSafe("executing OnDisconnected hook");
		}

		internal static void InvokeOnPlayerJoined(PlayerID id)
		{
			MultiplayerHooking.OnPlayerJoined.InvokeSafe(id, "executing OnPlayerJoined hook");
		}

		internal static void InvokeOnPlayerLeft(PlayerID id)
		{
			MultiplayerHooking.OnPlayerLeft.InvokeSafe(id, "executing OnPlayerLeft hook");
		}

		internal static void InvokeOnPlayerAction(PlayerID id, PlayerActionType type, PlayerID otherPlayer = null)
		{
			MultiplayerHooking.OnPlayerAction.InvokeSafe(id, type, otherPlayer, "executing OnPlayerAction hook");
		}

		internal static void InvokeOnUpdate()
		{
			MultiplayerHooking.OnUpdate?.Invoke();
		}

		internal static void InvokeOnFixedUpdate()
		{
			MultiplayerHooking.OnFixedUpdate?.Invoke();
		}

		internal static void InvokeOnLateUpdate()
		{
			MultiplayerHooking.OnLateUpdate?.Invoke();
		}

		internal static void InvokeOnMainSceneInitialized()
		{
			MultiplayerHooking.OnMainSceneInitialized.InvokeSafe("executing OnMainSceneInitialized hook");
		}

		internal static void InvokeOnLoadingBegin()
		{
			MultiplayerHooking.OnLoadingBegin.InvokeSafe("executing OnLoadingBegin hook");
		}

		internal static void InvokeTargetLevelLoaded()
		{
			MultiplayerHooking.OnTargetLevelLoaded.InvokeSafe("executing OnTargetLevelLoaded hook");
		}
	}
	public static class GameObjectUtilities
	{
		private static readonly List<GameObject> _rootObjectBuffer = new List<GameObject>();

		internal static List<GameObject> FindRootsWithName(string scene, string name)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			Scene sceneByName = SceneManager.GetSceneByName(scene);
			if (!((Scene)(ref sceneByName)).IsValid())
			{
				return null;
			}
			_rootObjectBuffer.Capacity = ((Scene)(ref sceneByName)).rootCount;
			((Scene)(ref sceneByName)).GetRootGameObjects(_rootObjectBuffer);
			_rootObjectBuffer.RemoveAll(Predicate<GameObject>.op_Implicit((Func<GameObject, bool>)((GameObject g) => ((Object)g).name != name)));
			return _rootObjectBuffer;
		}

		internal static int GetRootIndex(this GameObject go)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			Scene scene = go.scene;
			return FindRootsWithName(((Scene)(ref scene)).name, ((Object)go).name).FindIndex(Predicate<GameObject>.op_Implicit((Func<GameObject, bool>)((GameObject g) => (Object)(object)g == (Object)(object)go)));
		}

		internal static GameObject GetRootByIndex(string scene, int index, string name)
		{
			List<GameObject> val = FindRootsWithName(scene, name);
			if (val == null || val.Count == 0)
			{
				return GameObject.Find("/" + name);
			}
			if (val.Count <= index)
			{
				return val[val.Count - 1];
			}
			return val[index];
		}

		public static string GetFullPath(this GameObject go)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(0, 4);
				Scene scene = go.scene;
				defaultInterpolatedStringHandler.AppendFormatted(((Scene)(ref scene)).name);
				defaultInterpolatedStringHandler.AppendFormatted('¬');
				defaultInterpolatedStringHandler.AppendFormatted(((Component)go.transform.root).gameObject.GetRootIndex());
				defaultInterpolatedStringHandler.AppendFormatted(go.transform.GetBasePath());
				return defaultInterpolatedStringHandler.ToStringAndClear();
			}
			catch
			{
			}
			return "INVALID_PATH";
		}

		public static GameObject GetGameObject(string path)
		{
			string[] array = path.Split('¬');
			string scene = array[0];
			int index = int.Parse(array[1]);
			string name = array[2];
			try
			{
				GameObject rootByIndex = GetRootByIndex(scene, index, name);
				if ((Object)(object)rootByIndex != (Object)null)
				{
					Transform val = rootByIndex.transform;
					for (int i = 3; i < array.Length; i++)
					{
						val = val.GetTransformByIndex(int.Parse(array[i++]), array[i]);
					}
					return ((Component)val).gameObject;
				}
			}
			catch (Exception)
			{
			}
			return null;
		}
	}
	public static class ImpactUtilities
	{
		public static void OnHitRigidbody(Rigidbody rb)
		{
			GameObject gameObject = ((Component)rb).gameObject;
			MarrowBody marrowBody = MarrowBody.Cache.Get(gameObject);
			if ((Object)(object)marrowBody == (Object)null)
			{
				return;
			}
			if (MarrowBodyExtender.Cache.TryGet(marrowBody, out var value))
			{
				if (!value.IsOwnerLocked)
				{
					GripExtender extender = value.GetExtender<GripExtender>();
					if (extender == null || !extender.CheckHeld())
					{
						NetworkEntityManager.TakeOwnership(value);
					}
				}
			}
			else
			{
				DelayUtilities.InvokeDelayed(delegate
				{
					PropSender.SendPropCreation(marrowBody.Entity);
				}, 4);
			}
		}
	}
	internal static class PersistentAssetCreator
	{
		private const string _targetFont = "arlon-medium";

		private static Action<HandPose> _onSoftGrabLoaded;

		internal static TMP_FontAsset Font { get; private set; }

		internal static HandPose SoftGrabPose { get; private set; }

		internal static void OnLateInitializeMelon()
		{
			CreateTextFont();
		}

		internal static void OnMainSceneInitialized()
		{
			GetHandPose();
		}

		private static void GetHandPose()
		{
			if (RigData.HasPlayer)
			{
				SoftGrabPose = RigData.Refs.RigManager.worldGripHandPose;
			}
			if ((Object)(object)SoftGrabPose != (Object)null)
			{
				_onSoftGrabLoaded?.Invoke(SoftGrabPose);
			}
			_onSoftGrabLoaded = null;
		}

		public static void HookOnSoftGrabLoaded(Action<HandPose> action)
		{
			if ((Object)(object)SoftGrabPose != (Object)null)
			{
				action?.Invoke(SoftGrabPose);
			}
			else
			{
				_onSoftGrabLoaded = (Action<HandPose>)Delegate.Combine(_onSoftGrabLoaded, action);
			}
		}

		private static void CreateTextFont()
		{
			Il2CppArrayBase<TMP_FontAsset> val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset item in val)
			{
				if (((Object)item).name.ToLower().Contains("arlon-medium"))
				{
					Font = item;
					break;
				}
			}
			if ((Object)(object)Font == (Object)null)
			{
				Font = val[0];
			}
		}

		internal static void SetupImpactProperties(RigManager rig)
		{
			PhysicsRig physicsRig = rig.physicsRig;
			Il2CppArrayBase<Rigidbody> componentsInChildren = ((Component)physicsRig).GetComponentsInChildren<Rigidbody>(true);
			SurfaceData surfaceData = physicsRig._surfaceDataDefault;
			Avatar avatar = rig.avatar;
			if ((Object)(object)avatar != (Object)null && Object.op_Implicit((Object)(object)avatar.surfaceData))
			{
				surfaceData = avatar.surfaceData;
			}
			List<ImpactProperties> list = new List<ImpactProperties>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Rigidbody obj = componentsInChildren[i];
				GameObject gameObject = ((Component)obj).gameObject;
				if (!Object.op_Implicit((Object)(object)((Component)obj).GetComponent<ImpactProperties>()) && !((Object)(object)gameObject == (Object)(object)physicsRig.knee) && !((Object)(object)gameObject == (Object)(object)physicsRig.feet))
				{
					ImpactProperties val = gameObject.AddComponent<ImpactProperties>();
					val.surfaceData = surfaceData;
					val.decalType = (DecalType)(-1);
					list.Add(val);
				}
			}
			physicsRig._impactProperties = new Il2CppReferenceArray<ImpactProperties>(list.ToArray());
		}
	}
	internal static class SafeEvents
	{
		internal static void InvokeSafe<T>(this T action, string task) where T : Delegate
		{
			if ((Delegate?)action == (Delegate?)null)
			{
				return;
			}
			Delegate[] invocationList = action.GetInvocationList();
			foreach (Delegate @delegate in invocationList)
			{
				try
				{
					@delegate.DynamicInvoke();
				}
				catch (Exception e)
				{
					FusionLogger.LogException(task, e);
				}
			}
		}

		internal static void InvokeSafe<T, T1>(this T action, T1 param, string task) where T : Delegate
		{
			if ((Delegate?)action == (Delegate?)null)
			{
				return;
			}
			Delegate[] invocationList = action.GetInvocationList();
			foreach (Delegate @delegate in invocationList)
			{
				try
				{
					@delegate.DynamicInvoke(param);
				}
				catch (Exception e)
				{
					FusionLogger.LogException(task, e);
				}
			}
		}

		internal static void InvokeSafe<T, T1, T2>(this T action, T1 param1, T2 param2, string task) where T : Delegate
		{
			if ((Delegate?)action == (Delegate?)null)
			{
				return;
			}
			Delegate[] invocationList = action.GetInvocationList();
			foreach (Delegate @delegate in invocationList)
			{
				try
				{
					@delegate.DynamicInvoke(param1, param2);
				}
				catch (Exception e)
				{
					FusionLogger.LogException(task, e);
				}
			}
		}

		internal static void InvokeSafe<T, T1, T2, T3>(this T action, T1 param1, T2 param2, T3 param3, string task) where T : Delegate
		{
			if ((Delegate?)action == (Delegate?)null)
			{
				return;
			}
			Delegate[] invocationList = action.GetInvocationList();
			foreach (Delegate @delegate in invocationList)
			{
				try
				{
					@delegate.DynamicInvoke(param1, param2, param3);
				}
				catch (Exception e)
				{
					FusionLogger.LogException(task, e);
				}
			}
		}
	}
	internal static class TimeUtilities
	{
		private static float _deltaTime = 1f;

		private static float _fixedDeltaTime = 0.02f;

		private static float _timeSinceStartup = 0f;

		private static float _timeScale = 1f;

		private static int _frameCount = 0;

		public static float DeltaTime => _deltaTime;

		public static float FixedDeltaTime => _fixedDeltaTime;

		public static float TimeSinceStartup => _timeSinceStartup;

		public static float TimeScale => _timeScale;

		public static int FrameCount => _frameCount;

		internal static void OnEarlyUpdate()
		{
			_timeScale = Time.timeScale;
			_deltaTime = Time.deltaTime;
			_timeSinceStartup += _deltaTime;
			_frameCount++;
		}

		internal static void OnEarlyFixedUpdate()
		{
			_fixedDeltaTime = Time.fixedDeltaTime;
		}

		public static bool IsMatchingFrame(int interval)
		{
			return FrameCount % interval == 0;
		}

		public static bool IsMatchingFrame(int interval, int offset)
		{
			return (FrameCount + offset) % interval == 0;
		}
	}
	public static class InteropUtilities
	{
		public unsafe static void FloatArrayFastWrite(IntPtr pointer, int size, int index, float value)
		{
			*(float*)((byte*)IntPtr.Add(pointer, 4 * size).ToPointer() + (nint)index * (nint)4) = value;
		}

		public unsafe static float FloatArrayFastRead(IntPtr pointer, int size, int index)
		{
			return *(float*)((byte*)IntPtr.Add(pointer, 4 * size).ToPointer() + (nint)index * (nint)4);
		}

		public static void Copy(IntPtr pointer, int size, int length, float[] array)
		{
			for (int i = 0; i < length; i++)
			{
				array[i] = FloatArrayFastRead(pointer, size, i);
			}
		}
	}
	public static class MagazineUtilities
	{
		public static void ClaimMagazine(Magazine magazine, InventoryAmmoReceiver ammoReceiver)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			CartridgeData val = ammoReceiver.defaultLightCart;
			if ((Object)(object)ammoReceiver._selectedCartridgeData != (Object)null)
			{
				val = ammoReceiver._selectedCartridgeData;
			}
			if ((Object)(object)val != (Object)null && (Object)(object)val.projectile != (Object)null)
			{
				ProjectileEmitter.Register(val.projectile);
			}
			magazine.Initialize(val, AmmoInventory.Instance.GetCartridgeCount(val));
			magazine.Claim();
			LocalAudioPlayer.PlayAtPoint(Il2CppArrayBase<AudioClip>.op_Implicit((Il2CppArrayBase<AudioClip>)(object)ammoReceiver.grabClips), ((Component)ammoReceiver).transform.position, new AudioPlayerSettings
			{
				Mixer = LocalAudioPlayer.SoftInteraction,
				Volume = 0.2f
			});
		}

		public static void GrabMagazine(Magazine magazine, NetworkPlayer player, Handedness handedness)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			player.HookOnReady(OnPlayerReady);
			void OnPlayerReady()
			{
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Invalid comparison between Unknown and I4
				RigManager rigManager = player.RigRefs.RigManager;
				InventoryAmmoReceiverExtender extender = player.NetworkEntity.GetExtender<InventoryAmmoReceiverExtender>();
				if (extender != null)
				{
					ClaimMagazine(magazine, extender.Component);
				}
				Grip grip = magazine.grip;
				Hand found = (((int)handedness == 0) ? null : (((int)handedness == 1) ? rigManager.physicsRig.leftHand : rigManager.physicsRig.rightHand));
				if (Object.op_Implicit((Object)(object)found))
				{
					DelayUtilities.InvokeNextFrame(delegate
					{
						grip.MoveIntoHand(found);
						grip.TryAttach(found, isInstant: true);
					});
				}
			}
		}
	}
	public static class MuteUIHelper
	{
		private static PageItem _mutePage;

		private static Poolee _indicatorPoolee;

		private static GameObject _indicatorGameObject;

		private static Renderer _indicatorRenderer;

		private static Camera _headsetCamera;

		public const string NotificationTag = "Mute";

		public static void OnInitializeMelon()
		{
			FusionPref<bool> muted = ClientSettings.VoiceChat.Muted;
			muted.OnValueChanged = (Action<bool>)Delegate.Combine(muted.OnValueChanged, new Action<bool>(OnMutedChanged));
			FusionPref<bool> mutedIndicator = ClientSettings.VoiceChat.MutedIndicator;
			mutedIndicator.OnValueChanged = (Action<bool>)Delegate.Combine(mutedIndicator.OnValueChanged, new Action<bool>(OnIndicatorChanged));
			RenderPipelineManager.beginCameraRendering += Action<ScriptableRenderContext, Camera>.op_Implicit((Action<ScriptableRenderContext, Camera>)OnBeginCameraRendering);
			RenderPipelineManager.endCameraRendering += Action<ScriptableRenderContext, Camera>.op_Implicit((Action<ScriptableRenderContext, Camera>)OnEndCameraRendering);
		}

		public static void OnDeinitializeMelon()
		{
			FusionPref<bool> muted = ClientSettings.VoiceChat.Muted;
			muted.OnValueChanged = (Action<bool>)Delegate.Remove(muted.OnValueChanged, new Action<bool>(OnMutedChanged));
			FusionPref<bool> mutedIndicator = ClientSettings.VoiceChat.MutedIndicator;
			mutedIndicator.OnValueChanged = (Action<bool>)Delegate.Remove(mutedIndicator.OnValueChanged, new Action<bool>(OnIndicatorChanged));
			RenderPipelineManager.beginCameraRendering -= Action<ScriptableRenderContext, Camera>.op_Implicit((Action<ScriptableRenderContext, Camera>)OnBeginCameraRendering);
			RenderPipelineManager.endCameraRendering -= Action<ScriptableRenderContext, Camera>.op_Implicit((Action<ScriptableRenderContext, Camera>)OnEndCameraRendering);
		}

		private static void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
		{
			if (!((Object)(object)camera != (Object)(object)_headsetCamera) && !((Object)(object)_indicatorRenderer == (Object)null))
			{
				_indicatorRenderer.enabled = true;
			}
		}

		private static void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
		{
			if (!((Object)(object)camera != (Object)(object)_headsetCamera) && !((Object)(object)_indicatorRenderer == (Object)null))
			{
				_indicatorRenderer.enabled = false;
			}
		}

		private static void OnMutedChanged(bool value)
		{
			if (_mutePage != null)
			{
				_mutePage.name = (value ? "Quick Unmute" : "Quick Mute");
			}
			UpdateMuteIcon();
		}

		private static void OnIndicatorChanged(bool value)
		{
			UpdateMuteIcon();
		}

		private static void UpdateMuteIcon()
		{
			if (!((Object)(object)_indicatorGameObject == (Object)null))
			{
				_indicatorGameObject.SetActive(VoiceInfo.ShowMuteIndicator);
			}
		}

		public static void OnCreateMuteUI(RigManager manager)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (!VoiceInfo.CanTalk)
			{
				return;
			}
			PopUpMenuView popUpMenu = UIRig.Instance.popUpMenu;
			Page homePage = popUpMenu.radialPageView.m_HomePage;
			FusionPref<bool> mutedPref = ClientSettings.VoiceChat.Muted;
			_mutePage = new PageItem(mutedPref.Value ? "Quick Unmute" : "Quick Mute", (Directions)3, Action.op_Implicit((Action)delegate
			{
				mutedPref.Value = !mutedPref.Value;
				popUpMenu.Deactivate();
				Notifier.Cancel("Mute");
				Notifier.Send(new Notification
				{
					ShowPopup = true,
					SaveToMenu = false,
					Message = (mutedPref.Value ? "Muted" : "Unmuted"),
					Tag = "Mute"
				});
			}));
			homePage.items.Add(_mutePage);
			OpenControllerRig val = ((Il2CppObjectBase)manager.ControllerRig).TryCast<OpenControllerRig>();
			Transform headset = val.headset;
			Spawnable spawnable = LocalAssetSpawner.CreateSpawnable(FusionSpawnableReferences.MuteIndicatorReference);
			LocalAssetSpawner.Register(spawnable);
			LocalAssetSpawner.Spawn(spawnable, Vector3.zero, Quaternion.identity, delegate(Poolee poolee)
			{
				//IL_007a: 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)
				_indicatorPoolee = poolee;
				_indicatorGameObject = ((Component)poolee).gameObject;
				_indicatorGameObject.SetActive(false);
				((Object)_indicatorGameObject).name = "Mute Icon [FUSION]";
				_indicatorRenderer = _indicatorGameObject.GetComponentInChildren<Renderer>();
				_indicatorRenderer.enabled = false;
				if (!((Object)(object)headset == (Object)null))
				{
					_headsetCamera = ((Component)headset).GetComponent<Camera>();
					Transform transform = _indicatorGameObject.transform;
					transform.parent = headset;
					transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
					UpdateMuteIcon();
				}
			});
		}

		public static void OnDestroyMuteUI()
		{
			if (_mutePage != null)
			{
				PopUpMenuView popUpMenu = UIRig.Instance.popUpMenu;
				Page homePage = popUpMenu.radialPageView.m_HomePage;
				homePage.items.RemoveAll(Predicate<PageItem>.op_Implicit((Func<PageItem, bool>)((PageItem i) => i.name == _mutePage.name)));
				popUpMenu.radialPageView.Render(homePage);
				_mutePage = null;
			}
			if ((Object)(object)_indicatorPoolee != (Object)null)
			{
				_indicatorPoolee.Despawn();
				_indicatorPoolee = null;
				_indicatorGameObject = null;
				_indicatorRenderer = null;
			}
		}
	}
	public static class PlatformHelper
	{
		private static readonly bool _isAndroidCached = (int)MelonUtils.CurrentPlatform == 3;

		public const string AndroidName = "QUEST";

		public const string WindowsName = "PC";

		public static bool IsAndroid => _isAndroidCached;

		public static string GetPlatformName()
		{
			if (IsAndroid)
			{
				return "QUEST";
			}
			return "PC";
		}
	}
	public static class PlayerAdditionsHelper
	{
		public static void OnInitializeMelon()
		{
			MultiplayerHooking.OnJoinedServer += delegate
			{
				OnEnterServer(RigData.Refs.RigManager);
			};
			MultiplayerHooking.OnStartedServer += delegate
			{
				OnEnterServer(RigData.Refs.RigManager);
			};
			MultiplayerHooking.OnDisconnected += delegate
			{
				OnExitServer(RigData.Refs.RigManager);
			};
			LocalPlayer.OnLocalRigCreated = (Action<RigManager>)Delegate.Combine(LocalPlayer.OnLocalRigCreated, (Action<RigManager>)delegate(RigManager rig)
			{
				if (NetworkInfo.HasServer)
				{
					OnEnterServer(rig);
				}
			});
			MuteUIHelper.OnInitializeMelon();
		}

		public static void OnDeinitializeMelon()
		{
			MuteUIHelper.OnDeinitializeMelon();
		}

		public static void OnEnterServer(RigManager manager)
		{
			if (!((Object)(object)manager == (Object)null))
			{
				MuteUIHelper.OnCreateMuteUI(manager);
				PersistentAssetCreator.SetupImpactProperties(manager);
				manager.health._testVisualDamage = true;
				Player_Health obj = ((Il2CppObjectBase)manager.health).TryCast<Player_Health>();
				obj.reloadLevelOnDeath = false;
				obj.slowMoOnDeath = false;
				PhysicsRig physicsRig = manager.physicsRig;
				((Component)((Rig)physicsRig).m_handLf).gameObject.AddComponent<CollisionSyncer>();
				((Component)((Rig)physicsRig).m_elbowLf).gameObject.AddComponent<CollisionSyncer>();
				((Component)((Rig)physicsRig).m_shoulderLf).gameObject.AddComponent<CollisionSyncer>();
				((Component)((Rig)physicsRig).m_handRt).gameObject.AddComponent<CollisionSyncer>();
				((Component)((Rig)physicsRig).m_elbowRt).gameObject.AddComponent<CollisionSyncer>();
				((Component)((Rig)physicsRig).m_shoulderRt).gameObject.AddComponent<CollisionSyncer>();
				physicsRig.feet.gameObject.AddComponent<CollisionSyncer>();
				((Component)((Rig)physicsRig).m_head).gameObject.AddComponent<CollisionSyncer>();
			}
		}

		public static void OnExitServer(RigManager manager)
		{
			if ((Object)(object)manager == (Object)null)
			{
				return;
			}
			MuteUIHelper.OnDestroyMuteUI();
			manager.physicsRig._impactProperties = new Il2CppReferenceArray<ImpactProperties>(0L);
			foreach (ImpactProperties componentsInChild in ((Component)manager).GetComponentsInChildren<ImpactProperties>(true))
			{
				Object.Destroy((Object)(object)componentsInChild);
			}
			foreach (CollisionSyncer componentsInChild2 in ((Component)manager).GetComponentsInChildren<CollisionSyncer>(true))
			{
				Object.Destroy((Object)(object)componentsInChild2);
			}
			manager.health._testVisualDamage = false;
			((Il2CppObjectBase)manager.health).TryCast<Player_Health>().slowMoOnDeath = true;
		}
	}
	public static class PooleeUtilities
	{
		public static void DespawnAll()
		{
			if (!NetworkInfo.IsHost)
			{
				return;
			}
			NetworkEntity[] array = NetworkEntityManager.IDManager.RegisteredEntities.EntityIDLookup.Keys.ToArray();
			foreach (NetworkEntity networkEntity in array)
			{
				if (networkEntity.GetExtender<NetworkProp>() != null)
				{
					PooleeExtender extender = networkEntity.GetExtender<PooleeExtender>();
					if (extender != null)
					{
						extender.Component.Despawn();
					}
				}
			}
		}

		public static void SendDespawn(ushort entityId, bool despawnEffect)
		{
			if (NetworkInfo.IsHost)
			{
				MessageRelay.RelayNative(new DespawnResponseData
				{
					Despawner = new PlayerReference(PlayerIDManager.LocalSmallID),
					Entity = new NetworkEntityReference(entityId),
					DespawnEffect = despawnEffect
				}, NativeMessageTag.DespawnResponse, CommonMessageRoutes.ReliableToOtherClients);
			}
			else
			{
				RequestDespawn(entityId, despawnEffect);
			}
		}

		public static void RequestDespawn(ushort entityId, bool despawnEffect)
		{
			MessageRelay.RelayNative(new DespawnRequestData
			{
				Entity = new NetworkEntityReference(entityId),
				DespawnEffect = despawnEffect
			}, NativeMessageTag.DespawnRequest, CommonMessageRoutes.ReliableToServer);
		}

		public static void RequestSpawn(string barcode, SerializedTransform serializedTransform, uint trackerId, bool spawnEffect)
		{
			MessageRelay.RelayNative(SpawnRequestData.Create(barcode, serializedTransform, trackerId, spawnEffect), NativeMessageTag.SpawnRequest, CommonMessageRoutes.ReliableToServer);
		}

		public static void SendSpawn(byte owner, string barcode, ushort syncId, SerializedTransform serializedTransform, uint trackerId = 0u, bool spawnEffect = false)
		{
			MessageRelay.RelayNative(SpawnResponseData.Create(owner, barcode, syncId, serializedTransform, trackerId, spawnEffect), NativeMessageTag.SpawnResponse, CommonMessageRoutes.ReliableToClients);
		}
	}
	public static class TriggerUtilities
	{
		public static bool IsMatchingRig(TriggerRefProxy proxy, RigManager rig)
		{
			if (!NetworkInfo.HasServer || !RigData.HasPlayer)
			{
				return true;
			}
			RigManager val;
			if (Object.op_Implicit((Object)(object)proxy.root) && Object.op_Implicit((Object)(object)(val = RigManager.Cache.Get(proxy.root))))
			{
				return (Object)(object)val == (Object)(object)rig;
			}
			return false;
		}
	}
	public static class LaserCursorUtilities
	{
		public static void CreateLaserCursor(Action<LaserCursor> onCursorReady = null)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Spawnable spawnable = LocalAssetSpawner.CreateSpawnable(FusionSpawnableReferences.LaserCursorReference);
			LocalAssetSpawner.Register(spawnable);
			LocalAssetSpawner.Spawn(spawnable, Vector3.zero, Quaternion.identity, delegate(Poolee poolee)
			{
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00db: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0107: Unknown result type (might be due to invalid IL or missing references)
				//IL_010c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0111: Unknown result type (might be due to invalid IL or missing references)
				//IL_0118: Expected O, but got Unknown
				GameObject gameObject = ((Component)poolee).gameObject;
				Transform transform = gameObject.transform;
				gameObject.SetActive(false);
				LaserCursor cursor = gameObject.AddComponent<LaserCursor>();
				PageElementView val = transform.Find("Arrow").SetupPageElementView();
				PageElementView val2 = transform.Find("ray_start").SetupPageElementView();
				PageElementView val3 = transform.Find("ray_mid").SetupPageElementView();
				PageElementView val4 = transform.Find("ray_mid2").SetupPageElementView();
				PageElementView val5 = transform.Find("ray_bez").SetupPageElementView();
				PageElementView val6 = transform.Find("ray_end").SetupPageElementView();
				PageElementView rayPulse = transform.Find("ray_pulse").SetupPageElementView();
				PageElementView val7 = transform.Find("SFX").SetupPageElementView();
				AnimationCurve blipCurve = (val4.blipCurve = (val3.blipCurve = (val2.blipCurve = new AnimationCurve((Keyframe[])(object)new Keyframe[4]
				{
					new Keyframe(0f, 1f),
					new Keyframe(0.1271991f, 1.953225f),
					new Keyframe(0.724905f, 0.9818711f),
					new Keyframe(1f, 1f)
				}))));
				val6.blipCurve = blipCurve;
				DrawBezierCurve val11 = ((Component)val).gameObject.AddComponent<DrawBezierCurve>();
				val11.Point1 = ((Component)val6).gameObject;
				val11.Point2 = ((Component)val5).gameObject;
				val11.Point3 = ((Component)val3).gameObject;
				val11.Point4 = ((Component)val2).gameObject;
				val11.lineSteps = 12;
				val11.linePercentageFill = 0.73f;
				PrismaticSFX prismaticSFX = ((Component)val7).gameObject.AddComponent<PrismaticSFX>();
				prismaticSFX.velocityTran = ((Component)val7).transform;
				prismaticSFX.sourceTran = ((Component)val7).transform;
				prismaticSFX.minSpeed = 0.2f;
				prismaticSFX.maxSpeed = 4f;
				prismaticSFX.sourceMinDistance = 1f;
				prismaticSFX.pitchMod = 1f;
				prismaticSFX.loopClips = true;
				AudioLoader.LoadMonoDisc(FusionMonoDiscReferences.LaserPrismaticSFXReference, delegate(AudioClip clip)
				{
					prismaticSFX.modulatedClips = Il2CppReferenceArray<AudioClip>.op_Implicit((AudioClip[])(object)new AudioClip[1] { clip });
				});
				prismaticSFX.SpatialBlend = 0.98f;
				cursor.cursorStart = val2;
				cursor.cursorEnd = val6;
				cursor.cursorMid = val3;
				cursor.cursorMid2 = val4;
				cursor.cursorBez = val5;
				cursor.rayPulse = rayPulse;
				cursor.lineEnd = val;
				cursor.cursorLine = ((Component)val).GetComponent<LineRenderer>();
				cursor.bezCurve = val11;
				cursor.pulseLength = 0.2f;
				cursor.pulseAceleration = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
				AudioLoader.LoadMonoDisc(FusionMonoDiscReferences.LaserPulseReference, delegate(AudioClip clip)
				{
					cursor.pulseSound = Il2CppReferenceArray<AudioClip>.op_Implicit((AudioClip[])(object)new AudioClip[1] { clip });
				});
				AudioLoader.LoadMonoDisc(FusionMonoDiscReferences.LaserRaySpawnReference, delegate(AudioClip clip)
				{
					cursor.raySpawn = Il2CppReferenceArray<AudioClip>.op_Implicit((AudioClip[])(object)new AudioClip[1] { clip });
				});
				AudioLoader.LoadMonoDisc(FusionMonoDiscReferences.LaserRayDespawnReference, delegate(AudioClip clip)
				{
					cursor.rayDespawn = Il2CppReferenceArray<AudioClip>.op_Implicit((AudioClip[])(object)new AudioClip[1] { clip });
				});
				cursor.prismaticSFX = prismaticSFX;
				cursor.spatialBlend = 1f;
				cursor._sourceVolume = 0.3f;
				cursor._sourceRadius = 1f;
				cursor.cursorHidden = true;
				cursor.canShowCursor = true;
				cursor.maxMillimeters = 16f;
				onCursorReady?.Invoke(cursor);
			});
		}

		private static PageElementView SetupPageElementView(this Transform transform)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			HighlightUI val = ((Component)transform).gameObject.AddComponent<HighlightUI>();
			val.color1 = new Color(1f, 1f, 1f, 0.1294118f);
			val.color2 = Color.white;
			PageElementView val2 = ((Component)transform).gameObject.AddComponent<PageElementView>();
			val2.highlightColor1 = new Color(1f, 1f, 1f, 0f);
			val2.highlightColor2 = Color.white;
			val2.color1 = new Color(1f, 1f, 1f, 0f);
			val2.color2 = Color.white;
			val2.blipCurve = AnimationCurve.Linear(0f, 1f, 1f, 1f);
			val2.elements = Il2CppReferenceArray<HighlightUI>.op_Implicit((HighlightUI[])(object)new HighlightUI[1] { val });
			return val2;
		}
	}
	public static class UIMachineUtilities
	{
		public static void CreateLaserCursor(Transform canvas, Transform uiPlane, Vector3 bounds)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			LaserCursorUtilities.CreateLaserCursor(delegate(LaserCursor cursor)
			{
				//IL_0033: 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_0042: 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_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_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Expected O, but got Unknown
				((Component)cursor).transform.parent = canvas.parent;
				((Component)cursor).transform.SetLocalPositionAndRotation(Vector3Extensions.zero, QuaternionExtensions.identity);
				CursorRegion val = new CursorRegion
				{
					bounds = new Bounds(Vector3Extensions.zero, Vector3.Scale(bounds, canvas.lossyScale)),
					center = uiPlane
				};
				cursor.regions = Il2CppReferenceArray<CursorRegion>.op_Implicit((CursorRegion[])(object)new CursorRegion[1] { val });
				FusionSceneManager.HookOnLevelLoad(delegate
				{
					if (!((Object)(object)cursor == (Object)null))
					{
						((Component)cursor).gameObject.SetActive(true);
					}
				});
			});
		}

		public static void CreateUITrigger(GameObject canvas, GameObject trigger)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0051: 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_0062: Expected O, but got Unknown
			trigger.SetActive(false);
			trigger.layer = 29;
			Zone zone = trigger.AddComponent<Zone>();
			ZoneEvents obj = trigger.AddComponent<ZoneEvents>();
			((ZoneItem)obj)._zone = zone;
			obj.onZoneEnter = new ZoneEventCallback();
			obj.onZoneEnterOneShot = new ZoneEventCallback();
			obj.onZoneExit = new ZoneEventCallback();
			TagQuery val = new TagQuery
			{
				BoneTag = MarrowBoneTagReferences.PlayerReference
			};
			((ZoneItem)obj).activatorTags.Tags.Add(val);
			((UltEvent<MarrowEntity>)(object)obj.onZoneEnter).DynamicCalls += Action<MarrowEntity>.op_Implicit((Action<MarrowEntity>)delegate
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				canvas.SetActive(true);
				LocalAudioPlayer.PlayAtPoint(new AudioReference(FusionMonoDiscReferences.UITurnOnReference), canvas.transform.position, LocalAudioPlayer.SFXSettings);
			});
			((UltEvent<MarrowEntity>)(object)obj.onZoneExit).DynamicCalls += Action<MarrowEntity>.op_Implicit((Action<MarrowEntity>)delegate
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				canvas.SetActive(false);
				LocalAudioPlayer.PlayAtPoint(new AudioReference(FusionMonoDiscReferences.UITurnOffReference), canvas.transform.position, LocalAudioPlayer.SFXSettings);
			});
			trigger.SetActive(true);
		}

		public static void OverrideFonts(Transform root)
		{
			foreach (TMP_Text componentsInChild in ((Component)root).GetComponentsInChildren<TMP_Text>(true))
			{
				componentsInChild.font = PersistentAssetCreator.Font;
			}
		}

		public static void AddButtonTriggers(Transform root)
		{
			foreach (Button componentsInChild in ((Component)root).GetComponentsInChildren<Button>(true))
			{
				Collider componentInChildren = ((Component)componentsInChild).GetComponentInChildren<Collider>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					((Component)componentInChildren).gameObject.AddComponent<FusionUITrigger>().button = componentsInChild;
				}
			}
		}

		public static void AddClickEvent(this Button button, Action action)
		{
			((UnityEvent)button.onClick).AddListener(UnityAction.op_Implicit(action));
		}
	}
}
namespace LabFusion.UI
{
	[RegisterTypeInIl2Cpp]
	public sealed class CupBoard : FusionUIMachine
	{
		private const float _maxMusicVolume = 0.3f;

		private CupBoardPanelView _panelView;

		private AudioSource[] _musicLayers;

		private int _layerCount;

		private GameObject _completionistGo;

		public CupBoardPanelView PanelView => _panelView;

		public CupBoard(IntPtr intPtr)
			: base(intPtr)
		{
		}

		protected override void OnAwake()
		{
			base.OnAwake();
			_musicLayers = Il2CppArrayBase<AudioSource>.op_Implicit(((Component)((Component)this).transform.Find("SFX/Music")).GetComponentsInChildren<AudioSource>());
			_layerCount = _musicLayers.Length;
			_completionistGo = ((Component)((Component)this).transform.Find("Art/Offset/Completionist")).gameObject;
			LabFusion.SDK.Achievements.Achievement.OnAchievementCompleted += OnAchievementCompleted;
			LoadProgress();
		}

		private void OnDestroy()
		{
			LabFusion.SDK.Achievements.Achievement.OnAchievementCompleted -= OnAchievementCompleted;
		}

		[HideFromIl2Cpp]
		private void OnAchievementCompleted(LabFusion.SDK.Achievements.Achievement achievement)
		{
			LoadProgress();
		}

		private void LoadProgress()
		{
			float achievementProgress = AchievementManager.GetAchievementProgress();
			LoadEffects(achievementProgress);
			LoadMusic(achievementProgress);
			AchievementManager.CheckCompletionistUnlocks();
		}

		private void LoadEffects(float progress)
		{
			bool active = progress >= 1f;
			_completionistGo.SetActive(active);
		}

		private void LoadMusic(float progress)
		{
			_musicLayers[0].volume = 0.3f;
			int num = _layerCount - 1;
			float num2 = progress * (float)num;
			for (int i = 0; i < num; i++)
			{
				float t = num2 - (float)i;
				_musicLayers[i + 1].volume = ManagedMathf.Lerp(0f, 0.3f, t);
			}
		}

		protected override void AddPanelView(GameObject panel)
		{
			_panelView = panel.AddComponent<CupBoardPanelView>();
		}

		protected override Transform GetGripRoot()
		{
			return ((Component)this).transform.Find("Colliders");
		}
	}
	public static class CupBoardHelper
	{
		public static void CompleteAchievementBoard(GameObject gameObject)
		{
			gameObject.AddComponent<CupBoard>();
		}

		public static void SpawnAchievementBoard(Vector3 position, Quaternion rotation)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Spawnable spawnable = LocalAssetSpawner.CreateSpawnable(FusionSpawnableReferences.AchievementBoardReference);
			LocalAssetSpawner.Register(spawnable);
			LocalAssetSpawner.Spawn(spawnable, position, rotation);
		}
	}
	[RegisterTypeInIl2Cpp]
	public sealed class CupBoardPanelView : FusionPanelView
	{
		private Transform _achievementButtonsRoot;

		private Transform _arrowButtonsRoot;

		private Slider _progressSlider;

		private TMP_Text _progressText;

		private Transform[] _achievementPanels;

		private int _achievementButtonCount;

		private int _currentPageIndex;

		private int _pageCount;

		private Texture _defaultPreview;

		private TMP_Text _pageCountText;

		protected override Vector3 Bounds => new Vector3(2.14f, 1.4f, 0.1f);

		public int PageCount => _pageCount;

		[HideFromIl2Cpp]
		public IReadOnlyList<LabFusion.SDK.Achievements.Achievement> PageItems => AchievementManager.GetSortedAchievements();

		public CupBoardPanelView(IntPtr intPtr)
			: base(intPtr)
		{
		}

		protected override void OnAwake()
		{
			base.OnAwake();
			SetupArrows();
			LabFusion.SDK.Achievements.Achievement.OnAchievementUpdated += OnAchievementUpdated;
			MenuResources.HookResourcesReady(LoadPage);
		}

		private void OnDestroy()
		{
			LabFusion.SDK.Achievements.Achievement.OnAchievementUpdated -= OnAchievementUpdated;
		}

		[HideFromIl2Cpp]
		private void OnAchievementUpdated(LabFusion.SDK.Achievements.Achievement achievement)
		{
			LoadPage();
		}

		protected override void OnSetupReferences()
		{
			_achievementButtonsRoot = _canvas.Find("achievement_Buttons");
			_arrowButtonsRoot = _canvas.Find("arrow_Buttons");
			_progressSlider = ((Component)_canvas.Find("bar_Progress")).GetComponent<Slider>();
			_progressText = ((Component)((Component)_progressSlider).transform.Find("text")).GetComponent<TMP_Text>();
			_pageCountText = ((Component)_arrowButtonsRoot.Find("button_pageCount")).GetComponentInChildren<TMP_Text>();
			_achievementButtonCount = _achievementButtonsRoot.childCount;
			_achievementPanels = (Transform[])(object)new Transform[_achievementButtonCount];
			for (int i = 0; i < _achievementButtonCount; i++)
			{
				_achievementPanels[i] = _achievementButtonsRoot.GetChild(i);
				if (i == 0)
				{
					_defaultPreview = ((Component)_achievementPanels[i]).GetComponentInChildren<RawImage>().texture;
				}
			}
		}

		private void SetupArrows()
		{
			((Component)_arrowButtonsRoot.Find("button_lastPage")).GetComponent<Button>().AddClickEvent(delegate
			{
				LastPage();
			});
			((Component)_arrowButtonsRoot.Find("button_nextPage")).GetComponent<Button>().AddClickEvent(delegate
			{
				NextPage();
			});
		}

		public void NextPage()
		{
			_currentPageIndex++;
			if (_currentPageIndex >= PageCount)
			{
				_currentPageIndex = PageCount - 1;
			}
			LoadPage();
		}

		public void LastPage()
		{
			_currentPageIndex--;
			if (_currentPageIndex < 0)
			{
				_currentPageIndex = 0;
			}
			LoadPage();
		}

		private void LoadPage()
		{
			if (PageItems.Count <= 0)
			{
				_pageCount = 0;
			}
			else
			{
				_pageCount = (int)System.Math.Ceiling((double)PageItems.Count / (double)_achievementButtonCount);
			}
			_currentPageIndex = ManagedMathf.Clamp(_currentPageIndex, 0, PageCount);
			_pageCountText.text = $"Page {_currentPageIndex + 1} out of {System.Math.Max(1, PageCount)}";
			for (int i = 0; i < _achievementButtonCount; i++)
			{
				Transform val = _achievementPanels[i];
				int achievementIndex = GetAchievementIndex(i);
				if (PageItems.Count <= achievementIndex)
				{
					((Component)val).gameObject.SetActive(false);
					continue;
				}
				((Component)val).gameObject.SetActive(true);
				LoadAchievement(val, PageItems[achievementIndex]);
			}
			LoadProgress();
		}

		private void LoadProgress()
		{
			float achievementProgress = AchievementManager.GetAchievementProgress();
			_progressSlider.Set(achievementProgress, false);
			_progressText.text = $"{achievementProgress * 100f}%";
		}

		[HideFromIl2Cpp]
		private void LoadAchievement(Transform transform, LabFusion.SDK.Achievements.Achievement achievement)
		{
			TMP_Text component = ((Component)transform.Find("title")).GetComponent<TMP_Text>();
			TMP_Text component2 = ((Component)transform.Find("description")).GetComponent<TMP_Text>();
			TMP_Text component3 = ((Component)transform.Find("progress")).GetComponent<TMP_Text>();
			RawImage component4 = ((Component)transform.Find("icon")).GetComponent<RawImage>();
			GameObject gameObject = ((Component)transform.Find("completed")).gameObject;
			GameObject gameObject2 = ((Component)transform.Find("incompleted")).gameObject;
			TMP_Text component5 = ((Component)component.transform.Find("button_bitCount").Find("text")).GetComponent<TMP_Text>();
			component.text = achievement.Title;
			component2.text = achievement.Description;
			component5.text = achievement.BitReward.ToString();
			component3.text = achievement.Progress;
			if ((Object)(object)achievement.Logo != (Object)null)
			{
				component4.texture = achievement.Logo;
			}
			else
			{
				component4.texture = _defaultPreview;
			}
			gameObject.SetActive(achievement.IsComplete);
			gameObject2.SetActive(!achievement.IsComplete);
		}

		private int GetAchievementIndex(int index)
		{
			return index + _currentPageIndex * _achievementButtonCount;
		}
	}
	public class FusionPanelView : MonoBehaviour
	{
		protected Transform _canvas;

		protected Transform _uiPlane;

		protected virtual Vector3 Bounds => new Vector3(1f, 1f, 0.1f);

		public FusionPanelView(IntPtr intPtr)
			: base(intPtr)
		{
		}

		private void Awake()
		{
			UIMachineUtilities.OverrideFonts(((Component)this).transform);
			UIMachineUtilities.AddButtonTriggers(((Component)this).transform);
			SetupReferences();
			OnAwake();
			((Component)_canvas).gameObject.SetActive(false);
		}

		private void SetupReferences()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			_canvas = ((Component)this).transform.Find("CANVAS");
			_uiPlane = _canvas.Find("UIPLANE");
			UIMachineUtilities.CreateLaserCursor(_canvas, _uiPlane, Bounds);
			OnSetupReferences();
		}

		protected virtual void OnAwake()
		{
		}

		protected virtual void OnSetupReferences()
		{
		}
	}
	public class FusionUIMachine : MonoBehaviour
	{
		public FusionUIMachine(IntPtr intPtr)
			: base(intPtr)
		{
		}

		private void Awake()
		{
			PersistentAssetCreator.HookOnSoftGrabLoaded(delegate(HandPose p)
			{
				foreach (Collider componentsInChild in ((Component)GetGripRoot()).GetComponentsInChildren<Collider>())
				{
					if (!Object.op_Implicit((Object)(object)Grip.Cache.Get(((Component)componentsInChild).gameObject)))
					{
						GenericGrip obj = ((Component)componentsInChild).gameObject.AddComponent<GenericGrip>();
						((Grip)obj).isThrowable = true;
						((Grip)obj).ignoreGripTargetOnAttach = false;
						((Grip)obj).additionalGripColliders = Il2CppReferenceArray<Collider>.op_Implicit((Collider[])(object)new Collider[0]);
						((Grip)obj).handleAmplifyCurve = AnimationCurve.Linear(0f, 1f, 0f, 1f);
						((Grip)obj).gripOptions = (InteractionOptions)1;
						((Grip)obj).priority = 1f;
						((Grip)obj).handPose = p;
						((Grip)obj).minBreakForce = float.PositiveInfinity;
						((Grip)obj).maxBreakForce = float.PositiveInfinity;
						((Grip)obj).defaultGripDistance = float.PositiveInfinity;
						((Grip)obj).radius = 0.24f;
					}
				}
				foreach (Rigidbody componentsInChild2 in ((Component)((Component)this).transform).GetComponentsInChildren<Rigidbody>())
				{
					((Component)componentsInChild2).gameObject.AddComponent<InteractableHost>();
				}
			});
			Transform val = ((Component)this).transform.Find("PANELVIEW");
			AddPanelView(((Component)val).gameObject);
			UIMachineUtilities.CreateUITrigger(((Component)val.Find("CANVAS")).gameObject, ((Component)((Component)this).transform.Find("uiTrigger")).gameObject);
			AudioSource[] array = Il2CppArrayBase<AudioSource>.op_Implicit(((Component)this).gameObject.GetComponentsInChildren<AudioSource>(true));
			for (int i = 0; i < array.Length; i++)
			{
				array[i].outputAudioMixerGroup = Audio3dManager.diegeticMusic;
			}
			OnAwake();
		}

		protected virtual void OnAwake()
		{
		}

		protected virtual void AddPanelView(GameObject panel)
		{
		}

		protected virtual Transform GetGripRoot()
		{
			return null;
		}
	}
	[RegisterTypeInIl2Cpp]
	public sealed class FusionUITrigger : MonoBehaviour
	{
		public Button button;

		public FusionUITrigger(IntPtr intPtr)
			: base(intPtr)
		{
		}

		private void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			EventTrigger obj = ((Component)this).gameObject.AddComponent<EventTrigger>();
			Entry val = new Entry
			{
				eventID = (EventTriggerType)4
			};
			((UnityEvent<BaseEventData>)(object)val.callback).AddListener(UnityAction<BaseEventData>.op_Implicit((Action<BaseEventData>)delegate
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				LocalAudioPlayer.PlayAtPoint(new AudioReference(FusionMonoDiscReferences.UIConfirmReference), ((Component)this).transform.position, LocalAudioPlayer.SFXSettings);
				ButtonClickedEvent onClick = button.onClick;
				if (onClick != null)
				{
					((UnityEvent)onClick).Invoke();
				}
			}));
			Entry val2 = new Entry
			{
				eventID = (EventTriggerType)0
			};
			((UnityEvent<BaseEventData>)(object)val2.callback).AddListener(UnityAction<BaseEventData>.op_Implicit((Action<BaseEventData>)delegate
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				LocalAudioPlayer.PlayAtPoint(new AudioReference(FusionMonoDiscReferences.UISelectReference), ((Component)this).transform.position, LocalAudioPlayer.SFXSettings);
			}));
			obj.delegates.Add(val);
			obj.delegates.Add(val2);
		}
	}
	[RegisterTypeInIl2Cpp]
	public sealed class InfoBox : FusionUIMachine
	{
		private InfoBoxPanelView _panelView;

		public InfoBoxPanelView PanelView => _panelView;

		public InfoBox(IntPtr intPtr)
			: base(intPtr)
		{
		}

		protected override void AddPanelView(GameObject panel)
		{
			_panelView = panel.AddComponent<InfoBoxPanelView>();
		}

		protected override Transform GetGripRoot()
		{
			return ((Component)this).transform.Find("Colliders");
		}
	}
	public static class InfoBoxHelper
	{
		public static void CompleteInfoBoard(GameObject gameObject)
		{
			gameObject.AddComponent<InfoBox>();
		}

		public static void SpawnInfoBoard(Vector3 position, Quaternion rotation)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Spawnable spawnable = LocalAssetSpawner.CreateSpawnable(FusionSpawnableReferences.InfoBoardReference);
			LocalAssetSpawner.Register(spawnable);
			LocalAssetSpawner.Spawn(spawnable, position, rotation);
		}
	}
	[RegisterTypeInIl2Cpp]
	public sealed class InfoBoxPanelView : FusionPanelView
	{
		private TMP_Text _versionText;

		private TMP_Text _changelogText;

		private TMP_Text _credits01Text;

		private TMP_Text _credits02Text;

		private TMP_Text _credits03Text;

		private Transform _groupPatchNotes;

		private Transform _groupCredits;

		private Transform _groupMystery;

		private Button _patchNotesButton;

		private Button _creditsButton;

		private Button _mysteryButton;

		protected override Vector3 Bounds => new Vector3(0.64f, 0.64f, 0.1f);

		public InfoBoxPanelView(IntPtr intPtr)
			: base(intPtr)
		{
		}

		protected override void OnAwake()
		{
			SetupButtons();
			LoadPage(((Component)_groupPatchNotes).gameObject);
		}

		protected override void OnSetupReferences()
		{
			_versionText = ((Component)_canvas.Find("text_versionNumber")).GetComponent<TMP_Text>();
			_versionText.text = $"v{FusionMod.Version}";
			_groupPatchNotes = _canvas.Find("group_patchNotes");
			_groupCredits = _canvas.Find("group_credits");
			_groupMystery = _canvas.Find("group_mystery");
			_changelogText = ((Component)_groupPatchNotes.Find("button_changelogContents")).GetComponentInChildren<TMP_Text>();
			_changelogText.text = FusionMod.Changelog;
			_credits01Text = ((Component)_groupCredits.Find("text_credits01")).GetComponentInChildren<TMP_Text>();
			_credits02Text = ((Component)_groupCredits.Find("text_credits02")).GetComponentInChildren<TMP_Text>();
			_credits03Text = ((Component)_groupCredits.Find("text_credits03")).GetComponentInChildren<TMP_Text>();
			if (FusionMod.Credits != null)
			{
				_credits01Text.text = FusionMod.Credits[0];
				_credits02Text.text = FusionMod.Credits[1];
				_credits03Text.text = FusionMod.Credits[2];
			}
			_patchNotesButton = ((Component)_canvas.Find("button_patchNotes")).GetComponent<Button>();
			_creditsButton = ((Component)_canvas.Find("button_credits")).GetComponent<Button>();
			_mysteryButton = ((Component)_canvas.Find("button_mystery")).GetComponent<Button>();
		}

		private void SetupButtons()
		{
			_patchNotesButton.AddClickEvent(delegate
			{
				LoadPage(((Component)_groupPatchNotes).gameObject);
			});
			_creditsButton.AddClickEvent(delegate
			{
				LoadPage(((Component)_groupCredits).gameObject);
			});
			_mysteryButton.AddClickEvent(delegate
			{
				if (AchievementManager.TryGetAchievement<HelloThere>(out var achievement))
				{
					achievement.IncrementTask();
				}
				LoadPage(((Component)_groupMystery).gameObject);
			});
		}

		private void LoadPage(GameObject page)
		{
			((Component)_groupPatchNotes).gameObject.SetActive(false);
			((Component)_groupCredits).gameObject.SetActive(false);
			((Component)_groupMystery).gameObject.SetActive(false);
			page.SetActive(true);
		}
	}
	public interface IPopupLayoutElement
	{
		int Priority { get; }

		Transform Transform { get; }

		bool Visible { get; set; }

		void Spawn(Transform parent);

		void Despawn();
	}
}
namespace LabFusion.UI.Popups
{
	public static class AchievementPopup
	{
		public const float DefaultDuration = 5f;

		public static readonly Vector3 LocalPosition = new Vector3(0f, -0.06f, 0.9f);

		private static readonly Queue<LabFusion.SDK.Achievements.Achievement> _queuedAchievements = new Queue<LabFusion.SDK.Achievements.Achievement>();

		private static float _timeOfPopup = 0f;

		public static void Send(LabFusion.SDK.Achievements.Achievement achievement)
		{
			QueueAchievement(achievement);
		}

		private static void QueueAchievement(LabFusion.SDK.Achievements.Achievement achievement)
		{
			_queuedAchievements.Enqueue(achievement);
		}

		private static void DequeueAchievement()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			_timeOfPopup = TimeUtilities.TimeSinceStartup;
			LabFusion.SDK.Achievements.Achievement achievement = _queuedAchievements.Dequeue();
			Transform camera = ((Rig)RigData.Refs.ControllerRig).m_head;
			Spawnable spawnable = LocalAssetSpawner.CreateSpawnable(FusionSpawnableReferences.AchievementPopupReference);
			LocalAssetSpawner.Register(spawnable);
			LocalAssetSpawner.Spawn(spawnable, Vector3.zero, Quaternion.identity, delegate(Poolee poolee)
			{
				//IL_001e: 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)
				Transform transform = ((Component)poolee).transform;
				transform.parent = camera;
				UIMachineUtilities.OverrideFonts(((Component)transform).transform);
				transform.localPosition = LocalPosition;
				transform.localRotation = Quaternion.identity;
				Transform val = transform.Find("Offset/Canvas");
				if ((Object)(object)achievement.Logo != (Object)null)
				{
					((Component)val.Find("icon")).GetComponent<RawImage>().texture = achievement.Logo;
				}
				((Component)val.Find("title")).GetComponent<TMP_Text>().text = achievement.Title;
				((Component)val.Find("description")).GetComponent<TMP_Text>().text = achievement.Description;
				LocalAudioPlayer.Play2dOneShot(new AudioReference(FusionMonoDiscReferences.UITurnOnReference), LocalAudioPlayer.InHeadSettings);
				PooleeHelper.DespawnDelayed(poolee, 5.1f);
			});
		}

		internal static bool IsPlayingPopup()
		{
			return TimeUtilities.TimeSinceStartup - _timeOfPopup <= 5.1f;
		}

		internal static void OnInitializeMelon()
		{
			LabFusion.SDK.Achievements.Achievement.OnAchievementCompleted += Send;
		}

		internal static void OnUpdate()
		{
			if (_queuedAchievements.Count > 0 && FusionSceneManager.HasTargetLoaded() && !FusionSceneManager.IsDelayedLoading() && RigData.HasPlayer && !IsPlayingPopup())
			{
				DequeueAchievement();
			}
		}
	}
	public static class BitPopup
	{
		private static readonly Queue<int> _bitQueue = new Queue<int>();

		public const float DefaultDuration = 1f;

		public static readonly Vector3 LocalPosition = new Vector3(0.319f, -0.198f, 0.783f);

		public static readonly Quaternion LocalRotation = Quaternion.Euler(0f, 17.252f, 0f);

		internal static void OnUpdate()
		{
			if (FusionSceneManager.HasTargetLoaded() && !FusionSceneManager.IsDelayedLoading() && RigData.HasPlayer && _bitQueue.Count > 0)
			{
				DequeueBit();
			}
		}

		public static void Send(int amount)
		{
			if (amount != 0)
			{
				_bitQueue.Enqueue(amount);
			}
		}

		private static void DequeueBit()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			int amount = _bitQueue.Dequeue();
			Transform camera = ((Rig)RigData.Refs.ControllerRig).m_head;
			Spawnable spawnable = LocalAssetSpawner.CreateSpawnable(FusionSpawnableReferences.BitPopupReference);
			LocalAssetSpawner.Register(spawnable);
			LocalAssetSpawner.Spawn(spawnable, Vector3.zero, Quaternion.identity, delegate(Poolee poolee)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00db: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Unknown result type (might be due to invalid IL or mi

Plugins/LabFusionUpdater.dll

Decompiled a month ago
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net.Http;
using System.Net.Security;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using LabFusionUpdater;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LabFusion Updater")]
[assembly: AssemblyProduct("LabFusion Updater")]
[assembly: AssemblyCopyright("Created by Lakatrazz")]
[assembly: AssemblyFileVersion("1.1.0")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: MelonInfo(typeof(FusionUpdaterPlugin), "LabFusion Updater", "1.1.0", "Lakatrazz", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
namespace LabFusionUpdater
{
	public class FusionUpdaterPlugin : MelonPlugin
	{
		public const string Name = "LabFusion Updater";

		public const string Author = "Lakatrazz";

		public const string Version = "1.1.0";

		private MelonPreferences_Category _prefCategory = MelonPreferences.CreateCategory("LabFusionUpdater");

		private MelonPreferences_Entry<bool> _offlineModePref;

		public const string ModName = "LabFusion";

		public const string PluginName = "LabFusionUpdater";

		public const string FileExtension = ".dll";

		public static readonly string ModAssemblyPath = Path.Combine(MelonEnvironment.ModsDirectory, "LabFusion.dll");

		public static readonly string PluginAssemblyPath = Path.Combine(MelonEnvironment.PluginsDirectory, "LabFusionUpdater.dll");

		public static FusionUpdaterPlugin Instance { get; private set; }

		public static Instance Logger { get; private set; }

		public static Assembly UpdaterAssembly { get; private set; }

		public bool IsOffline => _offlineModePref.Value;

		public override void OnPreInitialization()
		{
			Instance = this;
			Logger = ((MelonBase)this).LoggerInstance;
			UpdaterAssembly = ((MelonBase)this).MelonAssembly.Assembly;
			_offlineModePref = _prefCategory.CreateEntry<bool>("OfflineMode", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_prefCategory.SaveToFile(false);
			((MelonBase)this).LoggerInstance.Msg(IsOffline ? Color.Yellow : Color.Green, IsOffline ? "Fusion Auto-Updater is OFFLINE." : "Fusion Auto-Updater is ONLINE.");
			if (IsOffline)
			{
				if (!File.Exists(ModAssemblyPath))
				{
					((MelonBase)this).LoggerInstance.Warning("LabFusion.dll was not found in the Mods folder!");
					((MelonBase)this).LoggerInstance.Warning("Download it from the Github or switch to ONLINE mode.");
					((MelonBase)this).LoggerInstance.Warning("https://github.com/Lakatrazz/BONELAB-Fusion/releases");
				}
			}
			else
			{
				Updater.UpdateMod();
			}
		}
	}
	public static class Updater
	{
		public enum ExitResult
		{
			Success,
			UpToDate,
			Error
		}

		public const string ReleasesApi = "https://api.github.com/repos/Lakatrazz/BONELAB-Fusion/releases";

		public const string ModName = "LabFusion";

		public const string AssemblyExtension = ".dll";

		public const string ModFileName = "LabFusion.dll";

		public const string AcceptHeaderName = "Accept";

		public const string AcceptHeaderValue = "application/vnd.github.v3.raw";

		public const string UserAgentHeaderName = "User-Agent";

		public const string UserAgentHeaderValue = "LabFusionUpdater";

		public static void UpdateMod()
		{
			Version version = new Version(0, 0, 0);
			if (File.Exists(FusionUpdaterPlugin.ModAssemblyPath))
			{
				AssemblyName assemblyName = AssemblyName.GetAssemblyName(FusionUpdaterPlugin.ModAssemblyPath);
				version = new Version(assemblyName.Version.Major, assemblyName.Version.Minor, assemblyName.Version.Build);
				FusionUpdaterPlugin.Logger.Msg($"{"LabFusion"}{".dll"} found in Mods folder. Version: {version}");
			}
			try
			{
				switch (DownloadMod(version, FusionUpdaterPlugin.ModAssemblyPath))
				{
				case ExitResult.Success:
					((MelonBase)FusionUpdaterPlugin.Instance).LoggerInstance.Msg("LabFusion.dll updated successfully!");
					break;
				case ExitResult.UpToDate:
					((MelonBase)FusionUpdaterPlugin.Instance).LoggerInstance.Msg("LabFusion.dll is already up to date.");
					break;
				case ExitResult.Error:
					((MelonBase)FusionUpdaterPlugin.Instance).LoggerInstance.Error("LabFusion.dll failed to update!");
					break;
				}
			}
			catch (Exception ex)
			{
				FusionUpdaterPlugin.Logger.Error("Exception caught while running LabFusion updater!");
				FusionUpdaterPlugin.Logger.Error(ex.ToString());
			}
		}

		private static ExitResult DownloadMod(Version currentVersion, string modAssemblyPath)
		{
			using (new HttpClient())
			{
				using HttpClient httpClient = new HttpClient(new HttpClientHandler
				{
					ClientCertificateOptions = ClientCertificateOption.Manual,
					ServerCertificateCustomValidationCallback = (HttpRequestMessage _, X509Certificate2? _, X509Chain? _, SslPolicyErrors _) => true
				});
				httpClient.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3.raw");
				httpClient.DefaultRequestHeaders.Add("User-Agent", "LabFusionUpdater");
				try
				{
					using StreamReader streamReader = new StreamReader(httpClient.Send(new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/Lakatrazz/BONELAB-Fusion/releases")).Content.ReadAsStream(), Encoding.UTF8);
					JsonNode? jsonNode = JsonSerializer.Deserialize<JsonNode>(streamReader.ReadToEnd());
					Version version = new Version(0, 0, 0);
					JsonNode jsonNode2 = null;
					foreach (JsonNode item in jsonNode.AsArray())
					{
						Version version2 = new Version(((string?)item["tag_name"]).Replace("v", ""));
						if (version2 >= version)
						{
							version = version2;
							jsonNode2 = item;
						}
					}
					Console.WriteLine($"Latest version of {"LabFusion"} is {version}.");
					if (version <= currentVersion)
					{
						return ExitResult.UpToDate;
					}
					Console.WriteLine("Downloading latest version...");
					bool flag = false;
					foreach (JsonNode item2 in jsonNode2["assets"].AsArray())
					{
						if (item2["name"].ToString() == "LabFusion.dll")
						{
							string requestUri = item2["browser_download_url"].ToString();
							HttpResponseMessage httpResponseMessage = httpClient.Send(new HttpRequestMessage(HttpMethod.Get, requestUri));
							using FileStream destination = new FileStream(modAssemblyPath, FileMode.Create, FileAccess.Write);
							httpResponseMessage.Content.ReadAsStream().CopyTo(destination);
							flag = true;
						}
					}
					if (flag)
					{
						return ExitResult.Success;
					}
					return ExitResult.Error;
				}
				catch (Exception ex)
				{
					Console.WriteLine("Exception caught while running LabFusion updater!");
					Console.WriteLine(ex.ToString());
					return ExitResult.Error;
				}
			}
		}
	}
}