Decompiled source of LocalMultiXtras v1.1.0

LocalMultiXtras.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using MasterSlaveInput;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.TextCore;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LocalMultiXtras")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LocalMultiXtras")]
[assembly: AssemblyTitle("LocalMultiXtras")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
public class UIManager : MonoBehaviour
{
	[CompilerGenerated]
	private sealed class <FindAndApplyGameAssets>d__4 : IEnumerator<object>, IEnumerator, IDisposable
	{
		private int <>1__state;

		private object <>2__current;

		public UIManager <>4__this;

		private TMP_FontAsset <gameFont>5__1;

		private Material <outlineMaterial>5__2;

		object? IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object? IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <FindAndApplyGameAssets>d__4(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<gameFont>5__1 = null;
			<outlineMaterial>5__2 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(1f);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<gameFont>5__1 = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)delegate(TMP_FontAsset a)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					FaceInfo faceInfo = ((TMP_Asset)a).faceInfo;
					return ((FaceInfo)(ref faceInfo)).familyName == "Daruma Drop One";
				});
				if ((Object)(object)<gameFont>5__1 != (Object)null && (Object)(object)<>4__this._uiText != (Object)null)
				{
					((TMP_Text)<>4__this._uiText).font = <gameFont>5__1;
				}
				<outlineMaterial>5__2 = ((IEnumerable<Material>)Resources.FindObjectsOfTypeAll<Material>()).FirstOrDefault((Func<Material, bool>)((Material m) => ((Object)m).name.IndexOf("Daruma", StringComparison.OrdinalIgnoreCase) >= 0 && ((Object)m).name.IndexOf("Outline", StringComparison.OrdinalIgnoreCase) >= 0));
				if ((Object)(object)<outlineMaterial>5__2 != (Object)null && (Object)(object)<>4__this._uiText != (Object)null)
				{
					((TMP_Text)<>4__this._uiText).fontMaterial = <outlineMaterial>5__2;
					((TMP_Text)<>4__this._uiText).outlineWidth = 0.1f;
					((TMP_Text)<>4__this._uiText).outlineColor = Color32.op_Implicit(Color.black);
				}
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private TextMeshProUGUI? _uiText;

	private Canvas? _canvas;

	private void Awake()
	{
		if (!ConfigManager.EnableUI.Value)
		{
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}
	}

	private void Start()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Expected O, but got Unknown
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("MSI_Canvas");
		_canvas = val.AddComponent<Canvas>();
		_canvas.renderMode = (RenderMode)0;
		_canvas.sortingOrder = 100;
		Object.DontDestroyOnLoad((Object)(object)val);
		GameObject val2 = new GameObject("MSI_Text");
		val2.transform.SetParent(((Component)_canvas).transform);
		_uiText = val2.AddComponent<TextMeshProUGUI>();
		((TMP_Text)_uiText).fontSize = ConfigManager.FontSize.Value;
		((TMP_Text)_uiText).alignment = (TextAlignmentOptions)257;
		RectTransform rectTransform = ((TMP_Text)_uiText).rectTransform;
		rectTransform.anchorMin = new Vector2(0f, 1f);
		rectTransform.anchorMax = new Vector2(0f, 1f);
		rectTransform.pivot = new Vector2(0f, 1f);
		rectTransform.anchoredPosition = new Vector2(15f, -15f);
		rectTransform.sizeDelta = new Vector2(600f, 400f);
		((MonoBehaviour)this).StartCoroutine(FindAndApplyGameAssets());
	}

	[IteratorStateMachine(typeof(<FindAndApplyGameAssets>d__4))]
	private IEnumerator FindAndApplyGameAssets()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <FindAndApplyGameAssets>d__4(0)
		{
			<>4__this = this
		};
	}

	private void Update()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_canvas == (Object)null || (Object)(object)_uiText == (Object)null)
		{
			return;
		}
		if (Input.GetKeyDown(ConfigManager.ToggleUIKey.Value))
		{
			((Component)_canvas).gameObject.SetActive(!((Component)_canvas).gameObject.activeSelf);
		}
		if (!((Component)_canvas).gameObject.activeSelf)
		{
			return;
		}
		if (!PhotonNetwork.InRoom)
		{
			((TMP_Text)_uiText).text = "";
			return;
		}
		StringBuilder stringBuilder = new StringBuilder();
		if (PhotonNetwork.IsMasterClient)
		{
			string arg = (InputBroadcaster.IsBroadcasting ? "<color=green>ACTIVE</color>" : "<color=red>PAUSED</color>");
			stringBuilder.AppendLine($"[MASTER] Broadcasting: {arg} ({ConfigManager.BroadcastToggleKey.Value})");
			stringBuilder.AppendLine($"Toggle Control: {ConfigManager.ModifierKey.Value}+[2-9]");
			stringBuilder.AppendLine("--------------------");
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				string arg2 = (val.IsMasterClient ? "<color=white>[HOST]</color>" : ((InputBroadcaster.SlavePausedStates.ContainsKey(val.ActorNumber) && InputBroadcaster.SlavePausedStates[val.ActorNumber]) ? "<color=red>[PAUSED]</color>" : "<color=green>[ACTIVE]</color>"));
				stringBuilder.AppendLine($"  {val.ActorNumber}: {val.NickName} {arg2}");
			}
		}
		else
		{
			string text = (InputPatches.IsSlaveControlPaused ? "<color=red>PAUSED</color>" : "<color=green>ACTIVE</color>");
			stringBuilder.AppendLine("[INSTANCE] Master Control: " + text);
		}
		((TMP_Text)_uiText).text = stringBuilder.ToString();
	}
}
namespace MasterSlaveInput
{
	public static class ConfigManager
	{
		public static ConfigFile Config { get; private set; }

