Decompiled source of LocalMultiplayer v1.3.0

com.github.zehsteam.LocalMultiplayer.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using Photon.Pun;
using Photon.Realtime;
using Steamworks;
using Steamworks.Data;
using UnityEngine;
using com.github.zehsteam.LocalMultiplayer.Helpers;
using com.github.zehsteam.LocalMultiplayer.Objects;
using com.github.zehsteam.LocalMultiplayer.Patches;

[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("Zehs")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright © 2025 Zehs")]
[assembly: AssemblyDescription("Play multiplayer locally with one Steam account.")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0+4d04db22f7c5bf676b570f880cebfeaaecf84d81")]
[assembly: AssemblyProduct("LocalMultiplayer")]
[assembly: AssemblyTitle("com.github.zehsteam.LocalMultiplayer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace com.github.zehsteam.LocalMultiplayer
{
	internal static class ConfigManager
	{
		public static ConfigFile ConfigFile { get; private set; }

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

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

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

		public static void Initialize(ConfigFile configFile)
		{
			ConfigFile = configFile;
			BindConfigs();
		}

		private static void BindConfigs()
		{
			ExtendedLogging = ConfigFile.Bind<bool>("General", "ExtendedLogging", false, "Enable extended logging.");
			Photon_AppIdRealtime = ConfigFile.Bind<string>("Photon", "AppIdRealtime", "", "The App ID of your Photon Pun application.");
			Photon_AppIdVoice = ConfigFile.Bind<string>("Photon", "AppIdVoice", "", "The App ID of your Photon Voice application.");
		}
	}
	internal static class Logger
	{
		public static ManualLogSource ManualLogSource { get; private set; }

		public static void Initialize(ManualLogSource manualLogSource)
		{
			ManualLogSource = manualLogSource;
		}

		public static void LogDebug(object data, bool extended = false)
		{
			Log((LogLevel)32, data, extended);
		}

		public static void LogInfo(object data, bool extended = false)
		{
			Log((LogLevel)16, data, extended);
		}

		public static void LogWarning(object data, bool extended = false)
		{
			Log((LogLevel)4, data, extended);
		}

		public static void LogError(object data, bool extended = false)
		{
			Log((LogLevel)2, data, extended);
		}

		public static void Log(LogLevel logLevel, object data, bool extended = false)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!extended || IsExtendedLoggingEnabled())
			{
				ManualLogSource manualLogSource = ManualLogSource;
				if (manualLogSource != null)
				{
					manualLogSource.Log(logLevel, data);
				}
			}
		}

		public static bool IsExtendedLoggingEnabled()
		{
			if (ConfigManager.ExtendedLogging == null)
			{
				return false;
			}
			return ConfigManager.ExtendedLogging.Value;
		}
	}
	[BepInPlugin("com.github.zehsteam.LocalMultiplayer", "LocalMultiplayer", "1.3.0")]
	internal class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = new Harmony("com.github.zehsteam.LocalMultiplayer");

		internal static Plugin Instance { get; private set; }

		internal static ConfigFile Config { get; private set; }

		private void Awake()
		{
			Instance = this;
			Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.LocalMultiplayer"));
			Logger.LogInfo("LocalMultiplayer has awoken!");
			Config = Utils.CreateGlobalConfigFile((BaseUnityPlugin)(object)this);
			_harmony.PatchAll(typeof(NetworkConnectPatch));
			_harmony.PatchAll(typeof(SteamManagerPatch));
			_harmony.PatchAll(typeof(DataDirectorPatch));
			_harmony.PatchAll(typeof(InputManagerPatch));
			_harmony.PatchAll(typeof(MenuPageMainPatch));
			_harmony.PatchAll(typeof(PlayerAvatarPatch));
			ConfigManager.Initialize(Config);
			SteamClientPatch.PatchAll(_harmony);
		}
	}
	internal static class SteamAccountManager
	{
		public static SteamAccount SpoofAccount;

		private static bool _initialized;

		public static SteamAccount RealAccount { get; private set; }

		public static bool IsUsingSpoofAccount => SpoofAccount != default(SteamAccount);

		public static void Initialize()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized)
			{
				RealAccount = new SteamAccount(SteamClient.Name, SteamId.op_Implicit(SteamClient.SteamId));
				CreateSpoofAccounts();
				Application.quitting += UnassignSpoofAccount;
				_initialized = true;
			}
		}

		private static void CreateSpoofAccounts()
		{
			List<SteamAccount> value = GlobalSaveHelper.SpoofSteamAccounts.Value;
			int num = 5;
			if (value.Count < num)
			{
				for (int i = value.Count; i < num; i++)
				{
					value.Add(new SteamAccount($"Player {i + 2}", SteamHelper.GenerateRandomSteamId()));
				}
				GlobalSaveHelper.SpoofSteamAccounts.Value = value;
			}
		}

		public static void AssignSpoofAccount()
		{
			if (!IsUsingSpoofAccount)
			{
				SteamAccount availableSpoofAccount = GetAvailableSpoofAccount();
				AddSpoofAccountInUse(availableSpoofAccount);
				SpoofAccount = availableSpoofAccount;
				PhotonNetwork.NickName = availableSpoofAccount.Username;
			}
		}

		public static void UnassignSpoofAccount()
		{
			if (IsUsingSpoofAccount)
			{
				RemoveSpoofAccountInUse(SpoofAccount);
				SpoofAccount = default(SteamAccount);
				PhotonNetwork.NickName = RealAccount.Username;
			}
		}

		public static void ResetSpoofAccountsInUse()
		{
			GlobalSaveHelper.SpoofSteamAccountsInUse.Value = new List<SteamAccount>();
		}

		public static bool TryGetSpoofAccount(ulong steamId, out SteamAccount steamAccount)
		{
			List<SteamAccount> value = GlobalSaveHelper.SpoofSteamAccounts.Value;
			foreach (SteamAccount item in value)
			{
				if (item.SteamId == steamId)
				{
					steamAccount = item;
					return true;
				}
			}
			steamAccount = default(SteamAccount);
			return false;
		}

		public static void SetCurrentSpoofAccountColor(int id)
		{
			if (IsUsingSpoofAccount)
			{
				SpoofAccount.ColorId = id;
				UpdateCurrentSpoofAccountData();
			}
		}

		private static void UpdateCurrentSpoofAccountData()
		{
			if (!IsUsingSpoofAccount)
			{
				return;
			}
			List<SteamAccount> value = GlobalSaveHelper.SpoofSteamAccounts.Value;
			for (int i = 0; i < value.Count; i++)
			{
				if (value[i] == SpoofAccount)
				{
					value[i] = SpoofAccount;
					break;
				}
			}
			GlobalSaveHelper.SpoofSteamAccounts.Value = value;
		}

		private static List<SteamAccount> GetAvailableSpoofAccounts()
		{
			List<SteamAccount> list = new List<SteamAccount>();
			List<SteamAccount> value = GlobalSaveHelper.SpoofSteamAccountsInUse.Value;
			foreach (SteamAccount item in GlobalSaveHelper.SpoofSteamAccounts.Value)
			{
				if (!value.Contains(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static SteamAccount GetAvailableSpoofAccount()
		{
			List<SteamAccount> availableSpoofAccounts = GetAvailableSpoofAccounts();
			if (availableSpoofAccounts.Count == 0)
			{
				Logger.LogWarning("SteamHelper: No cached spoof steam accounts available. Generating new spoof steam account.");
				return new SteamAccount($"Player {Random.Range(100, 999)}", SteamHelper.GenerateRandomSteamId());
			}
			return availableSpoofAccounts[0];
		}

		private static void AddSpoofAccountInUse(SteamAccount account)
		{
			List<SteamAccount> value = GlobalSaveHelper.SpoofSteamAccountsInUse.Value;
			if (!value.Contains(account))
			{
				value.Add(account);
				GlobalSaveHelper.SpoofSteamAccountsInUse.Value = value;
			}
		}

		private static void RemoveSpoofAccountInUse(SteamAccount account)
		{
			List<SteamAccount> value = GlobalSaveHelper.SpoofSteamAccountsInUse.Value;
			if (value.Contains(account))
			{
				value.Remove(account);
				GlobalSaveHelper.SpoofSteamAccountsInUse.Value = value;
			}
		}
	}
	internal static class Utils
	{
		public static string GetPluginPersistentDataPath()
		{
			return Path.Combine(Application.persistentDataPath, "LocalMultiplayer");
		}

		public static ConfigFile CreateConfigFile(BaseUnityPlugin plugin, string path, string name = null, bool saveOnInit = false)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin);
			if (name == null)
			{
				name = metadata.GUID;
			}
			name += ".cfg";
			return new ConfigFile(Path.Combine(path, name), saveOnInit, metadata);
		}

		public static ConfigFile CreateLocalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false)
		{
			return CreateConfigFile(plugin, Paths.ConfigPath, name, saveOnInit);
		}

		public static ConfigFile CreateGlobalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false)
		{
			string pluginPersistentDataPath = GetPluginPersistentDataPath();
			if (name == null)
			{
				name = "global";
			}
			return CreateConfigFile(plugin, pluginPersistentDataPath, name, saveOnInit);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.github.zehsteam.LocalMultiplayer";

		public const string PLUGIN_NAME = "LocalMultiplayer";

		public const string PLUGIN_VERSION = "1.3.0";
	}
}
namespace com.github.zehsteam.LocalMultiplayer.Patches
{
	[HarmonyPatch(typeof(DataDirector))]
	internal static class DataDirectorPatch
	{
		[HarmonyPatch("SaveSettings")]
		[HarmonyPrefix]
		private static bool SaveSettingsPatch()
		{
			if (!SteamAccountManager.IsUsingSpoofAccount)
			{
				return true;
			}
			return false;
		}

