Decompiled source of moreStrafts v0.1.0

moreStrafts.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Object.Synchronizing;
using FishNet.Transporting;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using moreStrafts.Patches;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("moreStrafts")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+34e216bd24532845f866566dd97ba804fddaf2b1")]
[assembly: AssemblyProduct("moreStrafts")]
[assembly: AssemblyTitle("moreStrafts")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
	[CompilerGenerated]
	[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 moreStrafts
{
	public static class Log
	{
		private static ManualLogSource? source;

		private static StreamWriter? writer;

		private static readonly object gate = new object();

		public static void Init(ManualLogSource logSource, bool perInstanceFile)
		{
			source = logSource;
			if (!perInstanceFile)
			{
				return;
			}
			try
			{
				string text = Path.Combine(Paths.BepInExRootPath, "moreStrafts_debug");
				Directory.CreateDirectory(text);
				writer = new StreamWriter(Path.Combine(text, string.Format(arg1: Process.GetCurrentProcess().Id, format: "moreStrafts_{0:yyyyMMdd_HHmmss}_pid{1}.log", arg0: DateTime.Now)), append: false)
				{
					AutoFlush = true
				};
			}
			catch (Exception ex)
			{
				logSource.LogWarning((object)("per-instance log unavailable: " + ex.Message));
			}
		}

		public static void Info(string message)
		{
			Write("INFO", message);
		}

		public static void Warn(string message)
		{
			Write("WARN", message);
		}

		public static void Error(string message)
		{
			Write("ERROR", message);
		}

		private static void Write(string level, string message)
		{
			lock (gate)
			{
				try
				{
					writer?.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] [{level}] {message}");
				}
				catch
				{
				}
			}
			if (!(level == "ERROR"))
			{
				if (level == "WARN")
				{
					ManualLogSource? obj2 = source;
					if (obj2 != null)
					{
						obj2.LogWarning((object)message);
					}
				}
				else
				{
					ManualLogSource? obj3 = source;
					if (obj3 != null)
					{
						obj3.LogInfo((object)message);
					}
				}
			}
			else
			{
				ManualLogSource? obj4 = source;
				if (obj4 != null)
				{
					obj4.LogError((object)message);
				}
			}
		}
	}
	public static class ModState
	{
		public const int MaxPlayers = 10;

		private static bool quickLoad;

		public static bool QuickLoad
		{
			get
			{
				return quickLoad;
			}
			set
			{
				if (value != quickLoad)
				{
					Log.Info($"QuickLoad {quickLoad} -> {value}");
				}
				quickLoad = value;
			}
		}
	}
	[BepInPlugin("com.nitrogenia.morestrafts", "More Strafts Players", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.nitrogenia.morestrafts";

		public const string PluginName = "More Strafts Players";

		public const string PluginVersion = "0.1.0";

		private static readonly Type[] PatchClasses = new Type[16]
		{
			typeof(SteamLobbyStartPatch),
			typeof(OnLobbyCreatedPatch),
			typeof(SetMaxPlayersPatch),
			typeof(UpdateOnClientsPatch),
			typeof(QuickLoadLobbyDataPatch),
			typeof(QuickLoadTogglePatch),
			typeof(QuickLoadInterfacePatch),
			typeof(PlayerListItemUpdatePatch),
			typeof(TeamDropdownPatch),
			typeof(RunIntoLobbyPatch),
			typeof(MenuAnimationObserversPatch),
			typeof(DressAboubiObserversPatch),
			typeof(RoundEndArraysPatch),
			typeof(GamemodeFfaPatch),
			typeof(StartGameFfaPatch),
			typeof(MatchPointsHudPatch)
		};

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "PerInstanceLogFiles", false, "Write a small per-instance log file to BepInEx/moreStrafts_debug. Include these files in bug reports.");
			Log.Init(((BaseUnityPlugin)this).Logger, val.Value);
			SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode mode)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				Log.Info($"scene '{((Scene)(ref scene)).name}' ({mode})");
			};
			Harmony val2 = new Harmony("com.nitrogenia.morestrafts");
			int num = 0;
			Type[] patchClasses = PatchClasses;
			foreach (Type type in patchClasses)
			{
				try
				{
					val2.CreateClassProcessor(type).Patch();
					num++;
				}
				catch (Exception arg)
				{
					Log.Error($"patch {type.Name} failed: {arg}");
				}
			}
			Log.Info(string.Format("{0} {1}: {2}/{3} patches applied", "More Strafts Players", "0.1.0", num, PatchClasses.Length));
		}
	}
}
namespace moreStrafts.Patches
{
	[HarmonyPatch(typeof(MatchPoitnsHUD), "UpdateVisuals", new Type[]
	{
		typeof(int),
		typeof(Dictionary<int, int>)
	})]
	internal static class MatchPointsHudPatch
	{
		private static readonly FieldRef<MatchPoitnsHUD, MeshRenderer[]> SecondaryObjects = AccessTools.FieldRefAccess<MatchPoitnsHUD, MeshRenderer[]>("secondaryPointObjects");

