Decompiled source of Fusion v1.8.0

Mods/LabFusion.dll

Decompiled 3 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
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.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.Windows.Forms;
using System.Xml.Linq;
using BoneLib;
using BoneLib.BoneMenu;
using FusionHelper.Network;
using HarmonyLib;
using Il2Cpp;
using Il2CppCysharp.Threading.Tasks;
using Il2CppInterop.Runtime;
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.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 Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using Il2CppUltEvents;
using LabFusion;
using LabFusion.BoneMenu;
using LabFusion.Data;
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.Integration;
using LabFusion.Marrow.Zones;
using LabFusion.MonoBehaviours;
using LabFusion.Network;
using LabFusion.Patching;
using LabFusion.Player;
using LabFusion.Preferences;
using LabFusion.Preferences.Client;
using LabFusion.RPC;
using LabFusion.Representation;
using LabFusion.SDK.Achievements;
using LabFusion.SDK.Cosmetics;
using LabFusion.SDK.Gamemodes;
using LabFusion.SDK.Lobbies;
using LabFusion.SDK.Metadata;
using LabFusion.SDK.Modules;
using LabFusion.SDK.Points;
using LabFusion.SDK.Triggers;
using LabFusion.Scene;
using LabFusion.Senders;
using LabFusion.Syncables;
using LabFusion.UI;
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;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: Guid("490e160d-251d-4ab4-a3bb-f473961ff8a1")]
[assembly: AssemblyTitle("LabFusion")]
[assembly: AssemblyFileVersion("1.8.0")]
[assembly: MelonInfo(typeof(FusionMod), "LabFusion", "1.8.0", "Lakatrazz", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonPriority(-10000)]
[assembly: MelonOptionalDependencies(new string[] { "System.Windows.Forms" })]
[assembly: MelonIncompatibleAssemblies(new string[] { "BonelabMultiplayerMockup", "Junction" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.8.0.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 FusionHelper.Network
{
	internal enum MessageTypes
	{
		SteamID = 0,
		OnDisconnected = 1,
		OnMessage = 2,
		GetUsername = 3,
		UnreliableBroadcastToClients = 4,
		ReliableBroadcastToClients = 5,
		UnreliableBroadcastToServer = 6,
		ReliableBroadcastToServer = 7,
		OnConnectionDisconnected = 8,
		OnConnectionMessage = 9,
		JoinServer = 10,
		Disconnect = 11,
		Ping = 12,
		StartServer = 13,
		UnreliableSendFromServer = 14,
		ReliableSendFromServer = 15,
		LobbyIds = 16,
		LobbyMetadata = 17,
		UpdateConnectPresence = 18,
		SetLobbyMetadata = 20,
		SteamFriends = 21
	}
}
namespace LabFusion
{
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct FusionVersion
	{
		public const byte VersionMajor = 1;

		public const byte VersionMinor = 8;

		public const short VersionPatch = 0;

		public const string VersionString = "1.8.0";
	}
	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, 8, 0);

		private static bool _hasAutoUpdater = false;

		private static int _nextSyncableSendRate = 1;

		private static bool _initializedBoneMenu = false;

		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();
			ByteRetriever.PopulateInitial();
			PDController.OnInitializeMelon();
			ModuleHandler.Internal_HookAssemblies();
			GamemodeRegistration.Internal_HookAssemblies();
			PointItemManager.HookEvents();
			VoteKickHelper.Internal_OnInitializeMelon();
		}

		public override void OnInitializeMelon()
		{
			BoneMenuCreator.OnPrepareMainPage();
			FusionFileLoader.OnInitializeMelon();
			FusionBundleLoader.OnBundleLoad();
			LevelDataHandler.OnInitializeMelon();
			FusionMessageHandler.RegisterHandlersFromAssembly(FusionAssembly);
			GrabGroupHandler.RegisterHandlersFromAssembly(FusionAssembly);
			NetworkLayer.RegisterLayersFromAssembly(FusionAssembly);
			GamemodeRegistration.LoadGamemodes(FusionAssembly);
			PointItemManager.LoadItems(FusionAssembly);
			AchievementManager.LoadAchievements(FusionAssembly);
			EntityComponentManager.RegisterComponentsFromAssembly(FusionAssembly);
			LobbyFilterManager.LoadBuiltInFilters();
			NetworkEntityManager.OnInitializeManager();
			NetworkPlayerManager.OnInitializeManager();
			FusionPopupManager.OnInitializeMelon();
			AssetWarehouse.OnReady(Action.op_Implicit((Action)delegate
			{
				CosmeticLoader.OnAssetWarehouseReady();
				ScannableEvents.OnAssetWarehouseReady();
			}));
			FusionPreferences.OnInitializePreferences();
			FusionSceneManager.Internal_OnInitializeMelon();
			OnInitializeNetworking();
		}

		public override void OnLateInitializeMelon()
		{
			InternalLayerHelpers.OnLateInitializeLayer();
			PersistentAssetCreator.OnLateInitializeMelon();
			PlayerAdditionsHelper.OnInitializeMelon();
			_hasAutoUpdater = MelonTypeBase<MelonPlugin>.RegisteredMelons.Any((MelonPlugin p) => ((MelonBase)p).Info.Name.Contains("LabFusion Updater"));
			if (!_hasAutoUpdater && !PlatformHelper.IsAndroid)
			{
				FusionNotifier.Send(new FusionNotification
				{
					isMenuItem = false,
					isPopup = 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
				});
			}
		}

		protected static void OnInitializeNetworking()
		{
			if (NetworkInfo.CurrentNetworkLayer != null)
			{
				FusionLogger.Warn("Cannot initialize new network layer because a previous one is active!");
				return;
			}
			NetworkLayerDeterminer.LoadLayer();
			if (NetworkLayerDeterminer.LoadedLayer == null)
			{
				FusionLogger.Error("The target network layer is null!");
			}
			else
			{
				InternalLayerHelpers.SetLayer(NetworkLayerDeterminer.LoadedLayer);
			}
		}

		public override void OnDeinitializeMelon()
		{
			InternalLayerHelpers.OnCleanupLayer();
			VoteKickHelper.Internal_OnDeinitializeMelon();
			FusionFileLoader.OnDeinitializeMelon();
			ModuleHandler.Internal_UnhookAssemblies();
			GamemodeRegistration.Internal_UnhookAssemblies();
			PointItemManager.UnhookEvents();
			FusionBundleLoader.OnBundleUnloaded();
			PlayerAdditionsHelper.OnDeinitializeMelon();
			SteamAPILoader.OnFreeSteamAPI();
		}

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

		public static void OnMainSceneInitialized()
		{
			if (!_initializedBoneMenu)
			{
				BoneMenuCreator.OnPopulateMainPage();
				_initializedBoneMenu = true;
			}
			_ = ((Scannable)FusionSceneManager.Level).Title;
			NetworkEntityManager.OnCleanupIds();
			RigData.OnCacheRigInfo();
			PersistentAssetCreator.OnMainSceneInitialized();
			ConstrainerUtilities.OnMainSceneInitialized();
			MultiplayerHooking.Internal_OnMainSceneInitialized();
			FusionPlayer.OnMainSceneInitialized();
			if (NetworkInfo.IsServer && Gamemode.ActiveGamemode != null && Gamemode.ActiveGamemode.AutoStopOnSceneLoad)
			{
				Gamemode.ActiveGamemode.StopGamemode();
			}
		}

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

		public override void OnUpdate()
		{
			NetworkInfo.BytesDown = 0;
			NetworkInfo.BytesUp = 0;
			ModIODownloader.UpdateQueue();
			TimeUtilities.OnEarlyUpdate();
			FusionSceneManager.Internal_UpdateScene();
			FusionPopupManager.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.Internal_OnUpdate();
			GamemodeManager.Internal_OnUpdate();
			DelayUtilities.Internal_OnUpdate();
		}

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

		public override void OnLateUpdate()
		{
			float deltaTime = TimeUtilities.DeltaTime;
			NetworkPlayerManager.OnLateUpdate(deltaTime);
			NetworkEntityManager.OnLateUpdate(deltaTime);
			InternalLayerHelpers.OnLateUpdateLayer();
			MultiplayerHooking.Internal_OnLateUpdate();
			GamemodeManager.Internal_OnLateUpdate();
		}

		public override void OnGUI()
		{
			InternalLayerHelpers.OnGUILayer();
		}
	}
}
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.GetCompressedVoiceData());
				}
			}
		}

		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[] GetCompressedVoiceData();

		void UpdateVoice(bool enabled);

		void Enable();

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

		NetworkPlayer Player { get; }

		AudioSource Source { get; }

		bool IsDestroyed { get; }

		float Volume { get; set; }

		float GetVoiceAmplitude();

		void CreateAudioSource();

		void VerifyRep();

		void OnVoiceDataReceived(byte[] data);

		void Cleanup();

		void Update();
	}
	public abstract class VoiceSpeaker : IVoiceSpeaker
	{
		protected PlayerId _id;

		protected NetworkPlayer _player;

		protected bool _hasPlayer;

		protected AudioSource _source;

		protected GameObject _sourceGo;

		protected bool _isDestroyed;

		protected float _volume = 1f;

		public PlayerId ID => _id;

		public NetworkPlayer Player => _player;

		public AudioSource Source => _source;

		public bool IsDestroyed => _isDestroyed;

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

		public bool MicrophoneDisabled
		{
			get
			{
				if (_hasPlayer)
				{
					return _player.MicrophoneDisabled;
				}
				return false;
			}
		}

		public virtual void CreateAudioSource()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			_sourceGo = new GameObject($"{ID.SmallId} Voice Source");
			_source = _sourceGo.AddComponent<AudioSource>();
			Object.DontDestroyOnLoad((Object)(object)_source);
			Object.DontDestroyOnLoad((Object)(object)_sourceGo);
			((Object)_sourceGo).hideFlags = (HideFlags)32;
			_source.rolloffMode = (AudioRolloffMode)1;
			_source.loop = true;
		}

		public virtual void VerifyRep()
		{
			if (!_hasPlayer && ID != null && NetworkPlayerManager.TryGetPlayer((byte)ID, out _player))
			{
				_player.InsertVoiceSource(this, Source);
				_hasPlayer = true;
			}
		}

		public virtual void Update()
		{
		}

		public virtual void Cleanup()
		{
			if ((Object)(object)_source != (Object)null)
			{
				if ((Object)(object)_source.clip != (Object)null)
				{
					Object.Destroy((Object)(object)_source.clip);
				}
				Object.Destroy((Object)(object)_sourceGo);
			}
			_isDestroyed = true;
		}

		public abstract void OnVoiceDataReceived(byte[] data);

		public abstract float GetVoiceAmplitude();
	}
	public class JawFlapper
	{
		private float _voiceLoudness;

		private const float _sinAmplitude = 5f;

		private const float _sinOmega = 10f;

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

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

		public void UpdateJaw(float amplitude)
		{
			float num = amplitude;
			num *= 1000f;
			num = ManagedMathf.Clamp(num, 0f, 2f);
			float value = Math.Abs(5f * ManagedMathf.Sin(10f * TimeUtilities.TimeSinceStartup));
			value = ManagedMathf.Clamp01(value);
			_voiceLoudness = ManagedMathf.LerpUnclamped(_voiceLoudness * value, num, TimeUtilities.DeltaTime * 12f);
		}
	}
	public static class VoiceCompressor
	{
		public static byte[] CompressVoiceData(byte[] data)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress);
			deflateStream.Write(data, 0, data.Length);
			deflateStream.Close();
			return memoryStream.ToArray();
		}

		public static byte[] DecompressVoiceData(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 => NetworkInfo.CurrentNetworkLayer?.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
			{
				bool flag = false;
				if (RigData.HasPlayer)
				{
					flag = ((Health)RigData.Refs.Health).deathIsImminent;
				}
				if (!(ClientSettings.VoiceChat.Muted.Value || flag))
				{
					return IsDeafened;
				}
				return true;
			}
		}

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

		public static bool ServerVoiceEnabled => ServerSettingsManager.ActiveSettings.VoiceChatEnabled.Value;
	}
	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 GetGlobalVolumeMultiplier()
		{
			float num = ClientSettings.VoiceChat.GlobalVolume.Value;
			if (FusionSceneManager.IsLoading())
			{
				num *= 0.25f;
			}
			return num;
		}
	}
}
namespace LabFusion.Voice.Unity
{
	public static class UnityVoice
	{
		public const int SampleRate = 16000;

		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 byte[] _uncompressedData;