		[HarmonyPatch("ColorSetBody")]
		[HarmonyPrefix]
		private static bool ColorSetBodyPatch(int colorID)
		{
			if (!SteamAccountManager.IsUsingSpoofAccount)
			{
				return true;
			}
			SteamAccountManager.SetCurrentSpoofAccountColor(colorID);
			return false;
		}

		[HarmonyPatch("ColorGetBody")]
		[HarmonyPrefix]
		private static bool ColorGetBodyPatch(ref int __result)
		{
			if (!SteamAccountManager.IsUsingSpoofAccount)
			{
				return true;
			}
			__result = SteamAccountManager.SpoofAccount.ColorId;
			return false;
		}
	}
	[HarmonyPatch(typeof(InputManager))]
	internal static class InputManagerPatch
	{
		[HarmonyPatch("SaveDefaultKeyBindings")]
		[HarmonyPrefix]
		private static bool SaveDefaultKeyBindingsPatch()
		{
			if (!SteamAccountManager.IsUsingSpoofAccount)
			{
				return true;
			}
			return false;
		}

		[HarmonyPatch("SaveCurrentKeyBindings")]
		[HarmonyPrefix]
		private static bool SaveCurrentKeyBindingsPatch()
		{
			if (!SteamAccountManager.IsUsingSpoofAccount)
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(MenuPageMain))]
	internal static class MenuPageMainPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			SteamAccountManager.UnassignSpoofAccount();
		}

		[HarmonyPatch("ButtonEventJoinGame")]
		[HarmonyPrefix]
		private static bool ButtonEventJoinGamePatch()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			SteamAccountManager.AssignSpoofAccount();
			PhotonNetworkHelper.SetPhotonServerSettings();
			SteamManager instance = SteamManager.instance;
			if (instance != null)
			{
				instance.OnGameLobbyJoinRequested(new Lobby(SteamId.op_Implicit(GlobalSaveHelper.SteamLobbyId.Value)), SteamClient.SteamId);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(NetworkConnect))]
	internal static class NetworkConnectPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			PhotonNetworkHelper.SetPhotonServerSettings();
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar))]
	internal static class PlayerAvatarPatch
	{
		[HarmonyPatch("AddToStatsManager")]
		[HarmonyPrefix]
		private static void AddToStatsManagerPatch()
		{
			PhotonNetwork.NickName = SteamClient.Name;
		}
	}
	internal static class SteamClientPatch
	{
		public static void PatchAll(Harmony harmony)
		{
			if (harmony == null)
			{
				Logger.LogError("SteamClientPatch: Failed to apply patches. Harmony is null.");
				return;
			}
			ApplyNamePatch(harmony);
			ApplySteamIdPatch(harmony);
		}

		private static void ApplyNamePatch(Harmony harmony)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(SteamClient), "Name");
			MethodInfo methodInfo2 = AccessTools.Method(typeof(SteamClientPatch), "NamePatch", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Logger.LogError("SteamClientPatch: Failed to apply Name patch. Required methods not found.");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void ApplySteamIdPatch(Harmony harmony)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(SteamClient), "SteamId");
			MethodInfo methodInfo2 = AccessTools.Method(typeof(SteamClientPatch), "SteamIdPatch", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Logger.LogError("SteamClientPatch: Failed to apply SteamId patch. Required methods not found.");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static bool NamePatch(ref string __result)
		{
			if (!SteamAccountManager.IsUsingSpoofAccount)
			{
				return true;
			}
			__result = SteamAccountManager.SpoofAccount.Username;
			return false;
		}

		private static bool SteamIdPatch(ref SteamId __result)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!SteamAccountManager.IsUsingSpoofAccount)
			{
				return true;
			}
			__result = SteamId.op_Implicit(SteamAccountManager.SpoofAccount.SteamId);
			return false;
		}
	}
	[HarmonyPatch(typeof(SteamManager))]
	internal static class SteamManagerPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void AwakePatch()
		{
			SteamAccountManager.Initialize();
		}

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			if (!IsValidClient())
			{
				Application.Quit();
			}
		}

		[HarmonyPatch("OnLobbyCreated")]
		[HarmonyPostfix]
		private static void OnLobbyCreatedPatch(ref Result _result, ref Lobby _lobby)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((int)_result == 1)
			{
				GlobalSaveHelper.SteamLobbyId.Value = SteamId.op_Implicit(((Lobby)(ref _lobby)).Id);
				SteamAccountManager.ResetSpoofAccountsInUse();
			}
		}

		[HarmonyPatch("SendSteamAuthTicket")]
		[HarmonyPrefix]
		private static bool SendSteamAuthTicketPatch()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			PhotonNetwork.AuthValues = new AuthenticationValues(Guid.NewGuid().ToString());
			return false;
		}

		private static bool IsValidClient()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			AuthTicket steamAuthTicket = SteamManager.instance.steamAuthTicket;
			if (steamAuthTicket == null)
			{
				return false;
			}
			BeginAuthResult val = SteamUser.BeginAuthSession(steamAuthTicket.Data, SteamClient.SteamId);
			return (int)val == 0;
		}
	}
}
namespace com.github.zehsteam.LocalMultiplayer.Objects
{
	internal class JsonSave : IDisposable
	{
		private JObject _data;