		public static ConfigEntry<KeyCode> ModifierKey { get; private set; }

		public static ConfigEntry<KeyCode> MasterPauseKey { get; private set; }

		public static ConfigEntry<bool> AutoJoinOnLaunch { get; private set; }

		public static ConfigEntry<bool> EnableUI { get; private set; }

		public static ConfigEntry<KeyCode> ToggleUIKey { get; private set; }

		public static ConfigEntry<int> FontSize { get; private set; }

		public static ConfigEntry<bool> AutoRenameInstances { get; private set; }

		public static ConfigEntry<string> SyncedInputs { get; private set; }

		public static ConfigEntry<KeyCode> BroadcastToggleKey { get; private set; }

		public static void Initialize(ConfigFile config)
		{
			Config = config;
			ModifierKey = Config.Bind<KeyCode>("1. Key Binds", "ModifierKey", (KeyCode)304, "The key to hold to use number keys to toggle instance control.");
			ToggleUIKey = Config.Bind<KeyCode>("1. Key Binds", "ToggleUIKey", (KeyCode)289, "The key to press to show or hide the UI in-game.");
			MasterPauseKey = Config.Bind<KeyCode>("1. Key Binds", "MasterPauseKey", (KeyCode)290, "On the master instance, this key pauses control of the character while still broadcasting input to instances.");
			BroadcastToggleKey = Config.Bind<KeyCode>("1. Key Binds", "BroadcastToggleKey", (KeyCode)291, "On the master instance, this key toggles input broadcasting on and off for all instances.");
			EnableUI = Config.Bind<bool>("2. UI", "EnableUI", true, "Enable the master/instances status UI.");
			FontSize = Config.Bind<int>("2. UI", "FontSize", 12, "The font size of the UI text.");
			AutoRenameInstances = Config.Bind<bool>("3. Instances", "AutoRenameInstances", true, "If enabled, all instances will be automatically renamed to 'Instance #X'.");
			AutoJoinOnLaunch = Config.Bind<bool>("3. Instances", "AutoJoin", true, "If enabled, all instances will automatically try to join the host's lobby.");
			SyncedInputs = Config.Bind<string>("4. Syncing", "SyncedInputs", "movementInput, lookInput, jumpWasPressed, sprintIsPressed, interactWasPressed, interactIsPressed, dropWasPressed, usePrimaryWasPressed, usePrimaryIsPressed, useSecondaryWasPressed, useSecondaryIsPressed, crouchIsPressed, crouchWasPressed, emoteIsPressed", "A comma-separated list of the field names from the CharacterInput class to synchronize. Add or remove fields to customize what is controlled.\nAcceptable values: movementInput, sprintWasPressed, sprintIsPressed, sprintToggleIsPressed, sprintToggleWasPressed, jumpWasPressed, jumpIsPressed, dropWasPressed, dropIsPressed, dropWasReleased, scrollInput, lookInput, usePrimaryWasPressed, usePrimaryIsPressed, usePrimaryWasReleased, useSecondaryWasPressed, useSecondaryIsPressed, useSecondaryWasReleased, crouchWasPressed, crouchIsPressed, crouchToggleWasPressed, scrolledUp, scrolledDown, pauseWasPressed, interactWasPressed, interactIsPressed, interactWasReleased, emoteIsPressed, spectateLeftWasPressed, spectateRightWasPressed, selectBackpackWasPressed, scrollButtonLeftWasPressed, scrollButtonRightWasPressed, pingWasPressed, pushToTalkPressed, unselectSlotWasPressed, selectSlotForwardWasPressed, selectSlotBackwardWasPressed, unselectSlotWasPressed");
		}
	}
	public class InputBroadcaster : MonoBehaviourPunCallbacks
	{
		public static readonly Dictionary<string, object> SyncedInputData = new Dictionary<string, object>();