		private static readonly FieldRef<MatchPoitnsHUD, TMP_Text[]> PointsTexts = AccessTools.FieldRefAccess<MatchPoitnsHUD, TMP_Text[]>("pointsTexts");

		private static readonly FieldRef<MatchPoitnsHUD, MeshRenderer> PrimaryMesh = AccessTools.FieldRefAccess<MatchPoitnsHUD, MeshRenderer>("primaryPointMesh");

		private static readonly FieldRef<MatchPoitnsHUD, Material[]> ActiveMaterials = AccessTools.FieldRefAccess<MatchPoitnsHUD, Material[]>("activeMaterials");

		private static readonly FieldRef<MatchPoitnsHUD, Material> InactiveMaterial = AccessTools.FieldRefAccess<MatchPoitnsHUD, Material>("inactiveMaterial");

		private static bool warned;

		private static bool Prefix(MatchPoitnsHUD __instance, int winnerTeamId, Dictionary<int, int> roundScores)
		{
			try
			{
				if (ClientInstance.playerInstances.Count <= 1)
				{
					return false;
				}
				MeshRenderer[] array = SecondaryObjects.Invoke(__instance);
				TMP_Text[] array2 = PointsTexts.Invoke(__instance);
				MeshRenderer val = PrimaryMesh.Invoke(__instance);
				int[] array3 = ScoreManager.Instance.TeamIdToPlayerIds.Keys.ToArray();
				int num = array3.Count((int teamId) => ((SyncIDictionary<int, List<int>>)(object)ScoreManager.Instance.TeamIdToPlayerIds)[teamId].Any((int playerId) => ClientInstance.playerInstances.ContainsKey(playerId)));
				int num2 = Mathf.Clamp(num - 2, 0, array.Length);
				for (int num3 = 0; num3 < array.Length; num3++)
				{
					((Component)array[num3]).gameObject.SetActive(num3 < num2);
				}
				TMP_Text[] array4 = array2;
				for (int num4 = 0; num4 < array4.Length; num4++)
				{
					array4[num4].text = "";
				}
				Material[] materials = ((Renderer)val).materials;
				int num5 = Mathf.Min(num, 2 + array.Length);
				for (int num6 = 0; num6 < num5 && num6 < array3.Length; num6++)
				{
					int num7 = array3[num6];
					roundScores.TryGetValue(num7, out var value);
					ApplyTeamVisual(__instance, num6, value, num7 == winnerTeamId, materials);
				}
				((Renderer)val).materials = materials;
				return false;
			}
			catch (Exception arg)
			{
				if (!warned)
				{
					warned = true;
					Log.Error($"MatchPointsHudPatch: {arg}");
				}
				return true;
			}
		}