		private readonly Mutex _mutex;

		private const int _mutexTimeoutMs = 5000;

		private bool _disposed;

		public string DirectoryPath { get; private set; }

		public string FileName { get; private set; }

		public string FilePath => Path.Combine(DirectoryPath, FileName);

		public JsonSave(string directoryPath, string fileName)
		{
			DirectoryPath = directoryPath;
			FileName = fileName;
			string name = "Global\\JsonSave_" + fileName.Replace(Path.DirectorySeparatorChar, '_');
			_mutex = new Mutex(initiallyOwned: false, name);
			RefreshData();
			Application.quitting += Dispose;
		}

		public bool KeyExists(string key)
		{
			RefreshData();
			JObject data = _data;
			return data != null && data.ContainsKey(key);
		}

		public T Load<T>(string key, T defaultValue = default(T))
		{
			T value;
			return TryLoad<T>(key, out value) ? value : defaultValue;
		}

		public bool TryLoad<T>(string key, out T value)
		{
			value = default(T);
			RefreshData();
			if (_data == null)
			{
				Logger.LogError("TryLoad: Data is null. Key: " + key);
				return false;
			}
			JToken val = default(JToken);
			if (_data.TryGetValue(key, ref val))
			{
				try
				{
					value = val.ToObject<T>();
					return true;
				}
				catch (Exception ex)
				{
					Logger.LogError("TryLoad: Failed to deserialize key '" + key + "'. " + ex.Message);
				}
			}
			return false;
		}

