Decompiled source of TideFusion v1.1.1

Mods/LabFusion.dll

Decompiled a year 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.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
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 BoneLib.BoneMenu.Elements;
using BoneLib.BoneMenu.UI;
using BoneLib.Nullables;
using FusionHelper.Network;
using HarmonyLib;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LabFusion;
using LabFusion.BoneMenu;
using LabFusion.Data;
using LabFusion.Exceptions;
using LabFusion.Extensions;
using LabFusion.Grabbables;
using LabFusion.MarrowIntegration;
using LabFusion.MonoBehaviours;
using LabFusion.NativeStructs;
using LabFusion.Network;
using LabFusion.Patching;
using LabFusion.Preferences;
using LabFusion.Representation;
using LabFusion.Riptide.BoneMenu;
using LabFusion.Riptide.Messages;
using LabFusion.Riptide.Preferences;
using LabFusion.Riptide.Utilities;
using LabFusion.Riptide.Voice;
using LabFusion.SDK.Achievements;
using LabFusion.SDK.Gamemodes;
using LabFusion.SDK.Modules;
using LabFusion.SDK.Points;
using LabFusion.Senders;
using LabFusion.Syncables;
using LabFusion.UI;
using LabFusion.Utilities;
using LabFusion.XML;
using LiteNetLib;
using LiteNetLib.Layers;
using LiteNetLib.Utils;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Oculus.Platform;
using Oculus.Platform.Models;
using PuppetMasta;
using Riptide;
using SLZ;
using SLZ.AI;
using SLZ.Bonelab;
using SLZ.Combat;
using SLZ.Data;
using SLZ.Interaction;
using SLZ.Marrow;
using SLZ.Marrow.Data;
using SLZ.Marrow.Input;
using SLZ.Marrow.Pool;
using SLZ.Marrow.SceneStreaming;
using SLZ.Marrow.Utilities;
using SLZ.Marrow.Warehouse;
using SLZ.Player;
using SLZ.Props;
using SLZ.Props.Weapons;
using SLZ.Rig;
using SLZ.SFX;
using SLZ.SaveData;
using SLZ.UI;
using SLZ.Utilities;
using SLZ.VFX;
using SLZ.VRMK;
using SLZ.Vehicle;
using SLZ.Zones;
using Steamworks;
using Steamworks.Data;
using Steamworks.Ugc;
using TMPro;
using UltEvents;
using UnhollowerBaseLib;
using UnhollowerBaseLib.Attributes;
using UnhollowerRuntimeLib;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
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.5.1")]
[assembly: MelonInfo(typeof(FusionMod), "LabFusion", "1.5.1", "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(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.1.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
}
namespace LabFusion
{
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct FusionVersion
	{
		public const byte versionMajor = 1;

		public const byte versionMinor = 5;

		public const short versionPatch = 1;
	}
	public class FusionMod : MelonMod
	{
		public const string Name = "LabFusion";

		public const string Author = "Lakatrazz";

		public static readonly Version Version = new Version(1, 5, 1);

		private static int _nextSyncableSendRate = 1;

		private static bool _hasAutoUpdater = 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 = Assembly.GetExecutingAssembly();
			PersistentData.OnPathInitialize();
			SteamAPILoader.OnLoadSteamAPI();
			ByteRetriever.PopulateInitial();
			PDController.OnInitializeMelon();
			ModuleHandler.Internal_HookAssemblies();
			GamemodeRegistration.Internal_HookAssemblies();
			PointItemManager.Internal_HookAssemblies();
			VoteKickHelper.Internal_OnInitializeMelon();
		}

		public override void OnInitializeMelon()
		{
			FusionPreferences.OnPrepareBoneMenuCategory();
			FusionFileLoader.OnInitializeMelon();
			FusionBundleLoader.OnBundleLoad();
			LevelDataHandler.OnInitializeMelon();
			FusionMessageHandler.RegisterHandlersFromAssembly(FusionAssembly);
			GrabGroupHandler.RegisterHandlersFromAssembly(FusionAssembly);
			PropExtenderManager.RegisterExtendersFromAssembly(FusionAssembly);
			NetworkLayer.RegisterLayersFromAssembly(FusionAssembly);
			GamemodeRegistration.LoadGamemodes(FusionAssembly);
			PointItemManager.LoadItems(FusionAssembly);
			AchievementManager.LoadAchievements(FusionAssembly);
			SyncManager.OnInitializeMelon();
			FusionPopupManager.OnInitializeMelon();
			FusionPreferences.OnInitializePreferences();
			FusionSceneManager.Internal_OnInitializeMelon();
			OnInitializeNetworking();
		}

		public override void OnLateInitializeMelon()
		{
			ManualPatcher.PatchAll();
			InternalLayerHelpers.OnLateInitializeLayer();
			PersistentAssetCreator.OnLateInitializeMelon();
			PlayerAdditionsHelper.OnInitializeMelon();
			FusionPreferences.OnCreateBoneMenu();
			_hasAutoUpdater = MelonTypeBase<MelonPlugin>.RegisteredMelons.Any((MelonPlugin p) => ((MelonBase)p).Info.Name.Contains("LabFusion Updater"));
			if (!_hasAutoUpdater && !HelperMethods.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 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.Internal_UnhookAssemblies();
			FusionBundleLoader.OnBundleUnloaded();
			PlayerAdditionsHelper.OnDeinitializeMelon();
			SteamAPILoader.OnFreeSteamAPI();
		}

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

		public static void OnMainSceneInitialized()
		{
			_ = ((Scannable)FusionSceneManager.Level).Title;
			StaticGripFixer.OnMainSceneInitialized();
			SyncManager.OnCleanup();
			RigData.OnCacheRigInfo();
			PersistentAssetCreator.OnMainSceneInitialized();
			ConstrainerUtilities.OnMainSceneInitialized();
			PlayerRep.OnRecreateReps();
			MultiplayerHooking.Internal_OnMainSceneInitialized();
			FusionPlayer.OnMainSceneInitialized();
			if (NetworkInfo.IsServer && Gamemode.ActiveGamemode != null && Gamemode.ActiveGamemode.AutoStopOnSceneLoad)
			{
				Gamemode.ActiveGamemode.StopGamemode();
			}
		}

		public static void OnMainSceneInitializeDelayed()
		{
			if (RigData.HasPlayer)
			{
				RigData.RigReferences.RigManager.bodyVitals.quickmenuEnabled = true;
				((ControllerRig)RigData.RigReferences.RigManager.openControllerRig).quickmenuEnabled = true;
			}
		}

		public override void OnUpdate()
		{
			NetworkInfo.BytesDown = 0;
			NetworkInfo.BytesUp = 0;
			ThreadingUtilities.Internal_OnUpdate();
			PhysicsUtilities.OnCacheValues();
			FusionSceneManager.Internal_UpdateScene();
			RigData.OnRigUpdate();
			FusionPopupManager.OnUpdate();
			int playerSendRate = SendRateTable.GetPlayerSendRate();
			if (Time.frameCount % playerSendRate == 0)
			{
				PlayerRep.OnSyncRep();
			}
			if (Time.frameCount % _nextSyncableSendRate == 0)
			{
				int bytesUp = NetworkInfo.BytesUp;
				SyncManager.OnUpdate();
				_nextSyncableSendRate = SendRateTable.GetObjectSendRate(NetworkInfo.BytesUp - bytesUp);
			}
			PhysicsUtilities.OnSendPhysicsInformation();
			PlayerRep.OnUpdate();
			InternalLayerHelpers.OnVoiceChatUpdate();
			InternalLayerHelpers.OnUpdateLayer();
			MultiplayerHooking.Internal_OnUpdate();
			GamemodeManager.Internal_OnUpdate();
			DelayUtilities.Internal_OnUpdate();
		}

		public override void OnFixedUpdate()
		{
			PhysicsUtilities.OnUpdateTimescale();
			PDController.OnFixedUpdate();
			PlayerRep.OnFixedUpdate();
			SyncManager.OnFixedUpdate();
			MultiplayerHooking.Internal_OnFixedUpdate();
			GamemodeManager.Internal_OnFixedUpdate();
		}

		public override void OnLateUpdate()
		{
			PlayerRep.OnLateUpdate();
			InternalLayerHelpers.OnLateUpdateLayer();
			MultiplayerHooking.Internal_OnLateUpdate();
			GamemodeManager.Internal_OnLateUpdate();
		}

		public override void OnGUI()
		{
			InternalLayerHelpers.OnGUILayer();
		}
	}
}
namespace LabFusion.Preferences
{
	public enum PrefUpdateMode
	{
		IGNORE,
		SERVER_UPDATE,
		CLIENT_UPDATE,
		LOCAL_UPDATE
	}
	public interface IFusionPref<T>
	{
		Action<T> OnValueChanged { get; set; }

		void SetValue(T value);

		T GetValue();
	}
	public class ReadonlyFusionPrev<T> : IFusionPref<T>
	{
		private readonly T _value;

		public Action<T> OnValueChanged { get; set; }

		public ReadonlyFusionPrev(T value)
		{
			_value = value;
		}

		public void SetValue(T value)
		{
		}

		public T GetValue()
		{
			return _value;
		}
	}
	public class FusionPref<T> : IFusionPref<T>
	{
		private readonly MelonPreferences_Category _category;

		private readonly MelonPreferences_Entry<T> _entry;

		private readonly PrefUpdateMode _mode;

		public Action<T> OnValueChanged { get; set; }

		public FusionPref(MelonPreferences_Category category, string name, T defaultValue, PrefUpdateMode mode = PrefUpdateMode.IGNORE)
		{
			_category = category;
			_entry = category.CreateEntry<T>(name, defaultValue, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			_mode = mode;
			FusionPreferences.OnFusionPreferencesLoaded = (Action)Delegate.Combine(FusionPreferences.OnFusionPreferencesLoaded, new Action(OnPreferencesLoaded));
		}

		public void SetValue(T value)
		{
			_entry.Value = value;
			OnValueChanged?.Invoke(value);
			_category.SaveToFile(false);
			PushUpdate();
		}

		public void OnPreferencesLoaded()
		{
			OnValueChanged?.Invoke(GetValue());
			PushUpdate();
		}

		private void PushUpdate()
		{
			switch (_mode)
			{
			case PrefUpdateMode.SERVER_UPDATE:
				FusionPreferences.SendServerSettings();
				MultiplayerHooking.Internal_OnServerSettingsChanged();
				break;
			case PrefUpdateMode.CLIENT_UPDATE:
				FusionPreferences.SendClientSettings();
				break;
			case PrefUpdateMode.LOCAL_UPDATE:
				MultiplayerHooking.Internal_OnServerSettingsChanged();
				break;
			case PrefUpdateMode.IGNORE:
				break;
			}
		}

		public T GetValue()
		{
			return _entry.Value;
		}

		public static implicit operator T(FusionPref<T> pref)
		{
			return pref.GetValue();
		}
	}
	public static class FusionPreferences
	{
		public class ServerSettings
		{
			public IFusionPref<bool> NametagsEnabled;

			public IFusionPref<bool> VoicechatEnabled;

			public IFusionPref<bool> PlayerConstraintsEnabled;

			public IFusionPref<bool> VoteKickingEnabled;

			public IFusionPref<ServerPrivacy> Privacy;

			public IFusionPref<bool> AllowQuestUsers;

			public IFusionPref<bool> AllowPCUsers;

			public IFusionPref<TimeScaleMode> TimeScaleMode;

			public IFusionPref<byte> MaxPlayers;

			public IFusionPref<string> ServerName;

			public IFusionPref<List<string>> ServerTags;

			public IFusionPref<bool> ServerMortality;

			public IFusionPref<PermissionLevel> StatChangersAllowed;

			public IFusionPref<float> StatChangerLeeway;

			public IFusionPref<PermissionLevel> DevToolsAllowed;

			public IFusionPref<PermissionLevel> ConstrainerAllowed;

			public IFusionPref<PermissionLevel> CustomAvatarsAllowed;

			public IFusionPref<PermissionLevel> KickingAllowed;

			public IFusionPref<PermissionLevel> BanningAllowed;

			public IFusionPref<PermissionLevel> Teleportation;

			public static ServerSettings CreateMelonPrefs()
			{
				return new ServerSettings
				{
					NametagsEnabled = new FusionPref<bool>(prefCategory, "Server Nametags Enabled", defaultValue: true, PrefUpdateMode.SERVER_UPDATE),
					VoicechatEnabled = new FusionPref<bool>(prefCategory, "Server Voicechat Enabled", defaultValue: true, PrefUpdateMode.SERVER_UPDATE),
					PlayerConstraintsEnabled = new FusionPref<bool>(prefCategory, "Server Player Constraints Enabled", defaultValue: false, PrefUpdateMode.SERVER_UPDATE),
					VoteKickingEnabled = new FusionPref<bool>(prefCategory, "Server Vote Kicking Enabled", defaultValue: true, PrefUpdateMode.SERVER_UPDATE),
					Privacy = new FusionPref<ServerPrivacy>(prefCategory, "Server Privacy", ServerPrivacy.PUBLIC, PrefUpdateMode.LOCAL_UPDATE),
					AllowQuestUsers = new FusionPref<bool>(prefCategory, "Allow Quest Users", defaultValue: true, PrefUpdateMode.SERVER_UPDATE),
					AllowPCUsers = new FusionPref<bool>(prefCategory, "Allow PC Users", defaultValue: true, PrefUpdateMode.SERVER_UPDATE),
					TimeScaleMode = new FusionPref<TimeScaleMode>(prefCategory, "Time Scale Mode", LabFusion.Senders.TimeScaleMode.LOW_GRAVITY, PrefUpdateMode.SERVER_UPDATE),
					MaxPlayers = new FusionPref<byte>(prefCategory, "Max Players", 10, PrefUpdateMode.SERVER_UPDATE),
					ServerName = new FusionPref<string>(prefCategory, "Server Name", "", PrefUpdateMode.LOCAL_UPDATE),
					ServerTags = new FusionPref<List<string>>(prefCategory, "Server Tags", new List<string>(), PrefUpdateMode.LOCAL_UPDATE),
					ServerMortality = new FusionPref<bool>(prefCategory, "Server Mortality", defaultValue: true, PrefUpdateMode.SERVER_UPDATE),
					StatChangersAllowed = new FusionPref<PermissionLevel>(prefCategory, "Stat Changers Allowed", PermissionLevel.OPERATOR, PrefUpdateMode.SERVER_UPDATE),
					StatChangerLeeway = new FusionPref<float>(prefCategory, "Stat Changer Leeway", 0f, PrefUpdateMode.SERVER_UPDATE),
					DevToolsAllowed = new FusionPref<PermissionLevel>(prefCategory, "Dev Tools Allowed", PermissionLevel.DEFAULT, PrefUpdateMode.SERVER_UPDATE),
					ConstrainerAllowed = new FusionPref<PermissionLevel>(prefCategory, "Constrainer Allowed", PermissionLevel.DEFAULT, PrefUpdateMode.SERVER_UPDATE),
					CustomAvatarsAllowed = new FusionPref<PermissionLevel>(prefCategory, "Custom Avatars Allowed", PermissionLevel.DEFAULT, PrefUpdateMode.SERVER_UPDATE),
					KickingAllowed = new FusionPref<PermissionLevel>(prefCategory, "Kicking Allowed", PermissionLevel.OPERATOR, PrefUpdateMode.SERVER_UPDATE),
					BanningAllowed = new FusionPref<PermissionLevel>(prefCategory, "Banning Allowed", PermissionLevel.OPERATOR, PrefUpdateMode.SERVER_UPDATE),
					Teleportation = new FusionPref<PermissionLevel>(prefCategory, "Teleportation", PermissionLevel.OPERATOR, PrefUpdateMode.SERVER_UPDATE)
				};
			}
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct ClientSettings
		{
			public static FusionPref<string> NetworkLayerTitle { get; internal set; }

			public static FusionPref<int> ProxyPort { get; internal set; }

			public static FusionPref<bool> NametagsEnabled { get; internal set; }

			public static FusionPref<Color> NametagColor { get; internal set; }

			public static FusionPref<string> Nickname { get; internal set; }

			public static FusionPref<NicknameVisibility> NicknameVisibility { get; internal set; }

			public static FusionPref<bool> Muted { get; internal set; }

			public static FusionPref<bool> MutedIndicator { get; internal set; }

			public static FusionPref<bool> Deafened { get; internal set; }

			public static FusionPref<float> GlobalVolume { get; internal set; }

			public static FusionPref<bool> GamemodeMusic { get; internal set; }

			public static FusionPref<bool> GamemodeLateJoining { get; internal set; }
		}

		internal static ServerSettings LocalServerSettings;

		internal static MenuCategory fusionCategory;

		internal static MelonPreferences_Category prefCategory;

		internal static Action OnFusionPreferencesLoaded;

		private static int _lastIndex;

		internal static ServerSettings ReceivedServerSettings { get; set; }

		internal static ServerSettings ActiveServerSettings => ReceivedServerSettings ?? LocalServerSettings;

		internal static bool NametagsEnabled
		{
			get
			{
				if (ActiveServerSettings.NametagsEnabled.GetValue())
				{
					return ClientSettings.NametagsEnabled;
				}
				return false;
			}
		}

		internal static bool IsMortal => ActiveServerSettings.ServerMortality.GetValue();

		internal static TimeScaleMode TimeScaleMode => ActiveServerSettings.TimeScaleMode.GetValue();

		internal static void SendServerSettings()
		{
			if (!NetworkInfo.HasServer || !NetworkInfo.IsServer)
			{
				return;
			}
			using FusionWriter fusionWriter = FusionWriter.Create();
			using ServerSettingsData value = ServerSettingsData.Create(SerializedServerSettings.Create());
			fusionWriter.Write(value);
			using LabFusion.Network.FusionMessage message = LabFusion.Network.FusionMessage.Create(NativeMessageTag.ServerSettings, fusionWriter);
			MessageSender.BroadcastMessageExceptSelf(NetworkChannel.Reliable, message);
		}

		internal static void SendServerSettings(ulong longId)
		{
			if (!NetworkInfo.HasServer || !NetworkInfo.IsServer)
			{
				return;
			}
			using FusionWriter fusionWriter = FusionWriter.Create(13);
			using ServerSettingsData value = ServerSettingsData.Create(SerializedServerSettings.Create());
			fusionWriter.Write(value);
			using LabFusion.Network.FusionMessage message = LabFusion.Network.FusionMessage.Create(NativeMessageTag.ServerSettings, fusionWriter);
			MessageSender.SendFromServer(longId, NetworkChannel.Reliable, message);
		}

		internal static void SendClientSettings()
		{
			if (!NetworkInfo.HasServer)
			{
				return;
			}
			using FusionWriter fusionWriter = FusionWriter.Create(17);
			using PlayerSettingsData value = PlayerSettingsData.Create(PlayerIdManager.LocalSmallId, SerializedPlayerSettings.Create());
			fusionWriter.Write(value);
			using LabFusion.Network.FusionMessage message = LabFusion.Network.FusionMessage.Create(NativeMessageTag.PlayerSettings, fusionWriter);
			MessageSender.SendToServer(NetworkChannel.Reliable, message);
		}

		internal static void OnInitializePreferences()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			prefCategory = MelonPreferences.CreateCategory("BONELAB Fusion");
			LocalServerSettings = ServerSettings.CreateMelonPrefs();
			ClientSettings.NetworkLayerTitle = new FusionPref<string>(prefCategory, "Network Layer Title", NetworkLayerDeterminer.GetDefaultLayer().Title);
			ClientSettings.ProxyPort = new FusionPref<int>(prefCategory, "Proxy Port", 28340);
			ClientSettings.NametagsEnabled = new FusionPref<bool>(prefCategory, "Client Nametags Enabled", defaultValue: true, PrefUpdateMode.LOCAL_UPDATE);
			ClientSettings.NametagColor = new FusionPref<Color>(prefCategory, "Nametag Color", Color.white, PrefUpdateMode.CLIENT_UPDATE);
			ClientSettings.Nickname = new FusionPref<string>(prefCategory, "Nickname", "");
			ClientSettings.NicknameVisibility = new FusionPref<NicknameVisibility>(prefCategory, "Nickname Visibility", NicknameVisibility.SHOW_WITH_PREFIX, PrefUpdateMode.LOCAL_UPDATE);
			ClientSettings.Muted = new FusionPref<bool>(prefCategory, "Muted", defaultValue: false);
			ClientSettings.MutedIndicator = new FusionPref<bool>(prefCategory, "Muted Indicator", defaultValue: true);
			ClientSettings.Deafened = new FusionPref<bool>(prefCategory, "Deafened", defaultValue: false);
			ClientSettings.GlobalVolume = new FusionPref<float>(prefCategory, "GlobalMicVolume", 1f);
			ClientSettings.GamemodeMusic = new FusionPref<bool>(prefCategory, "Gamemode Music", defaultValue: true);
			ClientSettings.GamemodeLateJoining = new FusionPref<bool>(prefCategory, "Gamemode Late Joining", defaultValue: true);
			prefCategory.SaveToFile(false);
		}

		internal static void OnPrepareBoneMenuCategory()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			fusionCategory = MenuManager.CreateCategory("BONELAB Fusion", Color.white);
		}

		internal static void OnCreateBoneMenu()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			MenuCategory val = fusionCategory.CreateCategory("Network Layer Manager", Color.yellow);
			val.CreateFunctionElement("Players need to be on the same layer!", Color.yellow, (Action)null);
			_lastIndex = NetworkLayer.SupportedLayers.IndexOf(NetworkLayerDeterminer.LoadedLayer);
			val.CreateFunctionElement("Active Layer: " + NetworkLayerDeterminer.LoadedTitle, Color.white, (Action)null);
			SubPanelElement targetPanel = val.CreateSubPanel("Target Layer: " + ClientSettings.NetworkLayerTitle.GetValue(), Color.white);
			targetPanel.CreateFunctionElement("Cycle", Color.white, (Action)delegate
			{
				int count = NetworkLayer.SupportedLayers.Count;
				if (count > 0)
				{
					_lastIndex++;
					if (count <= _lastIndex)
					{
						_lastIndex = 0;
					}
					ClientSettings.NetworkLayerTitle.SetValue(NetworkLayer.SupportedLayers[_lastIndex].Title);
				}
			});
			FusionPref<string> networkLayerTitle = ClientSettings.NetworkLayerTitle;
			networkLayerTitle.OnValueChanged = (Action<string>)Delegate.Combine(networkLayerTitle.OnValueChanged, (Action<string>)delegate(string v)
			{
				((MenuElement)targetPanel).SetName("Target Layer: " + v);
			});
			targetPanel.CreateFunctionElement("Changing this setting requires a game restart!", Color.red, (Action)null);
			InternalLayerHelpers.OnSetupBoneMenuLayer(fusionCategory);
		}

		internal static void OnPreferencesLoaded()
		{
			OnFusionPreferencesLoaded?.Invoke();
		}
	}
}
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 BOARD_BARCODE = "c1534c5a-7b2a-41d7-bf2e-af9544657374";

		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 => FusionPreferences.ActiveServerSettings.PlayerConstraintsEnabled.GetValue();

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

		public static Constrainer GlobalConstrainer { get; private set; }

		public static void OnMainSceneInitialized()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			SpawnableCrate crate = AssetWarehouse.Instance.GetCrate<SpawnableCrate>("c1534c5a-3813-49d6-a98c-f595436f6e73");
			if (!((Object)(object)crate != (Object)null))
			{
				return;
			}
			if (!((Crate)crate).Pallet.Internal)
			{
				((GameObjectCrate)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 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			int num = _bitQueue.Dequeue();
			Transform head = ((Rig)RigData.RigReferences.ControllerRig).m_head;
			GameObject obj = Object.Instantiate<GameObject>(FusionContentLoader.BitPopupPrefab, head);
			UIMachineUtilities.OverrideFonts(obj.transform);
			obj.transform.localPosition = LocalPosition;
			obj.transform.localRotation = LocalRotation;
			Transform val = obj.transform.Find("Offset/Canvas");
			string text = ((num < 0) ? $"{num}" : $"+{num}");
			((Component)val.Find("text_shadow")).GetComponent<TMP_Text>().text = text;
			TMP_Text component = ((Component)val.Find("amount")).GetComponent<TMP_Text>();
			component.text = text;
			if (num < 0)
			{
				component.color = Color.red;
				((Graphic)((Component)val.Find("bit")).GetComponent<RawImage>()).color = Color.red;
			}
			FusionAudio.Play2D(FusionContentLoader.BitGet);
			Object.Destroy((Object)(object)obj, 1.1f);
		}
	}
	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_0041: Unknown result type (might be due to invalid IL or missing references)
			_timeOfPopup = Time.realtimeSinceStartup;
			LabFusion.SDK.Achievements.Achievement achievement = _queuedAchievements.Dequeue();
			Transform head = ((Rig)RigData.RigReferences.ControllerRig).m_head;
			GameObject obj = Object.Instantiate<GameObject>(FusionContentLoader.AchievementPopupPrefab, head);
			UIMachineUtilities.OverrideFonts(obj.transform);
			obj.transform.localPosition = LocalPosition;
			Transform val = obj.transform.Find("Offset/Canvas");
			if ((Object)(object)achievement.PreviewImage != (Object)null)
			{
				((Component)val.Find("icon")).GetComponent<RawImage>().texture = (Texture)(object)achievement.PreviewImage;
			}
			((Component)val.Find("title")).GetComponent<TMP_Text>().text = achievement.Title;
			((Component)val.Find("description")).GetComponent<TMP_Text>().text = achievement.Description;
			FusionAudio.Play2D(FusionContentLoader.UITurnOn);
			Object.Destroy((Object)(object)obj, 5.1f);
		}

		internal static bool IsPlayingPopup()
		{
			return Time.realtimeSinceStartup - _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 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 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 class AchievementPair
	{
		public Texture2D Preview { get; private set; }

		public static AchievementPair LoadFromBundle(AssetBundle bundle, string name)
		{
			return new AchievementPair
			{
				Preview = bundle.LoadPersistentAsset<Texture2D>("preview_" + name)
			};
		}
	}
	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>();

		public static AssetBundle AchievementBundle { get; private set; }

		public static void OnBundleLoad()
		{
			AchievementBundle = FusionBundleLoader.LoadAssetBundle("achievement_bundle.fusion");
			if ((Object)(object)AchievementBundle != (Object)null)
			{
				string[] achievementNames = _achievementNames;
				foreach (string text in achievementNames)
				{
					_achievementPairs.Add(text, AchievementPair.LoadFromBundle(AchievementBundle, text));
				}
			}
			else
			{
				FusionLogger.Error("Achievement bundle failed to load!");
			}
		}

		public static void OnBundleUnloaded()
		{
			if ((Object)(object)AchievementBundle != (Object)null)
			{
				AchievementBundle.Unload(true);
			}
		}

		public static AchievementPair GetPair(string name)
		{
			return _achievementPairs[name];
		}
	}
	public class ItemPair
	{
		public GameObject GameObject { get; private set; }

		public Texture2D Preview { get; private set; }

		public static ItemPair LoadFromBundle(AssetBundle bundle, string name)
		{
			return new ItemPair
			{
				GameObject = bundle.LoadPersistentAsset<GameObject>("item_" + name),
				Preview = bundle.LoadPersistentAsset<Texture2D>("preview_" + name)
			};
		}
	}
	public static class FusionPointItemLoader
	{
		private static readonly string[] _itemNames = new string[73]
		{
			"Gemstone", "GloopTrail", "Junktion", "PulsatingMass", "RubixCube", "BitsTrail", "CardboardTophat", "Glasses3D", "AdventureHat", "WaistRing",
			"BodyPillow", "BritishHelm", "CardboardDisguise", "CatBeanie", "CheeseHat", "ConstructionHat", "Cooler", "EltonGlasses", "EnaHat", "Fez",
			"Firework", "Fren", "FryCookHat", "Gearhead", "GuardHelmet", "KickMeSign", "KnollHat", "LaytonHat", "LegoHead", "LightningHead",
			"Monocle", "NyanTrail", "PartyHat", "PieceOfResistance", "SorcererHat", "StormyHead", "TestItem", "TheBeacon", "WeirdShades", "BitMiner",
			"AncientTablet", "BitBackpack", "Briefcase", "CirclingBit", "Floatie", "Headset", "HotHead", "Jetpack", "NESGuitar", "OctoSpecs",
			"Potion", "PsychicPerception", "RetroMind", "SignalingSpiral", "Speaker", "VioletVortex", "VictoryTrophy", "ArrowHead", "BucketHat", "CBRNGasMask",
			"Crown", "Fedoral", "FlinchsJinjle", "GP5", "JesterHat", "MissedAWideGlasses", "MissedAWideHat", "OldTimeyPipe", "RiotHelmet", "Smitty",
			"VirtuallyInsane", "Wonker", "ZestySwagShades"
		};

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

		public static AssetBundle ItemBundle { get; private set; }

		public static void OnBundleLoad()
		{
			ItemBundle = FusionBundleLoader.LoadAssetBundle("item_bundle.fusion");
			if ((Object)(object)ItemBundle != (Object)null)
			{
				string[] itemNames = _itemNames;
				foreach (string text in itemNames)
				{
					_itemPairs.Add(text, ItemPair.LoadFromBundle(ItemBundle, text));
				}
			}
			else
			{
				FusionLogger.Error("Item bundle failed to load!");
			}
		}

		public static void OnBundleUnloaded()
		{
			if ((Object)(object)ItemBundle != (Object)null)
			{
				ItemBundle.Unload(true);
			}
		}

		public static ItemPair GetPair(string name)
		{
			return _itemPairs[name];
		}
	}
	public static class FusionContentLoader
	{
		private static readonly string[] _combatSongNames = new string[6] { "music_FreqCreepInModulationBuggyPhysics", "music_SicklyBugInitiative", "music_SyntheticCavernsRemix", "music_WWWonderlan", "music_SmigglesInDespair", "music_AppenBeyuge" };

		private static readonly List<AudioClip> _combatPlaylist = new List<AudioClip>();

		public static AssetBundle ContentBundle { get; private set; }

		public static GameObject PointShopPrefab { get; private set; }

		public static GameObject InfoBoxPrefab { get; private set; }

		public static GameObject CupBoardPrefab { get; private set; }

		public static GameObject EntangledLinePrefab { get; private set; }

		public static GameObject AchievementPopupPrefab { get; private set; }

		public static GameObject BitPopupPrefab { get; private set; }

		public static GameObject MutePopupPrefab { get; private set; }

		public static Texture2D SabrelakeLogo { get; private set; }

		public static Texture2D LavaGangLogo { get; private set; }

		public static AudioClip GeoGrpFellDownTheStairs { get; private set; }

		public static AudioClip BouncingStrong { get; private set; }

		public static AudioClip LavaGangVictory { get; private set; }

		public static AudioClip SabrelakeVictory { get; private set; }

		public static AudioClip LavaGangFailure { get; private set; }

		public static AudioClip SabrelakeFailure { get; private set; }

		public static AudioClip DMTie { get; private set; }

		public static AudioClip BitGet { get; private set; }

		public static AudioClip UISelect { get; private set; }

		public static AudioClip UIDeny { get; private set; }

		public static AudioClip UIConfirm { get; private set; }

		public static AudioClip UITurnOff { get; private set; }

		public static AudioClip UITurnOn { get; private set; }

		public static AudioClip PurchaseFailure { get; private set; }

		public static AudioClip PurchaseSuccess { get; private set; }

		public static AudioClip EquipItem { get; private set; }

		public static AudioClip UnequipItem { get; private set; }

		public static Texture2D NotificationInformation { get; private set; }

		public static Texture2D NotificationWarning { get; private set; }

		public static Texture2D NotificationError { get; private set; }

		public static Texture2D NotificationSuccess { get; private set; }

		public static GameObject LaserCursor { get; private set; }

		public static AudioClip LaserPulseSound { get; private set; }

		public static AudioClip LaserRaySpawn { get; private set; }

		public static AudioClip LaserRayDespawn { get; private set; }

		public static AudioClip LaserPrismaticSFX { get; private set; }

		public static AudioClip[] CombatPlaylist => _combatPlaylist.ToArray();

		public static void OnBundleLoad()
		{
			ContentBundle = FusionBundleLoader.LoadAssetBundle("content_bundle.fusion");
			if ((Object)(object)ContentBundle != (Object)null)
			{
				PointShopPrefab = ContentBundle.LoadPersistentAsset<GameObject>("machine_PointShop");
				InfoBoxPrefab = ContentBundle.LoadPersistentAsset<GameObject>("machine_InfoBox");
				CupBoardPrefab = ContentBundle.LoadPersistentAsset<GameObject>("machine_CupBoard");
				EntangledLinePrefab = ContentBundle.LoadPersistentAsset<GameObject>("renderer_EntangledLine");
				AchievementPopupPrefab = ContentBundle.LoadPersistentAsset<GameObject>("achievement_Popup");
				BitPopupPrefab = ContentBundle.LoadPersistentAsset<GameObject>("bit_Popup");
				MutePopupPrefab = ContentBundle.LoadPersistentAsset<GameObject>("mute_Popup");
				SabrelakeLogo = ContentBundle.LoadPersistentAsset<Texture2D>("tex_sabreLakeLogo");
				LavaGangLogo = ContentBundle.LoadPersistentAsset<Texture2D>("tex_lavaGangLogo");
				string[] combatSongNames = _combatSongNames;
				foreach (string name in combatSongNames)
				{
					_combatPlaylist.Add(ContentBundle.LoadPersistentAsset<AudioClip>(name));
				}
				GeoGrpFellDownTheStairs = ContentBundle.LoadPersistentAsset<AudioClip>("music_GeoGrpFellDownTheStairs");
				BouncingStrong = ContentBundle.LoadPersistentAsset<AudioClip>("music_BouncingStrong");
				LavaGangVictory = ContentBundle.LoadPersistentAsset<AudioClip>("sting_LavaGangVictory");
				SabrelakeVictory = ContentBundle.LoadPersistentAsset<AudioClip>("sting_sabrelakeVictory");
				LavaGangFailure = ContentBundle.LoadPersistentAsset<AudioClip>("sting_LavaGangFailure");
				SabrelakeFailure = ContentBundle.LoadPersistentAsset<AudioClip>("sting_sabrelakeFailure");
				DMTie = ContentBundle.LoadPersistentAsset<AudioClip>("sting_DMTie");
				BitGet = ContentBundle.LoadPersistentAsset<AudioClip>("stinger_BitGet");
				UISelect = ContentBundle.LoadPersistentAsset<AudioClip>("UI_Beep_Bend_Short_stereo");
				UIDeny = ContentBundle.LoadPersistentAsset<AudioClip>("UI_Error_Double_Note_Down_Notch_stereo");
				UIConfirm = ContentBundle.LoadPersistentAsset<AudioClip>("UI_SCI-FI_Confirm_Dry_stereo");
				UITurnOff = ContentBundle.LoadPersistentAsset<AudioClip>("UI_TurnOff");
				UITurnOn = ContentBundle.LoadPersistentAsset<AudioClip>("UI_TurnOn");
				PurchaseFailure = ContentBundle.LoadPersistentAsset<AudioClip>("stinger_FailPurchase");
				PurchaseSuccess = ContentBundle.LoadPersistentAsset<AudioClip>("stinger_SuccessPurchase");
				EquipItem = ContentBundle.LoadPersistentAsset<AudioClip>("ui_EquipItem");
				UnequipItem = ContentBundle.LoadPersistentAsset<AudioClip>("ui_UnequipItem");
				NotificationInformation = ContentBundle.LoadPersistentAsset<Texture2D>("notification_Information");
				NotificationWarning = ContentBundle.LoadPersistentAsset<Texture2D>("notification_Warning");
				NotificationError = ContentBundle.LoadPersistentAsset<Texture2D>("notification_Error");
				NotificationSuccess = ContentBundle.LoadPersistentAsset<Texture2D>("notification_Success");
				LaserCursor = ContentBundle.LoadPersistentAsset<GameObject>("laser_Cursor");
				LaserPulseSound = ContentBundle.LoadPersistentAsset<AudioClip>("laser_PulseSound");
				LaserRaySpawn = ContentBundle.LoadPersistentAsset<AudioClip>("laser_RaySpawn");
				LaserRayDespawn = ContentBundle.LoadPersistentAsset<AudioClip>("laser_RayDespawn");
				LaserPrismaticSFX = ContentBundle.LoadPersistentAsset<AudioClip>("laser_PrismaticSFX");
			}
			else
			{
				FusionLogger.Error("Content Bundle failed to load!");
			}
		}

		public static void OnBundleUnloaded()
		{
			if ((Object)(object)ContentBundle != (Object)null)
			{
				ContentBundle.Unload(true);
			}
		}
	}
	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 FusionDevTools
	{
		public static bool DespawnConstrainer(PlayerId id)
		{
			FusionPermissions.FetchPermissionLevel(id, out var level, out var _);
			if (!FusionPermissions.HasSufficientPermissions(level, FusionPreferences.ActiveServerSettings.ConstrainerAllowed.GetValue()))
			{
				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, FusionPreferences.ActiveServerSettings.DevToolsAllowed.GetValue()))
			{
				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, FusionPreferences.ActiveServerSettings.DevToolsAllowed.GetValue()))
			{
				return true;
			}
			return false;
		}
	}
	public static class FusionAudio
	{
		public static AudioSource Play2D(AudioClip clip, float volume = 1f)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			GameObject val = new GameObject("Fusion 2D Audio Source");
			AudioSource source = val.AddComponent<AudioSource>();
			source.volume = volume;
			source.clip = clip;
			source.spatialBlend = 0f;
			PersistentAssetCreator.HookOnSFXMixerLoaded(delegate(AudioMixerGroup m)
			{
				if ((Object)(object)source != (Object)null)
				{
					source.outputAudioMixerGroup = m;
				}
			});
			source.Play();
			return source;
		}

		public static AudioSource Play3D(Vector3 position, AudioClip clip, float volume = 1f, bool loop = false)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Fusion 3D Audio Source");
			AudioSource source = val.AddComponent<AudioSource>();
			val.transform.position = position;
			source.volume = volume;
			source.clip = clip;
			source.spatialBlend = 1f;
			source.loop = loop;
			PersistentAssetCreator.HookOnSFXMixerLoaded(delegate(AudioMixerGroup m)
			{
				if ((Object)(object)source != (Object)null)
				{
					source.outputAudioMixerGroup = m;
				}
			});
			source.Play();
			return source;
		}
	}
	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 Internal_OnAvatarChanged(RigManager rigManager, Avatar avatar, string barcode)
		{
			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.Internal && PlayerIdManager.LocalId != null && PlayerIdManager.LocalId.TryGetPermissionLevel(out level))
			{
				PermissionLevel value = FusionPreferences.ActiveServerSettings.CustomAvatarsAllowed.GetValue();
				if (!FusionPermissions.HasSufficientPermissions(level, value))
				{
					rigManager.SwapAvatarCrate("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.RigReferences.RigManager;
		}

		public static void SetAmmo(int count)
		{
			RigManager rigManager = RigData.RigReferences.RigManager;
			if (!((Object)(object)rigManager).IsNOC())
			{
				AmmoInventory ammoInventory = rigManager.AmmoInventory;
				ammoInventory.ClearAmmo();
				ammoInventory.AddCartridge(ammoInventory.lightAmmoGroup, count);
				ammoInventory.AddCartridge(ammoInventory.heavyAmmoGroup, count);
				ammoInventory.AddCartridge(ammoInventory.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.RigReferences.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(FusionPreferences.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.RigReferences.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()
		{
			if (!RigData.HasPlayer || !AssetWarehouse.ready || AvatarOverride == null || !((Object)(object)AssetWarehouse.Instance.GetCrate<AvatarCrate>(AvatarOverride) != (Object)null))
			{
				return;
			}
			RigManager rm = RigData.RigReferences.RigManager;
			rm.SwapAvatarCrate(AvatarOverride, true, Action<bool>.op_Implicit((Action<bool>)delegate(bool success)
			{
				if (!success)
				{
					rm.SwapAvatarCrate("c3534c5a-94b2-40a4-912a-24a8506f6c79", true, (Action<bool>)null);
				}
			}));
		}

		private static void Internal_ChangePlayerHealth()
		{
			if (RigData.HasPlayer)
			{
				RigManager rigManager = RigData.RigReferences.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 static class FusionPopupManager
	{
		internal static void OnInitializeMelon()
		{
			FusionAchievementPopup.OnInitializeMelon();
		}

		internal static void OnUpdate()
		{
			FusionNotifier.OnUpdate();
			FusionAchievementPopup.OnUpdate();
			FusionBitPopup.OnUpdate();
		}
	}
	public static class FusionSceneManager
	{
		private static Action _onTargetLevelLoad = null;

		private static Action _onLevelLoad = null;

		private static Action _onDelayedLevelLoad = null;

		private static bool _isLoading = false;

		private static bool _wasLoading = false;

		private static string _prevLevelBarcode = "NONE";

		public const float LEVEL_LOAD_WINDOW = 0.5f;

		private static bool _isDelayedLoading = false;

		private static float _loadingTimer = 0f;

		private static string _targetServerScene = null;

		private static bool _hasStartedLoadingTarget = false;

		private static bool _hasEnteredTargetLoadingScreen = false;

		public static LevelCrate Level => SceneStreamer.Session.Level;

		public static string Barcode
		{
			get
			{
				if (!((Object)(object)Level != (Object)null))
				{
					return "";
				}
				return Barcode.op_Implicit(((Scannable)Level).Barcode);
			}
		}

		public static string Title
		{
			get
			{
				if (!((Object)(object)Level != (Object)null))
				{
					return "";
				}
				return ((Scannable)Level).Title;
			}
		}

		internal static void Internal_OnInitializeMelon()
		{
			MultiplayerHooking.OnStartServer += Internal_OnCleanup;
			MultiplayerHooking.OnDisconnect += Internal_OnCleanup;
		}

		private static void Internal_OnCleanup()
		{
			_targetServerScene = null;
			_hasStartedLoadingTarget = false;
			_hasEnteredTargetLoadingScreen = false;
		}

		private static void Internal_SetServerScene(string barcode)
		{
			_targetServerScene = barcode;
			_hasStartedLoadingTarget = false;
			_hasEnteredTargetLoadingScreen = false;
		}

		private static void Internal_UpdateLoadStatus()
		{
			if (IsLoading_Internal())
			{
				_prevLevelBarcode = null;
				_isLoading = true;
				if (!_wasLoading)
				{
					LoadSender.SendLoadingState(isLoading: true);
					if (NetworkInfo.IsServer)
					{
						LoadSender.SendLevelLoad(Barcode);
					}
					MultiplayerHooking.Internal_OnLoadingBegin();
				}
			}
			else if (_prevLevelBarcode == null)
			{
				_isLoading = false;
				FusionMod.OnMainSceneInitialized();
				_prevLevelBarcode = Barcode;
				LoadSender.SendLoadingState(isLoading: false);
				_onLevelLoad?.Invoke();
				_onLevelLoad = null;
				if (HasTargetLoaded())
				{
					_onTargetLevelLoad?.Invoke();
					_onTargetLevelLoad = null;
				}
			}
			_wasLoading = _isLoading;
		}

		private static void Internal_UpdateDelayedLoadStatus()
		{
			if (_isLoading)
			{
				_loadingTimer = 0f;
				_isDelayedLoading = true;
			}
			else if (_loadingTimer <= 0.5f)
			{
				_loadingTimer += Time.deltaTime;
				_isDelayedLoading = true;
			}
			else if (_isDelayedLoading)
			{
				_isDelayedLoading = false;
				FusionMod.OnMainSceneInitializeDelayed();
				_onDelayedLevelLoad?.Invoke();
				_onDelayedLevelLoad = null;
			}
		}

		private static void Internal_UpdateTargetScene()
		{
			if (NetworkInfo.IsClient)
			{
				if (_hasStartedLoadingTarget && IsLoading())
				{
					_hasEnteredTargetLoadingScreen = true;
				}
				if (IsDelayedLoadDone() && !_hasStartedLoadingTarget && !string.IsNullOrEmpty(_targetServerScene))
				{
					SceneLoadPatch.IgnorePatches = true;
					SceneStreamer.Load(_targetServerScene, "");
					SceneLoadPatch.IgnorePatches = false;
					_hasStartedLoadingTarget = true;
				}
			}
		}

		internal static void Internal_UpdateScene()
		{
			Internal_UpdateLoadStatus();
			Internal_UpdateDelayedLoadStatus();
			Internal_UpdateTargetScene();
		}

		public static void SetTargetScene(string barcode)
		{
			Internal_SetServerScene(barcode);
		}

		public static void HookOnTargetLevelLoad(Action action)
		{
			if (!HasTargetLoaded())
			{
				_onTargetLevelLoad = (Action)Delegate.Combine(_onTargetLevelLoad, action);
			}
			else
			{
				action?.Invoke();
			}
		}

		public static void HookOnLevelLoad(Action action)
		{
			if (IsLoading())
			{
				_onLevelLoad = (Action)Delegate.Combine(_onLevelLoad, action);
			}
			else
			{
				action?.Invoke();
			}
		}

		public static void HookOnDelayedLevelLoad(Action action)
		{
			if (IsDelayedLoading())
			{
				_onDelayedLevelLoad = (Action)Delegate.Combine(_onDelayedLevelLoad, action);
			}
			else
			{
				action?.Invoke();
			}
		}

		public static bool HasLevel(string barcode)
		{
			if ((Object)(object)AssetWarehouse.Instance.GetCrate<LevelCrate>(barcode) != (Object)null)
			{
				return true;
			}
			return false;
		}

		public static bool IsLoading()
		{
			return _isLoading;
		}

		public static bool IsDelayedLoading()
		{
			return _isDelayedLoading;
		}

		public static bool IsLoadDone()
		{
			return !_isLoading;
		}

		public static bool IsDelayedLoadDone()
		{
			return !_isDelayedLoading;
		}

		public static bool HasTargetLoaded()
		{
			if (!NetworkInfo.HasServer || NetworkInfo.IsServer)
			{
				return IsLoadDone();
			}
			if (_hasStartedLoadingTarget && _hasEnteredTargetLoadingScreen)
			{
				return IsLoadDone();
			}
			return false;
		}

		private static bool IsLoading_Internal()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			return (int)SceneStreamer.Session.Status == 1;
		}
	}
	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_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)
			try
			{
				object[] array = new object[4];
				Scene scene = go.scene;
				array[0] = ((Scene)(ref scene)).name;
				array[1] = '¬';
				array[2] = ((Component)go.transform.root).gameObject.GetRootIndex();
				array[3] = go.transform.GetBasePath();
				return string.Format("{0}{1}{2}{3}", array);
			}
			catch
			{
			}
			return "INVALID_PATH";
		}

		public static GameObject GetGameObject(string path)
		{
			string[] array = path.Split(new char[1] { '¬' });
			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;
		}

		internal static async Task<List<GameObject>> FindRootsWithNameAsync(string scene, string name)
		{
			await Task.Delay(16);
			Scene sceneAsset = default(Scene);
			bool isFinished = false;
			ThreadingUtilities.RunSynchronously(delegate
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				sceneAsset = SceneManager.GetSceneByName(scene);
				isFinished = true;
			});
			while (!isFinished)
			{
				await Task.Delay(16);
			}
			ThreadingUtilities.IL2PrepareThread();
			List<GameObject> buffer = new List<GameObject>();
			isFinished = false;
			if (!((Scene)(ref sceneAsset)).IsValid())
			{
				return buffer;
			}
			ThreadingUtilities.RunSynchronously(delegate
			{
				buffer.Capacity = ((Scene)(ref sceneAsset)).rootCount;
				((Scene)(ref sceneAsset)).GetRootGameObjects(buffer);
				isFinished = true;
			});
			while (!isFinished)
			{
				await Task.Delay(16);
			}
			ThreadingUtilities.IL2PrepareThread();
			buffer.RemoveAll(Predicate<GameObject>.op_Implicit((Func<GameObject, bool>)((GameObject g) => ((Object)g).name != name)));
			return buffer;
		}

		internal static async Task<int> GetRootIndexAsync(this GameObject go)
		{
			await Task.Delay(16);
			ThreadingUtilities.IL2PrepareThread();
			Scene scene = go.scene;
			string name = ((Scene)(ref scene)).name;
			string name2 = ((Object)go).name;
			List<GameObject> obj = await FindRootsWithNameAsync(name, name2);
			ThreadingUtilities.IL2PrepareThread();
			return obj.FindIndex(Predicate<GameObject>.op_Implicit((Func<GameObject, bool>)((GameObject g) => (Object)(object)g == (Object)(object)go)));
		}

		internal static async Task<GameObject> GetRootByIndexAsync(string scene, int index, string name)
		{
			await Task.Delay(16);
			List<GameObject> val = await FindRootsWithNameAsync(scene, name);
			ThreadingUtilities.IL2PrepareThread();
			return (val == null || val.Count == 0) ? GameObject.Find("/" + name) : ((val.Count > index) ? val[index] : val[val.Count - 1]);
		}

		public static async Task<string> GetFullPathAsync(this GameObject go, Action<string> onComplete = null)
		{
			await Task.Delay(16);
			string path = null;
			ThreadingUtilities.IL2PrepareThread();
			try
			{
				Transform transform = go.transform;
				int num = await ((Component)transform.root).gameObject.GetRootIndexAsync();
				ThreadingUtilities.IL2PrepareThread();
				object[] array = new object[4];
				Scene scene = go.scene;
				array[0] = ((Scene)(ref scene)).name;
				array[1] = '¬';
				array[2] = num;
				array[3] = transform.GetBasePath();
				path = string.Format("{0}{1}{2}{3}", array);
			}
			catch
			{
			}
			if (onComplete != null)
			{
				ThreadingUtilities.RunSynchronously(delegate
				{
					onComplete(path);
				});
			}
			return path;
		}

		public static async Task<GameObject> GetGameObjectAsync(string path, Action<GameObject> onComplete = null)
		{
			await Task.Delay(16);
			string[] parts = path.Split(new char[1] { '¬' });
			string scene = parts[0];
			int index = int.Parse(parts[1]);
			string name = parts[2];
			ThreadingUtilities.IL2PrepareThread();
			GameObject result = null;
			try
			{
				GameObject val = await GetRootByIndexAsync(scene, index, name);
				ThreadingUtilities.IL2PrepareThread();
				if ((Object)(object)val != (Object)null)
				{
					Transform val2 = val.transform;
					for (int i = 3; i < parts.Length; i++)
					{
						val2 = val2.GetTransformByIndex(int.Parse(parts[i++]), parts[i]);
					}
					result = ((Component)val2).gameObject;
					if (onComplete != null)
					{
						ThreadingUtilities.RunSynchronously(delegate
						{
							onComplete(result);
						});
					}
				}
			}
			catch (Exception)
			{
			}
			return result;
		}
	}
	public static class ImpactUtilities
	{
		public static void OnHitRigidbody(Rigidbody rb)
		{
			GameObject go = ((Component)rb).gameObject;
			if (PropSyncable.HostCache.TryGet(go, out var value))
			{
				if (!value.IsHeld && !value.IsVehicle)
				{
					PropSender.SendOwnershipTransfer(value);
				}
			}
			else if (go.IsSyncWhitelisted())
			{
				DelayUtilities.Delay(delegate
				{
					PropSender.SendPropCreation(go);
				}, 4);
			}
		}
	}
	internal 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 AssetBundle LoadAssetBundle(string name)
		{
			if (HelperMethods.IsAndroid())
			{
				return EmbeddedAssetBundle.LoadFromAssembly(FusionMod.FusionAssembly, "LabFusion.Core.resources.bundles.Android." + name);
			}
			return EmbeddedAssetBundle.LoadFromAssembly(FusionMod.FusionAssembly, "LabFusion.Core.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 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<MenuCategory> onCreateCategory;
	}
	public static class FusionNotifier
	{
		public const float DefaultDuration = 2f;

		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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: 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}";
				MenuCategory category = BoneMenuCreator.NotificationCategory.CreateCategory(text, fusionNotification.title.color);
				((MenuElement)category).SetName(fusionNotification.title.text);
				_notificationNumber++;
				if (!string.IsNullOrWhiteSpace(fusionNotification.message.text))
				{
					category.CreateFunctionElement(fusionNotification.message.text, fusionNotification.message.color, (Action)null);
				}
				category.CreateFunctionElement("Mark as Read", Color.red, (Action)delegate
				{
					BoneMenuCreator.RemoveNotification((MenuElement)(object)category);
				});
				fusionNotification.onCreateCategory.InvokeSafe<Action<MenuCategory>, MenuCategory>(category, "executing Notification.OnCreateCategory");
			}
			RigManager rigManager = RigData.RigReferences.RigManager;
			if (fusionNotification.isPopup && !((Object)(object)rigManager).IsNOC())
			{
				HeadTitles headTitles = rigManager.tutorialRig.headTitles;
				EnableTutorialRig();
				string text2 = "New Notification";
				if (fusionNotification.showTitleOnPopup)
				{
					text2 = fusionNotification.title.text;
				}
				string text3 = fusionNotification.message.text;
				Texture2D val = (Texture2D)(fusionNotification.type switch
				{
					NotificationType.WARNING => FusionContentLoader.NotificationWarning, 
					NotificationType.ERROR => FusionContentLoader.NotificationError, 
					NotificationType.SUCCESS => FusionContentLoader.NotificationSuccess, 
					_ => FusionContentLoader.NotificationInformation, 
				});
				Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
				float popupLength = fusionNotification.popupLength;
				headTitles.CUSTOMDISPLAY(text2, text3, val2, popupLength, (AudioClip)null, false, (Sprite)null, (Sprite)null, (Sprite)null, (Sprite)null);
				headTitles.sr_element.sprite = val2;
			}
		}

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

		internal static bool IsPlayingNotification()
		{
			RigManager rigManager = RigData.RigReferences.RigManager;
			if (!((Object)(object)rigManager).IsNOC())
			{
				return ((Component)rigManager.tutorialRig.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;
			}
		}
	}
	internal static class NativeUtilities
	{
		internal unsafe static IntPtr GetNativePtr<T>(string name)
		{
			return *(IntPtr*)(void*)(IntPtr)typeof(T).GetField(name, AccessTools.all).GetValue(null);
		}

		internal static IntPtr GetDestPtr<TDelegate>(TDelegate destination) where TDelegate : Delegate
		{
			return destination.Method.MethodHandle.GetFunctionPointer();
		}

		internal static TDelegate GetOriginal<TDelegate>(IntPtr nativePtr)
		{
			return Marshal.GetDelegateForFunctionPointer<TDelegate>(nativePtr);
		}
	}
	internal class PooleePusher
	{
		private readonly List<AssetPoolee> _list = new List<AssetPoolee>();

		public void Push(AssetPoolee poolee)
		{
			if (!((IEnumerable<AssetPoolee>)_list).Has<AssetPoolee>(poolee))
			{
				_list.Add(poolee);
			}
		}

		public bool Pull(AssetPoolee poolee)
		{
			for (int i = 0; i < _list.Count; i++)
			{
				if ((Object)(object)_list[i] == (Object)(object)poolee)
				{
					_list.RemoveAt(i);
					return true;
				}
			}
			return false;
		}

		public bool Contains(AssetPoolee poolee)
		{
			for (int i = 0; i < _list.Count; i++)
			{
				if ((Object)(object)_list[i] == (Object)(object)poolee)
				{
					return true;
				}
			}
			return false;
		}
	}
	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);
				}
			}
		}
	}
	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 RigManagerEvent(RigManager rig);
	public delegate void CatchupAction(ulong longId);
	public delegate void LobbyMenuAction(MenuCategory category, 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 CatchupAction OnPlayerCatchup;

		public static event LobbyMenuAction OnLobbyCategoryCreated;

		public static event RigManagerEvent OnLocalPlayerCreated;

		public static event RigManagerEvent OnPlayerRepCreated;

		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(ulong longId)
		{
			MultiplayerHooking.OnPlayerCatchup.InvokeSafe(longId, "executing OnPlayerCatchup hook");
		}

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

		internal static void Internal_OnLocalPlayerCreated(RigManager rig)
		{
			MultiplayerHooking.OnLocalPlayerCreated.InvokeSafe<RigManagerEvent, RigManager>(rig, "executing OnLocalPlayerCreated hook");
		}

		internal static void Internal_OnPlayerRepCreated(RigManager rig)
		{
			MultiplayerHooking.OnPlayerRepCreated.InvokeSafe<RigManagerEvent, RigManager>(rig, "executing OnPlayerRepCreated hook");
		}

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

		internal static void Internal_OnUpdate()
		{
			MultiplayerHooking.OnUpdate.InvokeSafe("executing OnUpdate hook");
		}

		internal static void Internal_OnFixedUpdate()
		{
			MultiplayerHooking.OnFixedUpdate.InvokeSafe("executing OnFixedUpdate hook");
		}

		internal static void Internal_OnLateUpdate()
		{
			MultiplayerHooking.OnLateUpdate.InvokeSafe("executing OnLateUpdate hook");
		}

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

		internal static void Internal_OnLoadingBegin()
		{
			MultiplayerHooking.OnLoadingBegin.InvokeSafe("executing OnLoadingBegin hook");
		}
	}
	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 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);
		}
	}
	internal static class PersistentAssetCreator
	{
		private const string _targetFont = "arlon-medium";

		private static Action<AudioMixerGroup> _onMusicMixerLoaded;

		private static Action<AudioMixerGroup> _onSFXMixerLoaded;

		private static Action<HandPose> _onSoftGrabLoaded;

		internal static SurfaceData BloodSurfaceData { get; private set; }

		internal static TMP_FontAsset Font { get; private set; }

		internal static HandPose SoftGrabPose { get; private set; }

		internal static AudioMixerGroup MusicMixer { get; private set; }

		internal static AudioMixerGroup SFXMixer { get; private set; }

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

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

		private static void GetAllMixers()
		{
			if ((Object)(object)SFXMixer != (Object)null && (Object)(object)MusicMixer != (Object)null)
			{
				return;
			}
			AudioMixerGroup[] array = Il2CppArrayBase<AudioMixerGroup>.op_Implicit(Resources.FindObjectsOfTypeAll<AudioMixerGroup>());
			foreach (AudioMixerGroup val in array)
			{
				string name = ((Object)val).name;
				if (!(name == "Music"))
				{
					if (name == "SFX")
					{
						SFXMixer = val;
					}
				}
				else
				{
					MusicMixer = val;
				}
			}
			if ((Object)(object)MusicMixer != (Object)null)
			{
				_onMusicMixerLoaded?.Invoke(MusicMixer);
			}
			if ((Object)(object)SFXMixer != (Object)null)
			{
				_onSFXMixerLoaded?.Invoke(SFXMixer);
			}
			_onMusicMixerLoaded = null;
			_onSFXMixerLoaded = null;
		}

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

		public static void HookOnMusicMixerLoaded(Action<AudioMixerGroup> action)
		{
			if ((Object)(object)MusicMixer != (Object)null)
			{
				action?.Invoke(MusicMixer);
			}
			else
			{
				_onMusicMixerLoaded = (Action<AudioMixerGroup>)Delegate.Combine(_onMusicMixerLoaded, action);
			}
		}

		public static void HookOnSFXMixerLoaded(Action<AudioMixerGroup> action)
		{
			if ((Object)(object)SFXMixer != (Object)null)
			{
				action?.Invoke(SFXMixer);
			}
			else
			{
				_onSFXMixerLoaded = (Action<AudioMixerGroup>)Delegate.Combine(_onSFXMixerLoaded, action);
			}
		}

		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];
			}
		}

		private static void CreateSurfaceData()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			BloodSurfaceData = ScriptableObject.CreateInstance<SurfaceData>();
			((Object)BloodSurfaceData).name = "Fusion Blood Surface";
			BloodSurfaceData.PenetrationResistance = 0.59f;
			BloodSurfaceData.megaPascal = 4f;
			BloodSurfaceData.isFlammable = false;
			BloodSurfaceData.fireResistance = 0f;
			BloodSurfaceData.ParicleColorTint = new Color(0.1686275f, 0.003372546f, 0.003372546f, 1f);
			PhysicMaterial physicMaterial = new PhysicMaterial("Fusion Physic Material")
			{
				dynamicFriction = 0.45f,
				staticFriction = 0.63f,
				bounciness = 0.35f,
				frictionCombine = (PhysicMaterialCombine)1,
				bounceCombine = (PhysicMaterialCombine)1
			};
			BloodSurfaceData.physicMaterial = physicMaterial;
		}

		internal static void SetupImpactProperties(RigManager rig)
		{
			PhysicsRig physicsRig = rig.physicsRig;
			Il2CppArrayBase<Rigidbody> componentsInChildren = ((Component)physicsRig).GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				GameObject gameObject = ((Component)componentsInChildren[i]).gameObject;
				if (!((Object)(object)gameObject == (Object)(object)physicsRig.knee) && !((Object)(object)gameObject == (Object)(object)physicsRig.feet))
				{
					if (i == 0)
					{
						ImpactPropertiesManager obj = gameObject.AddComponent<ImpactPropertiesManager>();
						((ImpactPropertiesVariables)obj).surfaceData = BloodSurfaceData;
						((ImpactPropertiesVariables)obj).DecalMeshObj = null;
						((ImpactPropertiesVariables)obj).decalType = (DecalType)2;
					}
					ImpactProperties obj2 = gameObject.AddComponent<ImpactProperties>();
					((ImpactPropertiesVariables)obj2).surfaceData = BloodSurfaceData;
					((ImpactPropertiesVariables)obj2).DecalMeshObj = null;
					((ImpactPropertiesVariables)obj2).decalType = (DecalType)2;
				}
			}
		}
	}
	internal static class PhysicsUtilities
	{
		internal static bool CanModifyGravity;

		public static Vector3 Gravity;

		internal static void OnCacheValues()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Gravity = Physics.gravity;
		}

		internal static void OnUpdateTimescale()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkInfo.HasServer)
			{
				return;
			}
			TimeScaleMode timeScaleMode = FusionPreferences.TimeScaleMode;
			RigReferenceCollection rigReferences = RigData.RigReferences;
			RigManager rigManager = rigReferences.RigManager;
			switch (timeScaleMode)
			{
			case TimeScaleMode.DISABLED:
				Time.timeScale = 1f;
				break;
			case TimeScaleMode.LOW_GRAVITY:
			{
				Time.timeScale = 1f;
				if (!RigData.HasPlayer)
				{
					break;
				}
				Control_GlobalTime globalTimeControl = rigManager.openControllerRig.globalTimeControl;
				if (globalTimeControl.cur_intensity <= 0f)
				{
					break;
				}
				float num = 1f - 1f / globalTimeControl.cur_intensity;
				Vector3 val = -Gravity * num;
				if (rigReferences.RigRigidbodies == null)
				{
					rigReferences.GetRigidbodies();
				}
				Rigidbody[] rigRigidbodies = rigReferences.RigRigidbodies;
				foreach (Rigidbody val2 in rigRigidbodies)
				{
					if (!((Object)(object)val2 == (Object)null) && val2.useGravity)
					{
						val2.AddForce(val, (ForceMode)5);
					}
				}
				break;
			}
			}
		}

		internal static void OnSendPhysicsInformation()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (Time.frameCount % 40 != 0 || !NetworkInfo.IsServer)
			{
				return;
			}
			using FusionWriter fusionWriter = FusionWriter.Create(12);
			using WorldGravityMessageData value = WorldGravityMessageData.Create(Gravity);
			fusionWriter.Write(value);
			using LabFusion.Network.FusionMessage message = LabFusion.Network.FusionMessage.Create(NativeMessageTag.WorldGravity, fusionWriter);
			MessageSender.BroadcastMessageExceptSelf(NetworkChannel.Unreliable, message);
		}
	}
	internal static class StaticGripFixer
	{
		internal static void OnMainSceneInitialized()
		{
			foreach (AmmoDispenser item in Object.FindObjectsOfType<AmmoDispenser>())
			{
				((Component)item).gameObject.AddComponent<InteractableHost>();
			}
		}
	}
	public static class MuteUIHelper
	{
		private static PageItem _mutePage;

		private static GameObject _muteIcon;

		private static Renderer _muteRenderer;

		private static Camera _muteCamera;

		public static void OnInitializeMelon()
		{
			FusionPref<bool> muted = FusionPreferences.ClientSettings.Muted;
			muted.OnValueChanged = (Action<bool>)Delegate.Combine(muted.OnValueChanged, new Action<bool>(OnMutedChanged));
			FusionPref<bool> mutedIndicator = FusionPreferences.ClientSettings.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 = FusionPreferences.ClientSettings.Muted;
			muted.OnValueChanged = (Action<bool>)Delegate.Remove(muted.OnValueChanged, new Action<bool>(OnMutedChanged));
			FusionPref<bool> mutedIndicator = FusionPreferences.ClientSettings.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)_muteCamera && (Object)(object)_muteRenderer != (Object)null)
			{
				_muteRenderer.enabled = true;
			}
		}

		private static void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
		{
			if ((Object)(object)camera == (Object)(object)_muteCamera && (Object)(object)_muteRenderer != (Object)null)
			{
				_muteRenderer.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)_muteIcon != (Object)null)
			{
				_muteIcon.SetActive(VoiceHelper.ShowIndicator);
			}
		}

		public static void OnCreateMuteUI(RigManager manager)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if (VoiceHelper.CanTalk)
			{
				PopUpMenuView popUpMenu = manager.uiRig.popUpMenu;
				Page homePage = popUpMenu.radialPageView.m_HomePage;
				FusionPref<bool> mutedPref = FusionPreferences.ClientSettings.Muted;
				_mutePage = new PageItem(mutedPref.GetValue() ? "Quick Unmute" : "Quick Mute", (Directions)3, Action.op_Implicit((Action)delegate
				{
					mutedPref.SetValue(!mutedPref.GetValue());
					popUpMenu.Deactivate();
					FusionNotifier.Send(new FusionNotification
					{
						isPopup = true,
						isMenuItem = false,
						message = (mutedPref.GetValue() ? "Muted" : "Unmuted")
					});
				}));
				homePage.items.Add(_mutePage);
				Transform head = ((Rig)manager.openControllerRig).m_head;
				_muteIcon = Object.Instantiate<GameObject>(FusionContentLoader.MutePopupPrefab, head);
				((Object)_muteIcon).name = "Mute Icon [FUSION]";
				_muteRenderer = _muteIcon.GetComponentInChildren<Renderer>();
				_muteRenderer.enabled = false;
				_muteCamera = _muteIcon.GetComponent<Camera>();
				((Component)head).GetComponent<UniversalAdditionalCameraData>().cameraStack.Add(_muteCamera);
				_muteIcon.SetActive(VoiceHelper.ShowIndicator);
			}
		}

		public static void OnDestroyMuteUI(RigManager manager)
		{
			if (_mutePage != null)
			{
				PopUpMenuView popUpMenu = manager.uiRig.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)_muteIcon).IsNOC())
			{
				Object.Destroy((Object)(object)_muteIcon);
				_muteIcon = null;
			}
		}
	}
	public static class LaserCursorUtilities
	{
		public static LaserCursor CreateLaserCursor(Action<LaserCursor> onSetupRegions = null)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			GameObject obj = Object.Instantiate<GameObject>(FusionContentLoader.LaserCursor);
			Transform transform = obj.transform;
			obj.SetActive(false);
			LaserCursor val = obj.AddComponent<LaserCursor>();
			PageElementView val2 = transform.Find("Arrow").SetupPageElementView();
			PageElementView val3 = transform.Find("ray_start").SetupPageElementView();
			PageElementView val4 = transform.Find("ray_mid").SetupPageElementView();
			PageElementView val5 = transform.Find("ray_mid2").SetupPageElementView();
			PageElementView val6 = transform.Find("ray_bez").SetupPageElementView();
			PageElementView val7 = transform.Find("ray_end").SetupPageElementView();
			PageElementView rayPulse = transform.Find("ray_pulse").SetupPageElementView();
			PageElementView val8 = transform.Find("SFX").SetupPageElementView();
			AnimationCurve blipCurve = (val5.blipCurve = (val4.blipCurve = (val3.blipCurve = new AnimationCurve(Il2CppStructArray<Keyframe>.op_Implicit((Keyframe[])(object)new Keyframe[4]
			{
				new Keyframe(0f, 1f),
				new Keyframe(0.1271991f, 1.953225f),
				new Keyframe(0.724905f, 0.9818711f),
				new Keyframe(1f, 1f)
			})))));
			val7.blipCurve = blipCurve;
			DrawBezierCurve val12 = ((Component)val2).gameObject.AddComponent<DrawBezierCurve>();
			val12.Point1 = ((Component)val7).gameObject;
			val12.Point2 = ((Component)val6).gameObject;
			val12.Point3 = ((Component)val4).gameObject;
			val12.Point4 = ((Component)val3).gameObject;
			val12.lineSteps = 12;
			val12.linePercentageFill = 0.73f;
			PrismaticSFX val13 = ((Component)val8).gameObject.AddComponent<PrismaticSFX>();
			val13.velocityTran = ((Component)val8).transform;
			val13.sourceTran = ((Component)val8).transform;
			val13.minSpeed = 0.2f;
			val13.maxSpeed = 4f;
			val13.sourceMinDistance = 1f;
			val13.pitchMod = 1f;
			val13.enableModulatedAudio = true;
			val13.loopClips = true;
			val13.modulatedClips = Il2CppReferenceArray<AudioClip>.op_Implicit((AudioClip[])(object)new AudioClip[1] { FusionContentLoader.LaserPrismaticSFX });
			val13.SpatialBlend = 0.98f;
			val.cursorStart = val3;
			val.cursorEnd = val7;
			val.cursorMid = val4;
			val.cursorMid2 = val5;
			val.cursorBez = val6;
			val.rayPulse = rayPulse;
			val.lineEnd = val2;
			val.cursorLine = ((Component)val2).GetComponent<LineRenderer>();
			val.bezCurve = val12;
			val.pulseLength = 0.2f;
			val.pulseAceleration = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
			val.pulseSound = Il2CppReferenceArray<AudioClip>.op_Implicit((AudioClip[])(object)new AudioClip[1] { FusionContentLoader.LaserPulseSound });
			val.raySpawn = Il2CppReferenceArray<AudioClip>.op_Implicit((AudioClip[])(object)new AudioClip[1] { FusionContentLoader.LaserRaySpawn });
			val.rayDespawn = Il2CppReferenceArray<AudioClip>.op