		private static void ApplyTeamVisual(MatchPoitnsHUD hud, int teamNumber, int score, bool isWinner, Material[] primaryMaterials)
		{
			Material[] array = ActiveMaterials.Invoke(hud);
			if (teamNumber < 0 || teamNumber >= array.Length)
			{
				return;
			}
			Material val = ((score > 0) ? array[teamNumber] : InactiveMaterial.Invoke(hud));
			if (teamNumber < 2)
			{
				primaryMaterials[(teamNumber == 0) ? 1 : 3] = val;
			}
			else
			{
				MeshRenderer[] array2 = SecondaryObjects.Invoke(hud);
				int num = teamNumber - 2;
				if (num < array2.Length)
				{
					Material[] materials = ((Renderer)array2[num]).materials;
					materials[1] = val;
					((Renderer)array2[num]).materials = materials;
				}
			}
			TMP_Text[] array3 = PointsTexts.Invoke(hud);
			if (((score == 2 && !isWinner) || score > 2) && teamNumber < array3.Length)
			{
				array3[teamNumber].text = score.ToString();
			}
			if (isWinner)
			{
				primaryMaterials[2] = val;
			}
		}
	}
	internal static class LobbyCapacity
	{
		public static void ExpandDropdown(TMP_Dropdown? dropdown)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			if (!((Object)(object)dropdown == (Object)null) && dropdown.options.Count < 9)
			{
				int value = dropdown.value;
				dropdown.options.Clear();
				for (int i = 2; i <= 10; i++)
				{
					dropdown.options.Add(new OptionData($"{i} Players"));
				}
				dropdown.value = value;
				dropdown.RefreshShownValue();
				Log.Info($"max-players dropdown expanded to 2-{10} (value {value})");
			}
		}