		public bool Save<T>(string key, T value)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			bool flag = false;
			try
			{
				flag = _mutex.WaitOne(5000);
				if (!flag)
				{
					Logger.LogWarning("Save: Could not acquire mutex.");
					return false;
				}
				RefreshData();
				if (_data == null)
				{
					_data = new JObject();
				}
				_data[key] = JToken.FromObject((object)value);
				return WriteFile(_data);
			}
			catch (Exception ex)
			{
				Logger.LogError("Save: Error saving key '" + key + "'. " + ex.Message);
				return false;
			}
			finally
			{
				if (flag)
				{
					_mutex.ReleaseMutex();
				}
			}
		}

		private JObject ReadFile()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			try
			{
				if (!File.Exists(FilePath))
				{
					Logger.LogWarning("ReadFile: Save file not found at \"" + FilePath + "\". Creating new.");
					return new JObject();
				}
				using FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
				using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
				return JObject.Parse(streamReader.ReadToEnd());
			}
			catch (Exception ex)
			{
				Logger.LogError("ReadFile: Failed to read file \"" + FilePath + "\". " + ex.Message);
				return new JObject();
			}
		}

		private bool WriteFile(JObject data)
		{
			try
			{
				if (!Directory.Exists(DirectoryPath))
				{
					Directory.CreateDirectory(DirectoryPath);
				}
				File.WriteAllText(FilePath, ((object)data).ToString(), Encoding.UTF8);
				return true;
			}
			catch (Exception ex)
			{
				Logger.LogError("WriteFile: Failed to write file \"" + FilePath + "\". " + ex.Message);
				return false;
			}
		}

		private void RefreshData()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			_data = ReadFile();
			if (_data == null)
			{
				Logger.LogError("RefreshData: Data is null. Creating new.");
				_data = new JObject();
			}
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_mutex?.Dispose();
				_disposed = true;
			}
		}
	}
	internal class JsonSaveValue<T>
	{
		public JsonSave JsonSave { get; private set; }

		public string Key { get; private set; }

		public T DefaultValue { get; private set; }

		public T Value
		{
			get
			{
				return Load();
			}
			set
			{
				Save(value);
			}
		}

		public bool HasValue
		{
			get
			{
				T value;
				return TryLoad(out value);
			}
		}

		public JsonSaveValue(JsonSave jsonSave, string key, T defaultValue = default(T))
		{
			JsonSave = jsonSave;
			Key = key;
			DefaultValue = defaultValue;
			base..ctor();
		}

		public T Load()
		{
			return JsonSave.Load(Key, DefaultValue);
		}

		public bool TryLoad(out T value)
		{
			return JsonSave.TryLoad<T>(Key, out value);
		}

		public void Save(T value)
		{
			JsonSave.Save(Key, value);
		}
	}
	public struct SteamAccount : IEquatable<SteamAccount>
	{
		public string Username;

		public ulong SteamId;

		public int ColorId;

		public SteamAccount(string username, ulong steamId)
		{
			ColorId = 0;
			Username = username;
			SteamId = steamId;
		}

		public SteamAccount(string username, ulong steamId, int colorIndex)
			: this(username, steamId)
		{
			ColorId = colorIndex;
		}

		public bool Equals(SteamAccount other)
		{
			return SteamId == other.SteamId;
		}

		public override bool Equals(object obj)
		{
			return obj is SteamAccount other && Equals(other);
		}

		public static bool operator ==(SteamAccount a, SteamAccount b)
		{
			return a.Equals(b);
		}

		public static bool operator !=(SteamAccount a, SteamAccount b)
		{
			return !a.Equals(b);
		}

		public override int GetHashCode()
		{
			return SteamId.GetHashCode();
		}
	}
}
namespace com.github.zehsteam.LocalMultiplayer.Helpers
{
	internal static class GlobalSaveHelper
	{
		public static JsonSave JsonSave { get; private set; }