		private bool _hasVoiceActivity;

		private AudioClip _voiceClip;

		private int _lastSample;

		private float _amplitude;

		private float _lastTalkTime;

		private bool _loopedData;

		private bool _wasTalking;

		public float GetVoiceAmplitude()
		{
			return _amplitude;
		}

		public byte[] GetCompressedVoiceData()
		{
			return VoiceCompressor.CompressVoiceData(_uncompressedData);
		}

		public bool HasVoiceActivity()
		{
			return _hasVoiceActivity;
		}

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

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

		public unsafe void UpdateVoice(bool enabled)
		{
			if (!UnityVoice.IsSupported())
			{
				ClearData();
				return;
			}
			string validMicrophoneName = GetValidMicrophoneName();
			bool flag = Microphone.IsRecording(validMicrophoneName);
			if (enabled && !flag)
			{
				_voiceClip = Microphone.Start(validMicrophoneName, true, 1, 16000);
			}
			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 = 16000;
			}
			int num2 = num - _lastSample;
			Il2CppStructArray<float> val = new Il2CppStructArray<float>((long)num2);
			if (num2 > 0)
			{
				_voiceClip.GetData(val, _lastSample);
			}
			if (_loopedData)
			{
				_lastSample = 0;
				_loopedData = false;
			}
			else
			{
				_lastSample = num;
			}
			int num3 = 4;
			byte[] array = new byte[num2 * num3];
			bool isTalking = false;
			_amplitude = 0f;
			for (int i = 0; i < num2; i++)
			{
				float num4 = ((Il2CppArrayBase<float>)(object)val)[i] * 10f;
				_amplitude += Mathf.Abs(num4);
				int num5 = i * num3;
				byte* ptr = (byte*)(&num4);
				for (int j = 0; j < num3; j++)
				{
					array[j + num5] = *(ptr++);
				}
				if (!isTalking)
				{
					isTalking = Math.Abs(num4) >= 0.3f;
				}
			}
			if (num2 > 0)
			{
				_amplitude /= num2;
			}
			CheckTalkingTimeout(ref isTalking);
			_wasTalking = isTalking;
			_uncompressedData = array;
			_hasVoiceActivity = isTalking;
			if (!isTalking)
			{
				_amplitude = 0f;
			}
		}

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

		public void Enable()
		{
		}

		public void Disable()
		{
			_uncompressedData = null;
			_hasVoiceActivity = false;
		}
	}
	public class UnityVoiceSpeaker : VoiceSpeaker
	{
		private readonly Queue<float> _readingQueue = new Queue<float>();

		private float _amplitude;

		private bool _clearedAudio;

		private bool _isReadyToRead;

		public UnityVoiceSpeaker(PlayerId id)
		{
			_id = id;
			OnContactUpdated(ContactsList.GetContact(id));
			ContactsList.OnContactUpdated += OnContactUpdated;
			CreateAudioSource();
			base.Source.clip = AudioClip.Create("UnityVoice", 16000, 1, 16000, true, PCMReaderCallback.op_Implicit((Action<Il2CppStructArray<float>>)PcmReaderCallback));
			_source.Play();
			VerifyRep();
		}

		public override float GetVoiceAmplitude()
		{
			return _amplitude;
		}

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

		private void OnContactUpdated(Contact contact)
		{
			base.Volume = contact.volume;
		}

		private void ClearVoiceData()
		{
			_readingQueue.Clear();
		}

		public override void Update()
		{
			if (_readingQueue.Count >= 3200 && !_isReadyToRead)
			{
				_isReadyToRead = true;
			}
			else if (_readingQueue.Count <= 0)
			{
				_isReadyToRead = false;
			}
			if (!_clearedAudio && _amplitude <= 0.1f)
			{
				_clearedAudio = true;
				ClearVoiceData();
			}
			else if (_clearedAudio && _amplitude >= 0.3f)
			{
				_clearedAudio = false;
			}
		}

		public override void OnVoiceDataReceived(byte[] data)
		{
			if (base.MicrophoneDisabled)
			{
				ClearVoiceData();
				return;
			}
			VerifyRep();
			byte[] array = VoiceCompressor.DecompressVoiceData(data);
			float voiceMultiplier = GetVoiceMultiplier();
			for (int i = 0; i < array.Length; i += 4)
			{
				float item = BitConverter.ToSingle(array, i) * voiceMultiplier;
				_readingQueue.Enqueue(item);
			}
		}

		private float GetVoiceMultiplier()
		{
			float num = VoiceVolume.GetGlobalVolumeMultiplier();
			if (_source.spatialBlend <= 0f)
			{
				num *= 0.25f;
			}
			return num;
		}

		private void PcmReaderCallback(Il2CppStructArray<float> data)
		{
			_amplitude = 0f;
			for (int i = 0; i < ((Il2CppArrayBase<float>)(object)data).Length; i++)
			{
				float num = 0f;
				if (_readingQueue.Count > 0 && _isReadyToRead)
				{
					num = _readingQueue.Dequeue();
				}
				((Il2CppArrayBase<float>)(object)data)[i] = num;
				_amplitude += Math.Abs(num);
			}
			_amplitude /= ((Il2CppArrayBase<float>)(object)data).Length;
		}
	}
}
namespace LabFusion.Utilities
{
	public static class AssemblyUtilities
	{
		public static void LoadAllValid<T>(Assembly assembly, Action<Type> runOnValid)
		{
			if (assembly.FullName.Contains("System"))
			{
				return;
			}
			Type[] types = assembly.GetTypes();
			foreach (Type type in types)
			{
				if ((!type.Name.Contains("Mono") || !type.Name.Contains("Security")) && typeof(T).IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface)
				{
					try
					{
						runOnValid(type);
					}
					catch (Exception ex)
					{
						FusionLogger.Error(ex.Message);
					}
				}
			}
		}
	}
	public static class ByteRetriever
	{
		public const int DefaultSize = 16;