		private static readonly List<FieldInfo> _fieldsToSync = new List<FieldInfo>();

		private CharacterInput? m_characterInput;

		private bool _isInitialized = false;

		public static bool IsBroadcasting = true;

		public static bool IsMasterPaused = false;

		public static readonly Dictionary<int, bool> SlavePausedStates = new Dictionary<int, bool>();

		public static void InitializeSyncFields()
		{
			string[] array = ConfigManager.SyncedInputs.Value.Split(',');
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.Trim();
				if (!string.IsNullOrEmpty(text2))
				{
					FieldInfo field = typeof(CharacterInput).GetField(text2, BindingFlags.Instance | BindingFlags.Public);
					if (field != null)
					{
						_fieldsToSync.Add(field);
					}
					else
					{
						Debug.LogWarning((object)("[LocalMultiXtras] Configured input field '" + text2 + "' not found and will be ignored."));
					}
				}
			}
			Debug.Log((object)$"[LocalMultiXtras] Initialized with {_fieldsToSync.Count} fields to synchronize.");
		}

		[PunRPC]
		public void SetControlPaused(bool isPaused)
		{
			InputPatches.IsSlaveControlPaused = isPaused;
		}

		private void Update()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			if (!_isInitialized)
			{
				if (((MonoBehaviourPun)this).photonView.IsMine && (Object)(object)Player.localPlayer != (Object)null && (Object)(object)Player.localPlayer.character != (Object)null)
				{
					m_characterInput = ((Component)Player.localPlayer.character).GetComponent<CharacterInput>();
					if ((Object)(object)m_characterInput != (Object)null)
					{
						_isInitialized = true;
						if (!PhotonNetwork.IsMasterClient && ConfigManager.AutoRenameInstances.Value)
						{
							PhotonNetwork.NickName = $"Instance {PhotonNetwork.LocalPlayer.ActorNumber}";
						}
					}
				}
				else if (!((MonoBehaviourPun)this).photonView.IsMine)
				{
					_isInitialized = true;
				}
			}
			else if (PhotonNetwork.IsMasterClient && ((MonoBehaviourPun)this).photonView.IsMine)
			{
				if (Input.GetKeyDown(ConfigManager.MasterPauseKey.Value))
				{
					IsMasterPaused = !IsMasterPaused;
				}
				if (Input.GetKeyDown(ConfigManager.BroadcastToggleKey.Value))
				{
					IsBroadcasting = !IsBroadcasting;
				}
				HandleMasterToggles();
			}
		}

		private void HandleMasterToggles()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (!Input.GetKey(ConfigManager.ModifierKey.Value))
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)48))
			{
				SlavePausedStates.Clear();
				((MonoBehaviourPun)this).photonView.RPC("SetControlPaused", (RpcTarget)1, new object[1] { false });
				return;
			}
			for (int i = 1; i < 10; i++)
			{
				if (Input.GetKeyDown((KeyCode)(48 + i)))
				{
					int num = i - 1;
					if (num >= PhotonNetwork.PlayerList.Length)
					{
						break;
					}
					Player val = PhotonNetwork.PlayerList[num];
					if (!val.IsMasterClient)
					{
						int actorNumber = val.ActorNumber;
						bool flag = SlavePausedStates.ContainsKey(actorNumber) && SlavePausedStates[actorNumber];
						bool flag2 = !flag;
						SlavePausedStates[actorNumber] = flag2;
						((MonoBehaviourPun)this).photonView.RPC("SetControlPaused", val, new object[1] { flag2 });
						break;
					}
				}
			}
		}

		[PunRPC]
		public void ReceiveInput(byte[] inputData)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				DeserializeAndStoreInputs(inputData);
			}
		}

		public void BroadcastInputs(CharacterInput source)
		{
			if (IsBroadcasting)
			{
				byte[] array = SerializeInputs(source);
				((MonoBehaviourPun)this).photonView.RPC("ReceiveInput", (RpcTarget)1, new object[1] { array });
			}
		}

		private byte[] SerializeInputs(CharacterInput input)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
			{
				foreach (FieldInfo item in _fieldsToSync)
				{
					object value = item.GetValue(input);
					if (item.FieldType == typeof(bool))
					{
						binaryWriter.Write((bool)value);
					}
					else if (item.FieldType == typeof(float))
					{
						binaryWriter.Write((float)value);
					}
					else if (item.FieldType == typeof(Vector2))
					{
						Vector2 val = (Vector2)value;
						binaryWriter.Write(val.x);
						binaryWriter.Write(val.y);
					}
				}
			}
			return memoryStream.ToArray();
		}

		public static void DeserializeAndStoreInputs(byte[] inputData)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (inputData == null || inputData.Length == 0)
			{
				return;
			}
			using MemoryStream input = new MemoryStream(inputData);
			using BinaryReader binaryReader = new BinaryReader(input);
			try
			{
				foreach (FieldInfo item in _fieldsToSync)
				{
					object value;
					if (item.FieldType == typeof(bool))
					{
						value = binaryReader.ReadBoolean();
					}
					else if (item.FieldType == typeof(float))
					{
						value = binaryReader.ReadSingle();
					}
					else
					{
						if (!(item.FieldType == typeof(Vector2)))
						{
							continue;
						}
						value = (object)new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
					}
					SyncedInputData[item.Name] = value;
				}
			}
			catch (EndOfStreamException)
			{
			}
		}
	}
	[HarmonyPatch]
	internal static class InputPatches
	{
		private static MethodInfo? _resetInputMethod;

		public static bool IsSlaveControlPaused;

		private static MethodInfo? _assignSpoofAccountMethod;

		private static bool _hasAttemptedAutoJoin;

		[HarmonyPatch(typeof(Player), "Awake")]
		[HarmonyPostfix]
		private static void AddInputBroadcaster(Player __instance)
		{
			if ((Object)(object)((Component)__instance).gameObject.GetComponent<InputBroadcaster>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<InputBroadcaster>();
			}
		}

		[HarmonyPatch(typeof(CharacterInput), "Sample")]
		[HarmonyPrefix]
		private static bool Prefix_HandleSlaveInput(CharacterInput __instance)
		{
			if (!PhotonNetwork.IsMasterClient && !IsSlaveControlPaused && (Object)(object)Player.localPlayer != (Object)null && (Object)(object)Player.localPlayer.character != (Object)null && (Object)(object)((Component)Player.localPlayer.character).GetComponent<CharacterInput>() == (Object)(object)__instance)
			{
				if (_resetInputMethod == null)
				{
					_resetInputMethod = typeof(CharacterInput).GetMethod("ResetInput", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				_resetInputMethod?.Invoke(__instance, null);
				foreach (KeyValuePair<string, object> syncedInputDatum in InputBroadcaster.SyncedInputData)
				{
					typeof(CharacterInput).GetField(syncedInputDatum.Key)?.SetValue(__instance, syncedInputDatum.Value);
				}
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(CharacterInput), "Sample")]
		[HarmonyPostfix]
		private static void Postfix_HandleMasterLogic(CharacterInput __instance)
		{
			if (!PhotonNetwork.IsMasterClient || !((Object)(object)Player.localPlayer != (Object)null) || !((Object)(object)Player.localPlayer.character != (Object)null) || !((Object)(object)((Component)Player.localPlayer.character).GetComponent<CharacterInput>() == (Object)(object)__instance))
			{
				return;
			}
			InputBroadcaster component = ((Component)Player.localPlayer).GetComponent<InputBroadcaster>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			component.BroadcastInputs(__instance);
			if (InputBroadcaster.IsMasterPaused)
			{
				if (_resetInputMethod == null)
				{
					_resetInputMethod = typeof(CharacterInput).GetMethod("ResetInput", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				_resetInputMethod?.Invoke(__instance, null);
			}
		}

		[HarmonyPatch(typeof(MainMenu), "Initialize")]
		[HarmonyPostfix]
		private static void ResetAutoJoinFlag()
		{
			_hasAttemptedAutoJoin = false;
		}

		[HarmonyPatch(typeof(MainMenu), "Update")]
		[HarmonyPostfix]
		private static void AutoJoinSlaveInstance()
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if (_hasAttemptedAutoJoin || !ConfigManager.AutoJoinOnLaunch.Value || LocalMultiXtrasPlugin.IsFirstInstance)
			{
				return;
			}
			_hasAttemptedAutoJoin = true;
			try
			{
				Type type = Type.GetType("com.quackandcheese.LocalMultiplayer.Helpers.GlobalSaveHelper, com.quackandcheese.LocalMultiplayer");
				if (type == null)
				{
					return;
				}
				PropertyInfo property = type.GetProperty("SteamLobbyId", BindingFlags.Static | BindingFlags.Public);
				if (property == null)
				{
					return;
				}
				object value = property.GetValue(null);
				if (value == null)
				{
					return;
				}
				PropertyInfo property2 = value.GetType().GetProperty("Value");
				if (property2 == null)
				{
					return;
				}
				ulong num = (ulong)property2.GetValue(value);
				if (num != 0)
				{
					if (_assignSpoofAccountMethod == null)
					{
						_assignSpoofAccountMethod = Type.GetType("com.quackandcheese.LocalMultiplayer.SteamAccountManager, LocalMultiplayer")?.GetMethod("AssignSpoofAccount", BindingFlags.Static | BindingFlags.Public);
					}
					_assignSpoofAccountMethod?.Invoke(null, null);
					GameHandler.GetService<SteamLobbyHandler>().TryJoinLobby(new CSteamID(num));
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[LocalMultiXtras] AutoJoin failed: {arg}");
			}
		}
	}
	[BepInPlugin("LocalMultiXtras", "Local Multi Xtras", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class LocalMultiXtrasPlugin : BaseUnityPlugin
	{
		private static Mutex? _instanceMutex;

		public static bool IsFirstInstance { get; private set; }

		private void Awake()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			_instanceMutex = new Mutex(initiallyOwned: true, "MasterSlaveInput.InstanceLock", out var createdNew);
			IsFirstInstance = createdNew;
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
			InputBroadcaster.InitializeSyncFields();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
			GameObject val = new GameObject("MasterSlaveUIManager");
			val.AddComponent<UIManager>();
			Object.DontDestroyOnLoad((Object)(object)val);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Local Multi Xtras Mod Loaded!");
			((BaseUnityPlugin)this).Logger.LogInfo((object)(IsFirstInstance ? "This is the primary (HOST) instance." : "This is a secondary instance."));
		}

		private void OnDestroy()
		{
			if (IsFirstInstance)
			{
				_instanceMutex?.ReleaseMutex();
			}
			_instanceMutex?.Close();
		}
	}
}