		public static JsonSaveValue<ulong> SteamLobbyId { get; private set; }

		public static JsonSaveValue<List<SteamAccount>> SpoofSteamAccounts { get; private set; }

		public static JsonSaveValue<List<SteamAccount>> SpoofSteamAccountsInUse { get; private set; }

		static GlobalSaveHelper()
		{
			JsonSave = new JsonSave(Utils.GetPluginPersistentDataPath(), "GlobalSave");
			SteamLobbyId = new JsonSaveValue<ulong>(JsonSave, "SteamLobbyId", 0uL);
			SpoofSteamAccounts = new JsonSaveValue<List<SteamAccount>>(JsonSave, "SpoofSteamAccounts", new List<SteamAccount>());
			SpoofSteamAccountsInUse = new JsonSaveValue<List<SteamAccount>>(JsonSave, "SpoofSteamAccountsInUse", new List<SteamAccount>());
		}

		public static bool KeyExists(string key)
		{
			return JsonSave.KeyExists(key);
		}

		public static T Load<T>(string key, T defaultValue = default(T))
		{
			return JsonSave.Load(key, defaultValue);
		}

		public static bool TryLoad<T>(string key, out T value)
		{
			return JsonSave.TryLoad<T>(key, out value);
		}

		public static bool Save<T>(string key, T value)
		{
			return JsonSave.Save(key, value);
		}
	}
	internal static class PhotonNetworkHelper
	{
		public static void SetPhotonServerSettings()
		{
			AppSettings appSettings = PhotonNetwork.PhotonServerSettings.AppSettings;
			appSettings.AppIdRealtime = ConfigManager.Photon_AppIdRealtime.Value;
			appSettings.AppIdVoice = ConfigManager.Photon_AppIdVoice.Value;
		}
	}
	internal static class SteamHelper
	{
		public static ulong GenerateRandomSteamId()
		{
			ulong num = 76561197960265728uL;
			Random random = new Random();
			uint num2 = (uint)random.Next(0, int.MaxValue);
			num2 += (uint)random.Next(0, int.MaxValue);
			return num + num2;
		}
	}
}
namespace com.github.zehsteam.LocalMultiplayer.Extensions
{
	internal static class StringExtensions
	{
		public static ulong ToUlong(this string value)
		{
			if (ulong.TryParse(value, out var result))
			{
				return result;
			}
			return 0uL;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}