		private static FusionArrayPool<byte> _arrayPool;

		public static void PopulateInitial()
		{
			_arrayPool = new FusionArrayPool<byte>();
		}

		public static byte[] Rent(int size = 16)
		{
			return _arrayPool.Rent(size);
		}

		public static void Return(byte[] array)
		{
			_arrayPool.Return(array);
		}
	}
	public static class CommonBarcodes
	{
		public const string FADE_OUT_BARCODE = "c1534c5a-dac0-44a1-b656-6c235646584c";

		public const string CONSTRAINER_BARCODE = "c1534c5a-3813-49d6-a98c-f595436f6e73";

		public const string CONSTRAINER_ASSET_GUID = "bf9c97bf88c22dc4f981578e75d9aa12";

		public const string INVALID_AVATAR_BARCODE = "BONELABFUSION.NONE";

		public const string STRONG_BARCODE = "fa534c5a83ee4ec6bd641fec424c4142.Avatar.Strong";
	}
	public static class ConstrainerUtilities
	{
		public static bool PlayerConstraintsEnabled => ServerSettingsManager.ActiveSettings.PlayerConstraintsEnabled.Value;

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

		public static Constrainer GlobalConstrainer { get; private set; }

		public static void OnMainSceneInitialized()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			//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>(new Barcode("c1534c5a-3813-49d6-a98c-f595436f6e73"));
			if ((Object)(object)crate == (Object)null)
			{
				return;
			}
			if (!((Crate)crate).Pallet.IsInMarrowGame())
			{
				((Crate)crate).MainAsset = new MarrowAsset("bf9c97bf88c22dc4f981578e75d9aa12");
			}
			((CrateT<GameObject>)(object)crate).LoadAsset(Action<GameObject>.op_Implicit((Action<GameObject>)delegate(GameObject go)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)go == (Object)null))
				{
					GameObject obj = Object.Instantiate<GameObject>(go, new Vector3(1000f, 1000f, 1000f), QuaternionExtensions.identity);
					GlobalConstrainer = obj.GetComponent<Constrainer>();
					obj.SetActive(false);
				}
			}));
		}
	}
	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 Delay(Action action, int frames)
		{
			_delays.Add(new FrameDelayInfo
			{
				action = action,
				counter = frames
			});
		}

		internal static void Internal_OnUpdate()
		{
			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 class AchievementPair
	{
		public WeakAssetReference<Texture2D> Preview { get; private set; } = new WeakAssetReference<Texture2D>();


		public static AchievementPair LoadFromBundle(AssetBundle bundle, string name)
		{
			AchievementPair pair = new AchievementPair();
			bundle.LoadPersistentAssetAsync<Texture2D>("preview_" + name, (Action<Texture2D>)delegate(Texture2D v)
			{
				pair.Preview.SetAsset(v);
			});
			return pair;
		}
	}
	public static class FusionAchievementLoader
	{
		private static readonly string[] _achievementNames = new string[20]
		{
			"ExperiencedExecutioner", "MediocreMarksman", "RookieAssassin", "Rampage", "StyleAddict", "StyleBaby", "StyleMan", "Betrayal", "OneMoreTime", "HeadOfHouse",
			"WarmWelcome", "BouncingStrong", "LavaGang", "CleanupCrew", "ClassStruggle", "GuardianAngel", "HighwayMan", "DaycareAttendant", "AroundTheWorld", "HelloThere"
		};

		private static readonly Dictionary<string, AchievementPair> _achievementPairs = new Dictionary<string, AchievementPair>();

		private static AssetBundleCreateRequest _achievementBundleRequest = null;

		public static WeakAssetReference<AssetBundle> AchievementBundle { get; private set; } = new WeakAssetReference<AssetBundle>();


		private static void OnBundleCompleted(AsyncOperation operation)
		{
			AssetBundle assetBundle = _achievementBundleRequest.assetBundle;
			AchievementBundle.SetAsset(assetBundle);
			string[] achievementNames = _achievementNames;
			foreach (string text in achievementNames)
			{
				_achievementPairs.Add(text, AchievementPair.LoadFromBundle(assetBundle, text));
			}
		}

		public static void OnBundleLoad()
		{
			_achievementBundleRequest = FusionBundleLoader.LoadAssetBundleAsync("achievement_bundle.fusion");
			if (_achievementBundleRequest != null)
			{
				((AsyncOperation)_achievementBundleRequest).completed += Action<AsyncOperation>.op_Implicit((Action<AsyncOperation>)OnBundleCompleted);
			}
			else
			{
				FusionLogger.Error("Achievement bundle failed to load!");
			}
		}

		public static void OnBundleUnloaded()
		{
			if (AchievementBundle.HasAsset)
			{
				AchievementBundle.Asset.Unload(true);
				AchievementBundle.UnloadAsset();
			}
		}

		public static AchievementPair GetPair(string name)
		{
			return _achievementPairs[name];
		}
	}
	public static class FusionAudio
	{
		public static AudioSource Play2D(AudioClip clip, float volume = 1f)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			AudioSource obj = new GameObject("Fusion 2D Audio Source").AddComponent<AudioSource>();
			obj.volume = volume;
			obj.clip = clip;
			obj.spatialBlend = 0f;
			obj.outputAudioMixerGroup = Audio3dManager.inHead;
			obj.Play();
			return obj;
		}

		public static AudioSource Play3D(Vector3 position, AudioClip clip, float volume = 1f, bool loop = false)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Fusion 3D Audio Source");
			AudioSource val2 = val.AddComponent<AudioSource>();
			val.transform.position = position;
			val2.volume = volume;
			val2.clip = clip;
			val2.spatialBlend = 1f;
			val2.loop = loop;
			val2.outputAudioMixerGroup = Audio3dManager.hardInteraction;
			val2.Play();
			return val2;
		}
	}
	public static class FusionAvatar
	{
		public const string POLY_BLANK_BARCODE = "c3534c5a-94b2-40a4-912a-24a8506f6c79";

		public const string POLY_BLANK_NAME = "char_marrow1_polyBlank";

		public static bool IsMatchingAvatar(string barcode, string target)
		{
			if (!(barcode == target))
			{
				return barcode == "c3534c5a-94b2-40a4-912a-24a8506f6c79";
			}
			return true;
		}
	}
	public static class FusionBundleLoader
	{
		public static T LoadPersistentAsset<T>(this AssetBundle bundle, string name) where T : Object
		{
			Object val = bundle.LoadAsset(name);
			if (val != (Object)null)
			{
				val.hideFlags = (HideFlags)32;
				return ((Il2CppObjectBase)val).TryCast<T>();
			}
			return default(T);
		}

		public static void LoadPersistentAssetAsync<T>(this AssetBundle bundle, string name, Action<T> onLoaded) where T : Object
		{
			AssetBundleRequest request = bundle.LoadAssetAsync<T>(name);
			((AsyncOperation)request).completed += Action<AsyncOperation>.op_Implicit((Action<AsyncOperation>)delegate
			{
				if (!(request.asset == (Object)null))
				{
					T val = ((Il2CppObjectBase)request.asset).TryCast<T>();
					((Object)val).hideFlags = (HideFlags)32;
					onLoaded(val);
				}
			});
		}

		public static AssetBundle LoadAssetBundle(string name)
		{
			if (PlatformHelper.IsAndroid)
			{
				return EmbeddedAssetBundle.LoadFromAssembly(FusionMod.FusionAssembly, "LabFusion.dependencies.resources.bundles.Android." + name);
			}
			return EmbeddedAssetBundle.LoadFromAssembly(FusionMod.FusionAssembly, "LabFusion.dependencies.resources.bundles.StandaloneWindows64." + name);
		}

		public static AssetBundleCreateRequest LoadAssetBundleAsync(string name)
		{
			if (PlatformHelper.IsAndroid)
			{
				return EmbeddedAssetBundle.LoadFromAssemblyAsync(FusionMod.FusionAssembly, "LabFusion.dependencies.resources.bundles.Android." + name);
			}
			return EmbeddedAssetBundle.LoadFromAssemblyAsync(FusionMod.FusionAssembly, "LabFusion.dependencies.resources.bundles.StandaloneWindows64." + name);
		}

		public static void OnBundleLoad()
		{
			FusionContentLoader.OnBundleLoad();
			FusionPointItemLoader.OnBundleLoad();
			FusionAchievementLoader.OnBundleLoad();
		}

		public static void OnBundleUnloaded()
		{
			FusionContentLoader.OnBundleUnloaded();
			FusionPointItemLoader.OnBundleUnloaded();
			FusionAchievementLoader.OnBundleUnloaded();
		}
	}
	public class FusionComponentCache<TSource, TComponent> where TSource : Object where TComponent : class
	{
		private readonly FusionDictionary<TSource, TComponent> _Cache = new FusionDictionary<TSource, TComponent>((IEqualityComparer<TSource>)new UnityComparer());

		private readonly HashSet<TSource> _HashTable = new HashSet<TSource>((IEqualityComparer<TSource>?)new UnityComparer());

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

		public TComponent Get(TSource source)
		{
			if (_HashTable.ContainsIL2CPP(source))
			{
				return _Cache[source];
			}
			return null;
		}

		public bool TryGet(TSource source, out TComponent value)
		{
			if (!_HashTable.ContainsIL2CPP(source))
			{
				value = null;
				return false;
			}
			value = _Cache[source];
			return true;
		}

		public bool ContainsSource(TSource source)
		{
			return _HashTable.ContainsIL2CPP(source);
		}

		public void Add(TSource source, TComponent component)
		{
			if (_Cache.ContainsKey(source))
			{
				_Cache[source] = component;
				return;
			}
			_HashTable.Add(source);
			_Cache.Add(source, component);
		}

		public void Remove(TSource source)
		{
			_HashTable.RemoveIL2CPP(source);
			_Cache.Remove(source);
		}
	}
	public static class FusionContentLoader
	{
		private static AssetBundleCreateRequest _contentBundleRequest = null;

		public static WeakAssetReference<AssetBundle> ContentBundle { get; private set; } = new WeakAssetReference<AssetBundle>();


		public static WeakAssetReference<GameObject> EntangledLinePrefab { get; private set; } = new WeakAssetReference<GameObject>();


		public static WeakAssetReference<Texture2D> SabrelakeLogo { get; private set; } = new WeakAssetReference<Texture2D>();


		public static WeakAssetReference<Texture2D> LavaGangLogo { get; private set; } = new WeakAssetReference<Texture2D>();


		public static WeakAssetReference<AudioClip> BitGet { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> UISelect { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> UIDeny { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> UIConfirm { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> UITurnOff { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> UITurnOn { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> PurchaseFailure { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> PurchaseSuccess { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> EquipItem { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> UnequipItem { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<Texture2D> NotificationInformation { get; private set; } = new WeakAssetReference<Texture2D>();


		public static WeakAssetReference<Texture2D> NotificationWarning { get; private set; } = new WeakAssetReference<Texture2D>();


		public static WeakAssetReference<Texture2D> NotificationError { get; private set; } = new WeakAssetReference<Texture2D>();


		public static WeakAssetReference<Texture2D> NotificationSuccess { get; private set; } = new WeakAssetReference<Texture2D>();


		public static WeakAssetReference<GameObject> LaserCursor { get; private set; } = new WeakAssetReference<GameObject>();


		public static WeakAssetReference<AudioClip> LaserPulseSound { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> LaserRaySpawn { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> LaserRayDespawn { get; private set; } = new WeakAssetReference<AudioClip>();


		public static WeakAssetReference<AudioClip> LaserPrismaticSFX { get; private set; } = new WeakAssetReference<AudioClip>();


		private static void OnBundleCompleted(AsyncOperation operation)
		{
			AssetBundle assetBundle = _contentBundleRequest.assetBundle;
			ContentBundle.SetAsset(assetBundle);
			assetBundle.LoadPersistentAssetAsync<GameObject>("renderer_EntangledLine", (Action<GameObject>)delegate(GameObject v)
			{
				EntangledLinePrefab.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<Texture2D>("tex_sabreLakeLogo", (Action<Texture2D>)delegate(Texture2D v)
			{
				SabrelakeLogo.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<Texture2D>("tex_lavaGangLogo", (Action<Texture2D>)delegate(Texture2D v)
			{
				LavaGangLogo.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("stinger_BitGet", (Action<AudioClip>)delegate(AudioClip v)
			{
				BitGet.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("UI_Beep_Bend_Short_stereo", (Action<AudioClip>)delegate(AudioClip v)
			{
				UISelect.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("UI_Error_Double_Note_Down_Notch_stereo", (Action<AudioClip>)delegate(AudioClip v)
			{
				UIDeny.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("UI_SCI-FI_Confirm_Dry_stereo", (Action<AudioClip>)delegate(AudioClip v)
			{
				UIConfirm.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("UI_TurnOff", (Action<AudioClip>)delegate(AudioClip v)
			{
				UITurnOff.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("UI_TurnOn", (Action<AudioClip>)delegate(AudioClip v)
			{
				UITurnOn.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("stinger_FailPurchase", (Action<AudioClip>)delegate(AudioClip v)
			{
				PurchaseFailure.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("stinger_SuccessPurchase", (Action<AudioClip>)delegate(AudioClip v)
			{
				PurchaseSuccess.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("ui_EquipItem", (Action<AudioClip>)delegate(AudioClip v)
			{
				EquipItem.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("ui_UnequipItem", (Action<AudioClip>)delegate(AudioClip v)
			{
				UnequipItem.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<Texture2D>("notification_Information", (Action<Texture2D>)delegate(Texture2D v)
			{
				NotificationInformation.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<Texture2D>("notification_Warning", (Action<Texture2D>)delegate(Texture2D v)
			{
				NotificationWarning.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<Texture2D>("notification_Error", (Action<Texture2D>)delegate(Texture2D v)
			{
				NotificationError.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<Texture2D>("notification_Success", (Action<Texture2D>)delegate(Texture2D v)
			{
				NotificationSuccess.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<GameObject>("laser_Cursor", (Action<GameObject>)delegate(GameObject v)
			{
				LaserCursor.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("laser_PulseSound", (Action<AudioClip>)delegate(AudioClip v)
			{
				LaserPulseSound.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("laser_RaySpawn", (Action<AudioClip>)delegate(AudioClip v)
			{
				LaserRaySpawn.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("laser_RayDespawn", (Action<AudioClip>)delegate(AudioClip v)
			{
				LaserRayDespawn.SetAsset(v);
			});
			assetBundle.LoadPersistentAssetAsync<AudioClip>("laser_PrismaticSFX", (Action<AudioClip>)delegate(AudioClip v)
			{
				LaserPrismaticSFX.SetAsset(v);
			});
		}

		public static void OnBundleLoad()
		{
			_contentBundleRequest = FusionBundleLoader.LoadAssetBundleAsync("content_bundle.fusion");
			if (_contentBundleRequest != null)
			{
				((AsyncOperation)_contentBundleRequest).completed += Action<AsyncOperation>.op_Implicit((Action<AsyncOperation>)OnBundleCompleted);
			}
			else
			{
				FusionLogger.Error("Content Bundle failed to load!");
			}
		}

		public static void OnBundleUnloaded()
		{
			if (ContentBundle.HasAsset)
			{
				ContentBundle.Asset.Unload(true);
				ContentBundle.UnloadAsset();
			}
		}
	}
	public static class FusionDevTools
	{
		public static bool DespawnConstrainer(PlayerId id)
		{
			FusionPermissions.FetchPermissionLevel(id, out var level, out var _);
			if (!FusionPermissions.HasSufficientPermissions(level, ServerSettingsManager.ActiveSettings.ConstrainerAllowed.Value))
			{
				return true;
			}
			return false;
		}

		public static bool DespawnDevTool(PlayerId id)
		{
			if (Gamemode.ActiveGamemode != null && Gamemode.ActiveGamemode.DisableDevTools)
			{
				return true;
			}
			FusionPermissions.FetchPermissionLevel(id, out var level, out var _);
			if (!FusionPermissions.HasSufficientPermissions(level, ServerSettingsManager.ActiveSettings.DevToolsAllowed.Value))
			{
				return true;
			}
			return false;
		}

		public static bool PreventSpawnGun(PlayerId id)
		{
			if (Gamemode.ActiveGamemode != null && Gamemode.ActiveGamemode.DisableSpawnGun)
			{
				return true;
			}
			FusionPermissions.FetchPermissionLevel(id, out var level, out var _);
			if (!FusionPermissions.HasSufficientPermissions(level, ServerSettingsManager.ActiveSettings.DevToolsAllowed.Value))
			{
				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>();

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

		public static float? VitalityOverride { get; internal set; } = null;


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


		internal static void OnMainSceneInitialized()
		{
			LastAttacker = null;
		}

		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 (RigData.Refs.RigManager.physicsRig.feet.transform.position.IsNanOrInf())
			{
				if (NetworkInfo.HasServer && !NetworkInfo.IsServer)
				{
					NetworkHelper.Disconnect("Game Crash");
				}
				SceneStreamer.Reload();
				FusionNotifier.Send(new FusionNotification
				{
					isPopup = true,
					showTitleOnPopup = true,
					title = "Whoops! Sorry about that!",
					type = NotificationType.WARNING,
					message = "The scene was reloaded due to a physics crash.",
					popupLength = 6f
				});
			}
		}

		internal static void Internal_OnAvatarChanged(RigManager rigManager, Avatar avatar, string barcode)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			RigData.RigAvatarStats = new SerializedAvatarStats(avatar);
			RigData.RigAvatarId = barcode;
			PlayerSender.SendPlayerAvatar(RigData.RigAvatarStats, barcode);
			if (VitalityOverride.HasValue)
			{
				Internal_ChangePlayerHealth();
			}
			AvatarCrate crate = ((CrateReferenceT<AvatarCrate>)(object)rigManager.AvatarCrate).Crate;
			PermissionLevel level;
			if (AvatarOverride != null && !FusionAvatar.IsMatchingAvatar(barcode, AvatarOverride))
			{
				Internal_ChangeAvatar();
			}
			else if ((Object)(object)crate != (Object)null && !((Crate)crate).Pallet.IsInMarrowGame() && PlayerIdManager.LocalId != null && PlayerIdManager.LocalId.TryGetPermissionLevel(out level))
			{
				PermissionLevel value = ServerSettingsManager.ActiveSettings.CustomAvatarsAllowed.Value;
				if (!FusionPermissions.HasSufficientPermissions(level, value))
				{
					rigManager.SwapAvatarCrate(new Barcode("c3534c5a-94b2-40a4-912a-24a8506f6c79"), true, (Action<bool>)null);
				}
			}
			PlayerAdditionsHelper.OnAvatarChanged(rigManager);
		}

		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 IsSelf(this RigManager rigManager)
		{
			if (!RigData.HasPlayer)
			{
				return true;
			}
			return (Object)(object)rigManager == (Object)(object)RigData.Refs.RigManager;
		}

		public static void SetAmmo(int count)
		{
			AmmoInventory instance = AmmoInventory.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.ClearAmmo();
				instance.AddCartridge(instance.lightAmmoGroup, count);
				instance.AddCartridge(instance.heavyAmmoGroup, count);
				instance.AddCartridge(instance.mediumAmmoGroup, count);
			}
		}

		public static bool CanUnragdoll()
		{
			if (Gamemode.ActiveGamemode != null && Gamemode.ActiveGamemode.DisableManualUnragdoll)
			{
				return false;
			}
			return true;
		}

		public static void SetMortality(bool isMortal)
		{
			RigManager rigManager = RigData.Refs.RigManager;
			if (!((Object)(object)rigManager).IsNOC())
			{
				Player_Health val = ((Il2CppObjectBase)rigManager.health).TryCast<Player_Health>();
				if (isMortal)
				{
					((Health)val).healthMode = (HealthMode)1;
				}
				else
				{
					((Health)val).healthMode = (HealthMode)0;
				}
			}
		}

		public static void ResetMortality()
		{
			if (NetworkInfo.HasServer)
			{
				SetMortality(CommonPreferences.IsMortal);
			}
		}

		public static void Teleport(Vector3 position, Vector3 fwdSnap, bool zeroVelocity = true)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (RigData.HasPlayer)
			{
				RigManager rigManager = RigData.Refs.RigManager;
				rigManager.Teleport(position, fwdSnap, zeroVelocity);
				rigManager.physicsRig.ResetHands((Handedness)3);
			}
		}

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

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

		public static void SetAvatarOverride(string barcode)
		{
			AvatarOverride = barcode;
			Internal_ChangeAvatar();
		}

		public static void ClearAvatarOverride()
		{
			AvatarOverride = null;
		}

		public static void SetPlayerVitality(float vitality)
		{
			VitalityOverride = vitality;
			Internal_ChangePlayerHealth();
		}

		public static void ClearPlayerVitality()
		{
			VitalityOverride = null;
			Internal_ChangePlayerHealth();
		}

		private static void Internal_ChangeAvatar()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			if (!RigData.HasPlayer || !AssetWarehouse.ready || AvatarOverride == null)
			{
				return;
			}
			if ((Object)(object)CrateFilterer.GetCrate<AvatarCrate>(new Barcode(AvatarOverride)) == (Object)null)
			{
				return;
			}
			RigManager rm = RigData.Refs.RigManager;
			rm.SwapAvatarCrate(new Barcode(AvatarOverride), true, Action<bool>.op_Implicit((Action<bool>)delegate(bool success)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Expected O, but got Unknown
				if (!success)
				{
					rm.SwapAvatarCrate(new Barcode("c3534c5a-94b2-40a4-912a-24a8506f6c79"), true, (Action<bool>)null);
				}
			}));
		}

		private static void Internal_ChangePlayerHealth()
		{
			if (RigData.HasPlayer)
			{
				RigManager rigManager = RigData.Refs.RigManager;
				Avatar avatar = rigManager._avatar;
				if (VitalityOverride.HasValue)
				{
					avatar._vitality = VitalityOverride.Value;
					rigManager.health.SetAvatar(avatar);
				}
				else
				{
					avatar.RefreshBodyMeasurements();
					rigManager.health.SetAvatar(avatar);
				}
			}
		}

		public static bool TryGetSpawnPoint(out Transform point)
		{
			point = null;
			SpawnPoints.RemoveAll((Transform t) => (Object)(object)t == (Object)null);
			if (SpawnPoints.Count > 0)
			{
				point = Extensions.GetRandom<Transform>(SpawnPoints);
				return true;
			}
			return false;
		}
	}
	public class ItemPair
	{
		public WeakAssetReference<GameObject> GameObject { get; private set; } = new WeakAssetReference<GameObject>();


		public WeakAssetReference<Texture2D> Preview { get; private set; } = new WeakAssetReference<Texture2D>();


		public static ItemPair LoadFromBundle(AssetBundle bundle, string name)
		{
			ItemPair itemPair = new ItemPair();
			bundle.LoadPersistentAssetAsync<GameObject>("item_" + name, (Action<GameObject>)delegate(GameObject v)
			{
				itemPair.GameObject.SetAsset(v);
			});
			bundle.LoadPersistentAssetAsync<Texture2D>("preview_" + name, (Action<Texture2D>)delegate(Texture2D v)
			{
				itemPair.Preview.SetAsset(v);
			});
			return itemPair;
		}
	}
	public static class FusionPointItemLoader
	{
		private static readonly ItemPair _nullItemPair = new ItemPair();

		private static readonly string[] _itemNames = new string[1] { "BitMiner" };

		private static readonly Dictionary<string, ItemPair> _itemPairs = new Dictionary<string, ItemPair>();

		private static AssetBundleCreateRequest _itemBundleRequest = null;

		public static WeakAssetReference<AssetBundle> ItemBundle { get; private set; } = new WeakAssetReference<AssetBundle>();


		private static void OnBundleCompleted(AsyncOperation operation)
		{
			AssetBundle assetBundle = _itemBundleRequest.assetBundle;
			ItemBundle.SetAsset(assetBundle);
			string[] itemNames = _itemNames;
			foreach (string text in itemNames)
			{
				_itemPairs.Add(text, ItemPair.LoadFromBundle(assetBundle, text));
			}
		}

		public static void OnBundleLoad()
		{
			_itemBundleRequest = FusionBundleLoader.LoadAssetBundleAsync("item_bundle.fusion");
			if (_itemBundleRequest != null)
			{
				((AsyncOperation)_itemBundleRequest).completed += Action<AsyncOperation>.op_Implicit((Action<AsyncOperation>)OnBundleCompleted);
			}
			else
			{
				FusionLogger.Error("Item bundle failed to load!");
			}
		}

		public static void OnBundleUnloaded()
		{
			if (ItemBundle.HasAsset)
			{
				ItemBundle.Asset.Unload(true);
				ItemBundle.UnloadAsset();
			}
		}

		public static ItemPair GetPair(string name)
		{
			if (_itemPairs.TryGetValue(name, out var value))
			{
				return value;
			}
			return _nullItemPair;
		}
	}
	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 delegate void LobbyMenuAction(Page page, INetworkLobby lobby);
	public static class MultiplayerHooking
	{
		public static event UserAccessEvent OnShouldAllowConnection;

		public static event ServerEvent OnStartServer;

		public static event ServerEvent OnJoinServer;

		public static event ServerEvent OnDisconnect;

		public static event PlayerUpdate OnPlayerJoin;

		public static event PlayerUpdate OnPlayerLeave;

		public static event PlayerAction OnPlayerAction;

		public static event PlayerUpdate OnPlayerCatchup;

		public static event LobbyMenuAction OnLobbyCategoryCreated;

		public static event ServerEvent OnServerSettingsChanged;

		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;

		internal static bool Internal_OnShouldAllowConnection(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 Internal_OnStartServer()
		{
			MultiplayerHooking.OnStartServer.InvokeSafe("executing OnStartServer hook");
		}

		internal static void Internal_OnJoinServer()
		{
			MultiplayerHooking.OnJoinServer.InvokeSafe("executing OnJoinServer hook");
		}

		internal static void Internal_OnDisconnect()
		{
			MultiplayerHooking.OnDisconnect.InvokeSafe("executing OnDisconnect hook");
		}

		internal static void Internal_OnPlayerJoin(PlayerId id)
		{
			MultiplayerHooking.OnPlayerJoin.InvokeSafe(id, "executing OnPlayerJoin hook");
		}

		internal static void Internal_OnPlayerLeave(PlayerId id)
		{
			MultiplayerHooking.OnPlayerLeave.InvokeSafe(id, "executing OnPlayerLeave hook");
		}

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

		internal static void Internal_OnPlayerCatchup(PlayerId playerId)
		{
			MultiplayerHooking.OnPlayerCatchup.InvokeSafe(playerId, "executing OnPlayerCatchup hook");
		}

		internal static void Internal_OnLobbyCategoryCreated(Page page, INetworkLobby lobby)
		{
			MultiplayerHooking.OnLobbyCategoryCreated.InvokeSafe<LobbyMenuAction, Page, INetworkLobby>(page, lobby, "executing OnLobbyCategoryCreated");
		}

		internal static void Internal_OnServerSettingsChanged()
		{
			MultiplayerHooking.OnServerSettingsChanged.InvokeSafe("executing server settings changed hook");
		}

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

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

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

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

		internal static void Internal_OnLoadingBegin()
		{
			MultiplayerHooking.OnLoadingBegin.InvokeSafe("executing OnLoadingBegin hook");
		}
	}
	public static class FusionAchievementPopup
	{
		public const float DefaultDuration = 5f;

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

		private static 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			_timeOfPopup = TimeUtilities.TimeSinceStartup;
			LabFusion.SDK.Achievements.Achievement achievement = _queuedAchievements.Dequeue();
			Transform camera = ((Rig)RigData.Refs.ControllerRig).m_head;
			Spawnable val = new Spawnable
			{
				crateRef = FusionSpawnableReferences.AchievementPopupReference,
				policyData = null
			};
			AssetSpawner.Register(val);
			SafeAssetSpawner.Spawn(val, 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 val2 = transform.Find("Offset/Canvas");
				if ((Object)(object)achievement.PreviewImage != (Object)null)
				{
					((Component)val2.Find("icon")).GetComponent<RawImage>().texture = (Texture)(object)achievement.PreviewImage;
				}
				((Component)val2.Find("title")).GetComponent<TMP_Text>().text = achievement.Title;
				((Component)val2.Find("description")).GetComponent<TMP_Text>().text = achievement.Description;
				FusionAudio.Play2D(FusionContentLoader.UITurnOn.Asset);
				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 FusionBitPopup
	{
		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)
		{
			_bitQueue.Enqueue(amount);
		}

		private static void DequeueBit()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0048: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			int amount = _bitQueue.Dequeue();
			Transform camera = ((Rig)RigData.Refs.ControllerRig).m_head;
			Spawnable val = new Spawnable
			{
				crateRef = FusionSpawnableReferences.BitPopupReference,
				policyData = null
			};
			AssetSpawner.Register(val);
			SafeAssetSpawner.Spawn(val, 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_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
				Transform transform = ((Component)poolee).transform;
				transform.parent = camera;
				UIMachineUtilities.OverrideFonts(transform);
				transform.SetLocalPositionAndRotation(LocalPosition, LocalRotation);
				Transform val2 = transform.Find("Offset/Canvas");
				string text = ((amount < 0) ? $"{amount}" : $"+{amount}");
				((Component)val2.Find("text_shadow")).GetComponent<TMP_Text>().text = text;
				TMP_Text component = ((Component)val2.Find("amount")).GetComponent<TMP_Text>();
				component.text = text;
				if (amount < 0)
				{
					((Graphic)component).color = Color.red;
					((Graphic)((Component)val2.Find("bit")).GetComponent<RawImage>()).color = Color.red;
				}
				FusionAudio.Play2D(FusionContentLoader.BitGet.Asset);
				PooleeHelper.DespawnDelayed(poolee, 1.1f);
			});
		}
	}
	public enum NotificationType
	{
		INFORMATION,
		WARNING,
		ERROR,
		SUCCESS
	}
	public struct NotificationText
	{
		public string text;

		public Color color;

		public bool richText;

		public NotificationText(string text)
			: this(text, Color.white)
		{
		}//IL_0002: Unknown result type (might be due to invalid IL or missing references)


		public NotificationText(string text, Color color, bool richText = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!richText)
			{
				text = text.RemoveRichText();
			}
			this.text = text;
			this.color = color;
			this.richText = richText;
		}

		public static implicit operator NotificationText(string text)
		{
			return new NotificationText(text);
		}
	}
	public class FusionNotification
	{
		public NotificationText title;

		public NotificationText message;

		public bool showTitleOnPopup;

		public bool isPopup = true;

		public float popupLength = 2f;

		public NotificationType type;

		public bool isMenuItem = true;

		public Action<Page> onCreateCategory;
	}
	public static class FusionNotifier
	{
		public const float DefaultDuration = 2f;

		public const float DefaultScaleTime = 0.4f;

		private static readonly Queue<FusionNotification> _queuedNotifications = new Queue<FusionNotification>();

		private static ulong _notificationNumber = 0uL;

		private static bool _hasEnabledTutorialRig = false;

		public static void Send(FusionNotification notification)
		{
			QueueNotification(notification);
		}

		private static void QueueNotification(FusionNotification notification)
		{
			_queuedNotifications.Enqueue(notification);
		}

		private static void DequeueNotification()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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)
			FusionNotification fusionNotification = _queuedNotifications.Dequeue();
			if (fusionNotification.isMenuItem)
			{
				string text = $"Internal_Notification_Generated_{_notificationNumber}";
				Page val = BoneMenuCreator.NotificationCategory.CreatePage(text, fusionNotification.title.color, 0, false);
				PageLinkElement pageLink = BoneMenuCreator.NotificationCategory.CreatePageLink(val);
				val.Name = fusionNotification.title.text;
				_notificationNumber++;
				if (!string.IsNullOrWhiteSpace(fusionNotification.message.text))
				{
					val.CreateFunction(fusionNotification.message.text, fusionNotification.message.color, (Action)null);
				}
				val.CreateFunction("Mark as Read", Color.red, (Action)delegate
				{
					BoneMenuCreator.RemoveNotification((Element)(object)pageLink);
				});
				fusionNotification.onCreateCategory.InvokeSafe<Action<Page>, Page>(val, "executing Notification.OnCreateCategory");
			}
			RigManager rigManager = RigData.Refs.RigManager;
			if (fusionNotification.isPopup && !((Object)(object)rigManager).IsNOC())
			{
				HeadTitles headTitles = TutorialRig.Instance.headTitles;
				EnableTutorialRig();
				string text2 = "New Notification";
				if (fusionNotification.showTitleOnPopup)
				{
					text2 = fusionNotification.title.text;
				}
				string text3 = fusionNotification.message.text;
				Sprite popupSprite = GetPopupSprite(fusionNotification);
				float popupLength = fusionNotification.popupLength;
				float timeToScale = Mathf.Lerp(0.05f, 0.4f, Mathf.Clamp01(popupLength - 1f));
				headTitles.timeToScale = timeToScale;
				headTitles.CUSTOMDISPLAY(text2, text3, popupSprite, popupLength, (AudioClip)null, false, (Sprite)null, (Sprite)null, (Sprite)null, (Sprite)null);
				headTitles.sr_element.sprite = popupSprite;
			}
		}

		private static Sprite GetPopupSprite(FusionNotification notification)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = (Texture2D)(notification.type switch
			{
				NotificationType.WARNING => FusionContentLoader.NotificationWarning.Asset, 
				NotificationType.ERROR => FusionContentLoader.NotificationError.Asset, 
				NotificationType.SUCCESS => FusionContentLoader.NotificationSuccess.Asset, 
				_ => FusionContentLoader.NotificationInformation.Asset, 
			});
			if ((Object)(object)val != (Object)null)
			{
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			}
			return null;
		}

		internal static void EnableTutorialRig()
		{
			if (!((Object)(object)RigData.Refs.RigManager).IsNOC())
			{
				TutorialRig instance = TutorialRig.Instance;
				HeadTitles headTitles = instance.headTitles;
				((Component)instance).gameObject.SetActive(true);
				((Component)headTitles).gameObject.SetActive(true);
			}
		}

		internal static bool IsPlayingNotification()
		{
			if (!((Object)(object)RigData.Refs.RigManager).IsNOC())
			{
				return ((Component)TutorialRig.Instance.headTitles.headFollower).gameObject.activeInHierarchy;
			}
			return false;
		}

		internal static void OnUpdate()
		{
			if (_queuedNotifications.Count > 0 && !FusionSceneManager.IsLoading() && RigData.HasPlayer)
			{
				if (!_hasEnabledTutorialRig)
				{
					EnableTutorialRig();
					_hasEnabledTutorialRig = true;
				}
				else if (_queuedNotifications.Count > 0 && !IsPlayingNotification())
				{
					DequeueNotification();
				}
			}
			else
			{
				_hasEnabledTutorialRig = false;
			}
		}
	}
	public static class FusionPopupManager
	{
		internal static void OnInitializeMelon()
		{
			FusionAchievementPopup.OnInitializeMelon();
		}

		internal static void OnUpdate()
		{
			FusionNotifier.OnUpdate();
			FusionAchievementPopup.OnUpdate();
			FusionBitPopup.OnUpdate();
		}
	}
	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))
			{
				GripExtender extender = value.GetExtender<GripExtender>();
				if (extender == null || !extender.CheckHeld())
				{
					NetworkEntityManager.TakeOwnership(value);
				}
			}
			else if (gameObject.IsSyncWhitelisted())
			{
				DelayUtilities.Delay(delegate
				{
					PropSender.SendPropCreation(marrowBody.Entity);
				}, 4);
			}
		}
	}
	internal static class BigEndianHelper
	{
		internal static void WriteBytes(byte[] destination, int offset, short value)
		{
			destination[offset] = (byte)(value >> 8);
			destination[offset + 1] = (byte)value;
		}

		internal static void WriteBytes(byte[] destination, int offset, ushort value)
		{
			destination[offset] = (byte)(value >> 8);
			destination[offset + 1] = (byte)value;
		}

		internal static void WriteBytes(byte[] destination, int offset, int value)
		{
			destination[offset] = (byte)(value >> 24);
			destination[offset + 1] = (byte)(value >> 16);
			destination[offset + 2] = (byte)(value >> 8);
			destination[offset + 3] = (byte)value;
		}

		internal static void WriteBytes(byte[] destination, int offset, uint value)
		{
			destination[offset] = (byte)(value >> 24);
			destination[offset + 1] = (byte)(value >> 16);
			destination[offset + 2] = (byte)(value >> 8);
			destination[offset + 3] = (byte)value;
		}

		internal static void WriteBytes(byte[] destination, int offset, long value)
		{
			destination[offset] = (byte)(value >> 56);
			destination[offset + 1] = (byte)(value >> 48);
			destination[offset + 2] = (byte)(value >> 40);
			destination[offset + 3] = (byte)(value >> 32);
			destination[offset + 4] = (byte)(value >> 24);
			destination[offset + 5] = (byte)(value >> 16);
			destination[offset + 6] = (byte)(value >> 8);
			destination[offset + 7] = (byte)value;
		}

		internal static void WriteBytes(byte[] destination, int offset, ulong value)
		{
			destination[offset] = (byte)(value >> 56);
			destination[offset + 1] = (byte)(value >> 48);
			destination[offset + 2] = (byte)(value >> 40);
			destination[offset + 3] = (byte)(value >> 32);
			destination[offset + 4] = (byte)(value >> 24);
			destination[offset + 5] = (byte)(value >> 16);
			destination[offset + 6] = (byte)(value >> 8);
			destination[offset + 7] = (byte)value;
		}

		internal unsafe static void WriteBytes(byte[] destination, int offset, float value)
		{
			uint value2 = *(uint*)(&value);
			WriteBytes(destination, offset, value2);
		}

		internal unsafe static void WriteBytes(byte[] destination, int offset, double value)
		{
			ulong value2 = *(ulong*)(&value);
			WriteBytes(destination, offset, value2);
		}

		internal static short ReadInt16(byte[] source, int offset)
		{
			return (short)((source[offset] << 8) | source[offset + 1]);
		}

		internal static ushort ReadUInt16(byte[] source, int offset)
		{
			return (ushort)((source[offset] << 8) | source[offset + 1]);
		}

		internal static int ReadInt32(byte[] source, int offset)
		{
			return (source[offset] << 24) | (source[offset + 1] << 16) | (source[offset + 2] << 8) | source[offset + 3];
		}

		internal static uint ReadUInt32(byte[] source, int offset)
		{
			return (uint)((source[offset] << 24) | (source[offset + 1] << 16) | (source[offset + 2] << 8) | source[offset + 3]);
		}

		internal static long ReadInt64(byte[] source, int offset)
		{
			return (long)(((ulong)source[offset] << 56) | ((ulong)source[offset + 1] << 48) | ((ulong)source[offset + 2] << 40) | ((ulong)source[offset + 3] << 32) | ((ulong)source[offset + 4] << 24) | ((ulong)source[offset + 5] << 16) | ((ulong)source[offset + 6] << 8) | source[offset + 7]);
		}

		internal static ulong ReadUInt64(byte[] source, int offset)
		{
			return ((ulong)source[offset] << 56) | ((ulong)source[offset + 1] << 48) | ((ulong)source[offset + 2] << 40) | ((ulong)source[offset + 3] << 32) | ((ulong)source[offset + 4] << 24) | ((ulong)source[offset + 5] << 16) | ((ulong)source[offset + 6] << 8) | source[offset + 7];
		}

		internal unsafe static float ReadSingle(byte[] source, int offset)
		{
			uint num = ReadUInt32(source, offset);
			return *(float*)(&num);
		}

		internal unsafe static double ReadDouble(byte[] source, int offset)
		{
			ulong num = ReadUInt64(source, offset);
			return *(double*)(&num);
		}

		internal static ushort SwapBytes(ushort value)
		{
			return (ushort)(((value & 0xFF) << 8) | ((value & 0xFF00) >> 8));
		}

		internal static uint SwapBytes(uint value)
		{
			return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000u) >> 24);
		}

		internal static ulong SwapBytes(ulong value)
		{
			return ((value & 0xFF) << 56) | ((value & 0xFF00) << 40) | ((value & 0xFF0000) << 24) | ((value & 0xFF000000u) << 8) | ((value & 0xFF00000000L) >> 8) | ((value & 0xFF0000000000L) >> 24) | ((value & 0xFF000000000000L) >> 40) | ((value & 0xFF00000000000000uL) >> 56);
		}
	}
	internal static class ManagedMathf
	{
		[StructLayout(LayoutKind.Sequential, Size = 1)]
		private struct MathfInternal
		{
			public static volatile float FloatMinNormal = 1.1754944E-38f;

			public static volatile float FloatMinDenormal = float.Epsilon;

			public static bool IsFlushToZeroEnabled = FloatMinDenormal == 0f;
		}

		public static readonly float Epsilon = (MathfInternal.IsFlushToZeroEnabled ? MathfInternal.FloatMinNormal : MathfInternal.FloatMinDenormal);

		public const float Rad2Deg = 57.29578f;

		public const float Deg2Rad = (float)Math.PI / 180f;

		public static float Sin(float f)
		{
			return (float)Math.Sin(f);
		}

		public static float Acos(float f)
		{
			return (float)Math.Acos(f);
		}

		public static float Clamp(float value, float min, float max)
		{
			if (value < min)
			{
				value = min;
			}
			else if (value > max)
			{
				value = max;
			}
			return value;
		}

		public static int Clamp(int value, int min, int max)
		{
			if (value < min)
			{
				value = min;
			}
			else if (value > max)
			{
				value = max;
			}
			return value;
		}

		public static float Clamp01(float value)
		{
			if (value < 0f)
			{
				return 0f;
			}
			if (value > 1f)
			{
				return 1f;
			}
			return value;
		}

		public static float Lerp(float a, float b, float t)
		{
			return a + (b - a) * Clamp01(t);
		}

		public static float LerpUnclamped(float a, float b, float t)
		{
			return a + (b - a) * t;
		}

		public static int FloorToInt(float f)
		{
			return (int)Math.Floor(f);
		}

		public static int CeilToInt(float f)
		{
			return (int)Math.Ceiling(f);
		}

		public static bool Approximately(float a, float b)
		{
			return Math.Abs(b - a) < Math.Max(1E-06f * Math.Max(Math.Abs(a), Math.Abs(b)), Epsilon * 8f);
		}
	}
	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()
		{
			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);
			DataCardReference<SurfaceDataCard> surfaceDataCard = new DataCardReference<SurfaceDataCard>("SLZ.Backlot.SurfaceDataCard.Blood");
			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 obj2 = gameObject.AddComponent<ImpactProperties>();
					obj2.SurfaceDataCard = surfaceDataCard;
					obj2.decalType = (DecalType)(-1);
				}
			}
		}
	}
	internal static class PhysicsUtilities
	{
		internal static void OnUpdateTimescale()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkInfo.HasServer)
			{
				return;
			}
			TimeScaleMode timeScaleMode = CommonPreferences.TimeScaleMode;
			RigManager rigManager = RigData.Refs.RigManager;
			if (timeScaleMode != TimeScaleMode.LOW_GRAVITY || !RigData.HasPlayer || TimeManager.cur_intensity <= 0f)
			{
				return;
			}
			float num = 1f - 1f / TimeManager.cur_intensity;
			Vector3 val = -Physics.gravity * num;
			Enumerator<Rigidbody> enumerator = rigManager.physicsRig.selfRbs.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Rigidbody current = enumerator.Current;
				if (current.useGravity)
				{
					current.AddForce(val, (ForceMode)5);
				}
			}
		}
	}
	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 MagazineUtilities
	{
		public static void ClaimMagazine(Magazine magazine, InventoryAmmoReceiver ammoReceiver)
		{
			//IL_0045: 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;
			}
			magazine.Initialize(val, AmmoInventory.Instance.GetCartridgeCount(val));
			magazine.Claim();
			SafeAudio3dPlayer.PlayAtPoint(Il2CppArrayBase<AudioClip>.op_Implicit((Il2CppArrayBase<AudioClip>)(object)ammoReceiver.grabClips), ((Component)ammoReceiver).transform.position, Audio3dManager.softInteraction, 0.2f);
		}

		public static void GrabMagazine(Magazine magazine, NetworkPlayer player, Handedness handedness)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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 == 1) ? rigManager.physicsRig.leftHand : rigManager.physicsRig.rightHand);
			if (Object.op_Implicit((Object)(object)found))
			{
				DelayUtilities.Delay(delegate
				{
					grip.MoveIntoHand(found);
					grip.TryAttach(found, isInstant: true);
				}, 1);
			}
		}
	}
	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 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_00b7: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			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();
				FusionNotifier.Send(new FusionNotification
				{
					isPopup = true,
					isMenuItem = false,
					message = (mutedPref.Value ? "Muted" : "Unmuted")
				});
			}));
			homePage.items.Add(_mutePage);
			OpenControllerRig val = ((Il2CppObjectBase)manager.ControllerRig).TryCast<OpenControllerRig>();
			Transform headset = val.headset;
			Spawnable val2 = new Spawnable
			{
				crateRef = FusionSpawnableReferences.MuteIndicatorReference,
				policyData = null
			};
			AssetSpawner.Register(val2);
			SafeAssetSpawner.Spawn(val2, 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).IsNOC())
			{
				_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.OnJoinServer += delegate
			{
				OnEnterServer(RigData.Refs.RigManager);
			};
			MultiplayerHooking.OnStartServer += delegate
			{
				OnEnterServer(RigData.Refs.RigManager);
			};
			MultiplayerHooking.OnDisconnect += delegate
			{
				OnExitServer(RigData.Refs.RigManager);
			};
			LocalPlayer.OnLocalRigCreated = (Action<RigManager>)Delegate.Combine(LocalPlayer.OnLocalRigCreated, (Action<RigManager>)delegate(RigManager rig)
			{
				OnCreatedLocalPlayer(rig);
				if (NetworkInfo.HasServer)
				{
					OnEnterServer(rig);
				}
			});
			MuteUIHelper.OnInitializeMelon();
		}

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

		public static void OnAvatarChanged(RigManager manager)
		{
		}

		public static void OnCreatedLocalPlayer(RigManager manager)
		{
			OnCreatedRig(manager);
		}

		public static void OnCreatedRig(RigManager manager)
		{
			OnAvatarChanged(manager);
		}

		public static void OnEnterServer(RigManager manager)
		{
			if (!((Object)(object)manager).IsNOC())
			{
				MuteUIHelper.OnCreateMuteUI(manager);
				PersistentAssetCreator.SetupImpactProperties(manager);
				manager.health._testRagdollOnDeath = true;
				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>();
				FusionPlayer.ResetMortality();
			}
		}

		public static void OnExitServer(RigManager manager)
		{
			if (((Object)(object)manager).IsNOC())
			{
				return;
			}
			MuteUIHelper.OnDestroyMuteUI();
			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._testRagdollOnDeath = false;
			manager.health._testVisualDamage = false;
			((Il2CppObjectBase)manager.health).TryCast<Player_Health>().slowMoOnDeath = true;
		}
	}
	public static class PooleeUtilities
	{
		internal static bool CanDespawn;

		public static void D

Plugins/LabFusionUpdater.dll

Decompiled 3 months ago
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using LabFusionUpdater;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LabFusion Updater")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany(null)]
[assembly: AssemblyProduct("LabFusion Updater")]
[assembly: AssemblyCopyright("Created by Lakatrazz")]
[assembly: AssemblyTrademark(null)]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: MelonInfo(typeof(FusionUpdaterPlugin), "LabFusion Updater", "1.0.0", "Lakatrazz", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LabFusionUpdater;

[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct FusionUpdaterVersion
{
	public const byte versionMajor = 1;

	public const byte versionMinor = 0;

	public const short versionPatch = 0;
}
public class FusionUpdaterPlugin : MelonPlugin
{
	public const string Name = "LabFusion Updater";

	public const string Author = "Lakatrazz";

	public static readonly Version Version = new Version(1, 0, 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 override void OnApplicationQuit()
	{
		Updater.UpdatePlugin();
	}
}
internal static class Updater
{
	private static readonly string _dataDir = Path.Combine(MelonEnvironment.UserDataDirectory, "LabFusionUpdater");

	private static readonly string _updaterAppName = "updater.exe";

	private static bool pluginNeedsUpdating = false;

	public static void UpdateMod()
	{
		Version value = new Version(0, 0, 0);
		if (File.Exists(FusionUpdaterPlugin.ModAssemblyPath))
		{
			AssemblyName assemblyName = AssemblyName.GetAssemblyName(FusionUpdaterPlugin.ModAssemblyPath);
			value = new Version(assemblyName.Version.Major, assemblyName.Version.Minor, assemblyName.Version.Build);
			FusionUpdaterPlugin.Logger.Msg($"{"LabFusion"}{".dll"} found in Mods folder. Version: {value}");
		}
		try
		{
			Directory.CreateDirectory(_dataDir);
			string text = Path.Combine(_dataDir, _updaterAppName);
			Assembly updaterAssembly = FusionUpdaterPlugin.UpdaterAssembly;
			string name = updaterAssembly.GetManifestResourceNames().First((string x) => x.Contains(_updaterAppName));
			using (Stream stream = updaterAssembly.GetManifestResourceStream(name))
			{
				using FileStream destination = File.Create(text);
				stream.CopyTo(destination);
			}
			Process process = new Process();
			process.StartInfo.FileName = text;
			process.StartInfo.Arguments = $"{value} \"{FusionUpdaterPlugin.ModAssemblyPath}\" \"{FusionUpdaterPlugin.PluginAssemblyPath}\" \"false\"";
			process.Start();
			process.WaitForExit();
			switch ((ExitCode)process.ExitCode)
			{
			case ExitCode.Success:
				((MelonBase)FusionUpdaterPlugin.Instance).LoggerInstance.Msg("LabFusion.dll updated successfully!");
				pluginNeedsUpdating = true;
				break;
			case ExitCode.UpToDate:
				((MelonBase)FusionUpdaterPlugin.Instance).LoggerInstance.Msg("LabFusion.dll is already up to date.");
				break;
			case ExitCode.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());
		}
	}

	public static void UpdatePlugin()
	{
		if (!pluginNeedsUpdating)
		{
			return;
		}
		Directory.CreateDirectory(_dataDir);
		string text = Path.Combine(_dataDir, _updaterAppName);
		Assembly executingAssembly = Assembly.GetExecutingAssembly();
		string name = executingAssembly.GetManifestResourceNames().First((string x) => x.Contains(_updaterAppName));
		using (Stream stream = executingAssembly.GetManifestResourceStream(name))
		{
			using FileStream destination = File.Create(text);
			stream.CopyTo(destination);
		}
		Process process = new Process();
		process.StartInfo.FileName = text;
		process.StartInfo.Arguments = $"{new Version(0, 0, 0)} \"{FusionUpdaterPlugin.ModAssemblyPath}\" \"{FusionUpdaterPlugin.PluginAssemblyPath}\" true";
		process.Start();
	}
}
internal enum ExitCode
{
	Success,
	UpToDate,
	Error
}