		public static void SetTransportMaxClients(int maxClients)
		{
			Transport val = InstanceFinder.TransportManager?.Transport;
			if (!((Object)(object)val == (Object)null))
			{
				val.SetMaximumClients(maxClients);
				Log.Info($"transport max clients set to {maxClients}");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "Start")]
	internal static class SteamLobbyStartPatch
	{
		private static void Postfix(SteamLobby __instance)
		{
			try
			{
				LobbyCapacity.ExpandDropdown(__instance.MaxPlayersDropdown);
				LobbyCapacity.SetTransportMaxClients(9);
			}
			catch (Exception arg)
			{
				Log.Error($"SteamLobbyStartPatch: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "OnLobbyCreated")]
	internal static class OnLobbyCreatedPatch
	{
		private static void Prefix(SteamLobby __instance)
		{
			try
			{
				LobbyCapacity.ExpandDropdown(__instance.MaxPlayersDropdown);
			}
			catch (Exception arg)
			{
				Log.Error($"OnLobbyCreatedPatch prefix: {arg}");
			}
		}

		private static void Postfix(SteamLobby __instance, LobbyCreated_t callback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((int)callback.m_eResult == 1)
				{
					SteamMatchmaking.SetLobbyData(new CSteamID(callback.m_ulSteamIDLobby), "QuickLoad", "0");
					ModState.QuickLoad = false;
					LobbyCapacity.SetTransportMaxClients(__instance.maxPlayers - 1);
					Log.Info($"lobby {callback.m_ulSteamIDLobby} created with maxPlayers={__instance.maxPlayers}");
				}
			}
			catch (Exception arg)
			{
				Log.Error($"OnLobbyCreatedPatch postfix: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "SetMaxPlayers")]
	internal static class SetMaxPlayersPatch
	{
		private static void Postfix(SteamLobby __instance)
		{
			try
			{
				LobbyCapacity.SetTransportMaxClients(__instance.maxPlayers - 1);
			}
			catch (Exception arg)
			{
				Log.Error($"SetMaxPlayersPatch: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(ClientInstance), "RpcLogic___UpdateOnClients_3316948804")]
	internal static class UpdateOnClientsPatch
	{
		private static void Prefix(ref int maxPlayers)
		{
			maxPlayers = Mathf.Clamp(maxPlayers, 2, 10);
		}
	}
	internal static class PreviewSlots
	{
		public static bool Exists(int id)
		{
			LobbyController instance = LobbyController.Instance;
			int num;
			if ((Object)(object)instance != (Object)null && id >= 0 && id < instance.previews.Length)
			{
				num = (((Object)(object)instance.previews[id] != (Object)null) ? 1 : 0);
				if (num != 0)
				{
					goto IL_0047;
				}
			}
			else
			{
				num = 0;
			}
			Log.Info($"player {id} has no lobby preview slot, skipping preview RPC");
			goto IL_0047;
			IL_0047:
			return (byte)num != 0;
		}
	}
	[HarmonyPatch(typeof(ClientInstance), "RpcLogic___RunIntoLobby_3316948804")]
	internal static class RunIntoLobbyPatch
	{
		private static bool Prefix(int id)
		{
			return PreviewSlots.Exists(id);
		}
	}
	[HarmonyPatch(typeof(ClientInstance), "RpcLogic___MenuAnimationObservers_1692629761")]
	internal static class MenuAnimationObserversPatch
	{
		private static bool Prefix(int id)
		{
			return PreviewSlots.Exists(id);
		}
	}
	[HarmonyPatch(typeof(ClientInstance), "RpcLogic___DressAboubiObservers_2497120398")]
	internal static class DressAboubiObserversPatch
	{
		private static bool Prefix(int id)
		{
			return PreviewSlots.Exists(id);
		}
	}
	internal static class GameFields
	{
		public static readonly FieldRef<PlayerListItem, GameObject> CosmeticButton = AccessTools.FieldRefAccess<PlayerListItem, GameObject>("cosmeticbutton");

		public static readonly FieldRef<PlayerListItem, PauseManager> PauseManager = AccessTools.FieldRefAccess<PlayerListItem, PauseManager>("pauseManager");

		public static readonly FieldRef<PlayerListItem, LobbyController> LobbyController = AccessTools.FieldRefAccess<PlayerListItem, LobbyController>("lobbyController");

		public static readonly FieldRef<PlayerListItem, GameManager> GameManager = AccessTools.FieldRefAccess<PlayerListItem, GameManager>("gameManager");

		public static readonly FieldRef<PlayerListItem, TMP_Dropdown> TeamDropdown = AccessTools.FieldRefAccess<PlayerListItem, TMP_Dropdown>("teamIdDropdown");

		public static readonly FieldRef<PlayerListItem, ulong> LocalSteamId = AccessTools.FieldRefAccess<PlayerListItem, ulong>("localSteamId");

		public static readonly FieldRef<GameManager, bool> PlayingTeams = AccessTools.FieldRefAccess<GameManager, bool>("playingTeams");
	}
	[HarmonyPatch(typeof(PlayerListItem), "Update")]
	internal static class PlayerListItemUpdatePatch
	{
		private static bool warned;

		private static bool Prefix(PlayerListItem __instance)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PauseManager val = GameFields.PauseManager.Invoke(__instance);
				GameObject val2 = GameFields.CosmeticButton.Invoke(__instance);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val != (Object)null)
				{
					val2.transform.localScale = (val.inMainMenu ? Vector3.one : Vector3.zero);
				}
				Transform parent = ((Component)__instance).transform.parent;
				bool flag = (Object)(object)parent != (Object)null && ((Object)((Component)parent).gameObject).name == "-- TAB SCREEN --";
				LobbyController val3 = GameFields.LobbyController.Invoke(__instance);
				if (__instance.PlayerIdNumber > 0 && (Object)(object)val3 != (Object)null)
				{
					Transform[] slots = (flag ? val3.tabclientPosition : val3.clientPosition);
					((Component)__instance).transform.position = SlotPosition(slots, __instance.PlayerIdNumber - 1);
				}
				GameManager val4 = GameFields.GameManager.Invoke(__instance);
				TMP_Dropdown val5 = GameFields.TeamDropdown.Invoke(__instance);
				if ((Object)(object)val4 != (Object)null && (Object)(object)val5 != (Object)null)
				{
					((Component)val5).gameObject.SetActive(GameFields.PlayingTeams.Invoke(val4));
					bool num = (Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer;
					bool flag2 = GameFields.LocalSteamId.Invoke(__instance) == __instance.PlayerSteamID;
					if (num || flag2)
					{
						((Selectable)val5).interactable = !flag;
					}
				}
				return false;
			}
			catch (Exception arg)
			{
				if (!warned)
				{
					warned = true;
					Log.Error($"PlayerListItemUpdatePatch: {arg}");
				}
				return true;
			}
		}

		private static Vector3 SlotPosition(Transform[] slots, int index)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (index < slots.Length)
			{
				return slots[index].position;
			}
			Vector3 position = slots[^1].position;
			return new Vector3(position.x, position.y - (float)(index - slots.Length + 1) * 0.5f, position.z);
		}
	}
	[HarmonyPatch(typeof(PlayerListItem), "Start")]
	internal static class TeamDropdownPatch
	{
		private static void Postfix(PlayerListItem __instance)
		{
			try
			{
				if ((Object)(object)SteamLobby.Instance == (Object)null || SteamLobby.Instance.maxPlayers <= 4)
				{
					return;
				}
				TMP_Dropdown val = GameFields.TeamDropdown.Invoke(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					int maxPlayers = SteamLobby.Instance.maxPlayers;
					List<string> list = new List<string>();
					for (int i = 1; i <= maxPlayers; i++)
					{
						list.Add($"Team {i}");
					}
					val.ClearOptions();
					val.AddOptions(list);
					val.SetValueWithoutNotify(ScoreManager.Instance.GetTeamId(__instance.PlayerIdNumber));
					Log.Info($"team dropdown expanded to {maxPlayers} options for player {__instance.PlayerIdNumber}");
				}
			}
			catch (Exception arg)
			{
				Log.Error($"TeamDropdownPatch: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "OnGetLobbyData")]
	internal static class QuickLoadLobbyDataPatch
	{
		private static void Postfix(LobbyDataUpdate_t result)
		{
			//IL_000d: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)SteamLobby.Instance == (Object)null) && result.m_ulSteamIDLobby == SteamLobby.Instance.CurrentLobbyID)
				{
					ModState.QuickLoad = SteamMatchmaking.GetLobbyData(new CSteamID(result.m_ulSteamIDLobby), "QuickLoad") == "1";
				}
			}
			catch (Exception arg)
			{
				Log.Error($"QuickLoadLobbyDataPatch: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "OnLobbyEntered")]
	internal static class QuickLoadTogglePatch
	{
		private static void Postfix(SteamLobby __instance, LobbyEnter_t callback)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CSteamID val = default(CSteamID);
				((CSteamID)(ref val))..ctor(callback.m_ulSteamIDLobby);
				ModState.QuickLoad = SteamMatchmaking.GetLobbyData(val, "QuickLoad") == "1";
				CreateToggle(__instance, val);
			}
			catch (Exception arg)
			{
				Log.Error($"QuickLoadTogglePatch: {arg}");
			}
		}

		private static void CreateToggle(SteamLobby lobby, CSteamID lobbyId)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)lobby.enemyOutlineToggle == (Object)null)
			{
				return;
			}
			Transform parent = ((Component)lobby.enemyOutlineToggle).transform.parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if ((Object)(object)val == (Object)null || (Object)(object)((Transform)val).parent == (Object)null)
			{
				return;
			}
			Transform val2 = ((Transform)val).parent.Find("EnableQuickLoad");
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
			RectTransform val3 = Object.Instantiate<RectTransform>(val, ((Transform)val).parent);
			((Object)val3).name = "EnableQuickLoad";
			((Transform)val3).localScale = Vector3.one;
			((Transform)val3).localPosition = ((Transform)val3).localPosition + new Vector3(0f, -60f, 0f);
			Toggle componentInChildren = ((Component)val3).GetComponentInChildren<Toggle>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				Log.Warn("QuickLoad toggle row has no Toggle component");
				return;
			}
			for (int i = 0; i < ((UnityEventBase)componentInChildren.onValueChanged).GetPersistentEventCount(); i++)
			{
				((UnityEventBase)componentInChildren.onValueChanged).SetPersistentListenerState(i, (UnityEventCallState)0);
			}
			((UnityEventBase)componentInChildren.onValueChanged).RemoveAllListeners();
			bool flag = (Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer;
			componentInChildren.SetIsOnWithoutNotify(ModState.QuickLoad);
			((Selectable)componentInChildren).interactable = flag;
			if (flag)
			{
				((UnityEvent<bool>)(object)componentInChildren.onValueChanged).AddListener((UnityAction<bool>)delegate(bool isOn)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					SteamMatchmaking.SetLobbyData(lobbyId, "QuickLoad", isOn ? "1" : "0");
				});
			}
			TextMeshProUGUI componentInChildren2 = ((Component)val3).GetComponentInChildren<TextMeshProUGUI>();
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				((TMP_Text)componentInChildren2).text = "  Enable Quick Load";
			}
			Log.Info($"QuickLoad toggle created (host={flag}, on={ModState.QuickLoad})");
		}
	}
	[HarmonyPatch(typeof(RoundManager), "InterfaceSetup")]
	internal static class QuickLoadInterfacePatch
	{
		private static bool Prefix(ref IEnumerator __result)
		{
			if (!ModState.QuickLoad)
			{
				return true;
			}
			__result = LoadingScreenOnly();
			return false;
		}

		private static IEnumerator LoadingScreenOnly()
		{
			if ((Object)(object)SceneMotor.Instance != (Object)null)
			{
				SceneMotor.Instance.ShowLoadingScreen();
			}
			yield break;
		}
	}
	[HarmonyPatch(typeof(RoundManager), "NextRoundCall")]
	internal static class RoundEndArraysPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			for (int i = 0; i + 1 < list.Count; i++)
			{
				if (!(list[i].opcode != OpCodes.Ldc_I4_4) && !(list[i + 1].opcode != OpCodes.Newarr))
				{
					Type type = list[i + 1].operand as Type;
					if (!(type != typeof(string)) || !(type != typeof(int)))
					{
						list[i].opcode = OpCodes.Ldc_I4_S;
						list[i].operand = (sbyte)10;
						num++;
					}
				}
			}
			if (num == 2)
			{
				Log.Info($"round-end name/score arrays extended to {10}");
			}
			else
			{
				Log.Warn($"round-end array pattern changed ({num} matches, expected 2); post-round screen limited to 4 players");
			}
			return list;
		}
	}
	internal static class FfaTeams
	{
		public static void AssignUniqueTeams(string context)
		{
			try
			{
				if (!((Object)(object)InstanceFinder.NetworkManager == (Object)null) && InstanceFinder.NetworkManager.IsServer && !((Object)(object)ScoreManager.Instance == (Object)null))
				{
					int[] array = ClientInstance.playerInstances.Keys.ToArray();
					ScoreManager.Instance.ResetTeams();
					int[] array2 = array;
					foreach (int num in array2)
					{
						ScoreManager.Instance.SetTeamId(num, num);
					}
					Log.Info(context + ": unique FFA team per player [" + string.Join(",", array) + "]");
				}
			}
			catch (Exception arg)
			{
				Log.Error($"FfaTeams({context}): {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "SetGamemode", new Type[] { typeof(int) })]
	internal static class GamemodeFfaPatch
	{
		private static void Postfix(int value)
		{
			if (value == 0)
			{
				FfaTeams.AssignUniqueTeams("SetGamemode");
			}
		}
	}
	[HarmonyPatch(typeof(GameManager), "StartGame")]
	internal static class StartGameFfaPatch
	{
		private static void Postfix(GameManager __instance)
		{
			try
			{
				if (!GameFields.PlayingTeams.Invoke(__instance))
				{
					FfaTeams.AssignUniqueTeams("StartGame");
				}
			}
			catch (Exception arg)
			{
				Log.Error($"StartGameFfaPatch: {arg}");
			}
		}
	}
}