Decompiled source of DrawableSuits v0.5.77

BepInEx/plugins/DrawableSuits/DrawableSuits.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.UI;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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("DrawableSuits")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+4aec450a9737f33a67a55ab1962cf6ed017afa14")]
[assembly: AssemblyProduct("DrawableSuits")]
[assembly: AssemblyTitle("DrawableSuits")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 DrawableSuits
{
	internal static class DrawableSuitDesignCode
	{
		[Serializable]
		internal sealed class Payload
		{
			public int formatVersion;

			public string modVersion;

			public string designName;

			public string baseSuitName;

			public int sourceSuitId;

			public int width;

			public int height;

			public string exportedUtc;

			public string pngBase64;
		}

		internal struct CodeInfo
		{
			internal int FormatVersion;

			internal string DesignName;

			internal string BaseSuitName;

			internal int SourceSuitId;

			internal int Width;

			internal int Height;

			internal int PngBytes;

			internal int JsonBytes;

			internal int PayloadBytes;

			internal int CompressedBytes;

			internal int CodeLength;
		}

		internal const string PrefixV1 = "DSUIT1:";

		internal const string PrefixV2 = "DSUIT2:";

		internal const string Prefix = "DSUIT2:";

		private const int FormatVersionV1 = 1;

		private const int FormatVersionV2 = 2;

		private const int MaxDecodedJsonBytes = 25165824;

		private const int MaxDecodedBinaryBytes = 18874368;

		private const int MaxPngBytes = 16777216;

		internal static bool HasSupportedPrefix(string code)
		{
			if (string.IsNullOrWhiteSpace(code))
			{
				return false;
			}
			string text = code.TrimStart();
			if (!text.StartsWith("DSUIT2:", StringComparison.Ordinal))
			{
				return text.StartsWith("DSUIT1:", StringComparison.Ordinal);
			}
			return true;
		}

		internal static bool TryExport(SuitTextureState state, string designName, out string code, out CodeInfo info, out string failureReason)
		{
			code = string.Empty;
			info = default(CodeInfo);
			failureReason = string.Empty;
			if ((Object)(object)state?.EditableTexture == (Object)null)
			{
				failureReason = "No editable suit texture is available.";
				return false;
			}
			string text = TextureTools.SanitizeFileName(designName);
			if (string.IsNullOrWhiteSpace(text))
			{
				failureReason = "Design name is empty.";
				return false;
			}
			byte[] array = ImageConversion.EncodeToPNG(state.EditableTexture);
			if (array == null || array.Length == 0)
			{
				failureReason = "Failed to encode the editable texture.";
				return false;
			}
			if (array.Length > 16777216)
			{
				failureReason = $"Encoded texture is too large ({array.Length} bytes).";
				return false;
			}
			byte[] array2 = BuildV2PayloadBytes(text, state.SuitName ?? string.Empty, state.SuitId, ((Texture)state.EditableTexture).width, ((Texture)state.EditableTexture).height, DateTime.UtcNow.ToString("o"), array);
			byte[] array3 = Compress(array2);
			code = "DSUIT2:" + ToBase64Url(array3);
			info = new CodeInfo
			{
				FormatVersion = 2,
				DesignName = text,
				BaseSuitName = (state.SuitName ?? string.Empty),
				SourceSuitId = state.SuitId,
				Width = ((Texture)state.EditableTexture).width,
				Height = ((Texture)state.EditableTexture).height,
				PngBytes = array.Length,
				JsonBytes = 0,
				PayloadBytes = array2.Length,
				CompressedBytes = array3.Length,
				CodeLength = code.Length
			};
			return true;
		}

		internal static bool TryDecode(string code, int maxTextureSize, out Payload payload, out Texture2D texture, out CodeInfo info, out string failureReason)
		{
			payload = null;
			texture = null;
			info = default(CodeInfo);
			failureReason = string.Empty;
			if (string.IsNullOrWhiteSpace(code))
			{
				failureReason = "Design code is empty.";
				return false;
			}
			code = code.Trim();
			if (code.StartsWith("DSUIT2:", StringComparison.Ordinal))
			{
				return TryDecodeV2(code, maxTextureSize, out payload, out texture, out info, out failureReason);
			}
			if (code.StartsWith("DSUIT1:", StringComparison.Ordinal))
			{
				return TryDecodeV1(code, maxTextureSize, out payload, out texture, out info, out failureReason);
			}
			failureReason = "Design code must start with DSUIT2: or DSUIT1:";
			return false;
		}

		private static byte[] BuildV2PayloadBytes(string designName, string baseSuitName, int sourceSuitId, int width, int height, string exportedUtc, byte[] pngBytes)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true))
			{
				binaryWriter.Write(2);
				binaryWriter.Write("0.5.77");
				binaryWriter.Write(designName ?? string.Empty);
				binaryWriter.Write(baseSuitName ?? string.Empty);
				binaryWriter.Write(sourceSuitId);
				binaryWriter.Write(width);
				binaryWriter.Write(height);
				binaryWriter.Write(exportedUtc ?? string.Empty);
				binaryWriter.Write((pngBytes != null) ? pngBytes.Length : 0);
				if (pngBytes != null && pngBytes.Length != 0)
				{
					binaryWriter.Write(pngBytes);
				}
			}
			return memoryStream.ToArray();
		}

		private static bool TryDecodeV2(string code, int maxTextureSize, out Payload payload, out Texture2D texture, out CodeInfo info, out string failureReason)
		{
			payload = null;
			texture = null;
			info = default(CodeInfo);
			failureReason = string.Empty;
			byte[] array;
			try
			{
				array = FromBase64Url(RemoveWhitespace(code.Substring("DSUIT2:".Length)));
			}
			catch (Exception ex)
			{
				failureReason = "Design code is not valid Base64Url data (" + ex.GetType().Name + ").";
				return false;
			}
			byte[] array2;
			try
			{
				array2 = Decompress(array, 18874368);
			}
			catch (Exception ex2)
			{
				failureReason = "Design code payload could not be decompressed (" + ex2.GetType().Name + ").";
				return false;
			}
			byte[] array3;
			try
			{
				using MemoryStream memoryStream = new MemoryStream(array2);
				using BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8);
				int num = binaryReader.ReadInt32();
				if (num != 2)
				{
					failureReason = $"Unsupported design code format {num}.";
					return false;
				}
				payload = new Payload
				{
					formatVersion = num,
					modVersion = binaryReader.ReadString(),
					designName = binaryReader.ReadString(),
					baseSuitName = binaryReader.ReadString(),
					sourceSuitId = binaryReader.ReadInt32(),
					width = binaryReader.ReadInt32(),
					height = binaryReader.ReadInt32(),
					exportedUtc = binaryReader.ReadString(),
					pngBase64 = string.Empty
				};
				int num2 = binaryReader.ReadInt32();
				if (num2 <= 0)
				{
					failureReason = "Design code PNG data is empty.";
					return false;
				}
				if (num2 > 16777216)
				{
					failureReason = $"Design code PNG data is too large ({num2} bytes).";
					return false;
				}
				if (memoryStream.Length - memoryStream.Position < num2)
				{
					failureReason = "Design code PNG data is truncated.";
					return false;
				}
				array3 = binaryReader.ReadBytes(num2);
				if (array3.Length != num2)
				{
					failureReason = "Design code PNG data is truncated.";
					return false;
				}
			}
			catch (Exception ex3)
			{
				payload = null;
				failureReason = "Design code binary payload could not be parsed (" + ex3.GetType().Name + ").";
				return false;
			}
			return TryLoadDecodedTexture(code, maxTextureSize, payload, array3, array2.Length, 0, array.Length, out texture, out info, out failureReason);
		}

		private static bool TryDecodeV1(string code, int maxTextureSize, out Payload payload, out Texture2D texture, out CodeInfo info, out string failureReason)
		{
			payload = null;
			texture = null;
			info = default(CodeInfo);
			failureReason = string.Empty;
			byte[] array;
			try
			{
				array = FromBase64Url(RemoveWhitespace(code.Substring("DSUIT1:".Length)));
			}
			catch (Exception ex)
			{
				failureReason = "Design code is not valid Base64Url data (" + ex.GetType().Name + ").";
				return false;
			}
			byte[] array2;
			try
			{
				array2 = Decompress(array, 25165824);
			}
			catch (Exception ex2)
			{
				failureReason = "Design code payload could not be decompressed (" + ex2.GetType().Name + ").";
				return false;
			}
			try
			{
				payload = JsonUtility.FromJson<Payload>(Encoding.UTF8.GetString(array2));
			}
			catch (Exception ex3)
			{
				failureReason = "Design code JSON could not be parsed (" + ex3.GetType().Name + ").";
				return false;
			}
			if (payload == null)
			{
				failureReason = "Design code payload is missing.";
				return false;
			}
			if (payload.formatVersion != 1)
			{
				failureReason = $"Unsupported design code format {payload.formatVersion}.";
				return false;
			}
			if (string.IsNullOrWhiteSpace(payload.pngBase64))
			{
				failureReason = "Design code is missing PNG data.";
				return false;
			}
			byte[] pngBytes;
			try
			{
				pngBytes = Convert.FromBase64String(payload.pngBase64);
			}
			catch (Exception ex4)
			{
				failureReason = "Design code PNG data is invalid (" + ex4.GetType().Name + ").";
				return false;
			}
			return TryLoadDecodedTexture(code, maxTextureSize, payload, pngBytes, 0, array2.Length, array.Length, out texture, out info, out failureReason);
		}

		private static bool TryLoadDecodedTexture(string code, int maxTextureSize, Payload payload, byte[] pngBytes, int payloadBytes, int jsonBytes, int compressedBytes, out Texture2D texture, out CodeInfo info, out string failureReason)
		{
			texture = null;
			info = default(CodeInfo);
			failureReason = string.Empty;
			if (payload == null)
			{
				failureReason = "Design code payload is missing.";
				return false;
			}
			if (string.IsNullOrWhiteSpace(payload.designName))
			{
				failureReason = "Design code is missing a design name.";
				return false;
			}
			if (payload.width <= 0 || payload.height <= 0)
			{
				failureReason = "Design code has invalid texture dimensions.";
				return false;
			}
			if (payload.width > maxTextureSize || payload.height > maxTextureSize)
			{
				failureReason = $"Design code texture is too large ({payload.width}x{payload.height}, max {maxTextureSize}).";
				return false;
			}
			if (pngBytes == null || pngBytes.Length == 0)
			{
				failureReason = "Design code PNG data is empty.";
				return false;
			}
			if (pngBytes.Length > 16777216)
			{
				failureReason = $"Design code PNG data is too large ({pngBytes.Length} bytes).";
				return false;
			}
			texture = TextureTools.LoadImageBytes(pngBytes, "DrawableSuitsDesignCodeTexture", maxTextureSize, resizeOversized: false);
			if ((Object)(object)texture == (Object)null)
			{
				failureReason = $"Design code PNG data could not be loaded as an image or exceeds max size {maxTextureSize}.";
				return false;
			}
			if (((Texture)texture).width > maxTextureSize || ((Texture)texture).height > maxTextureSize)
			{
				int width = ((Texture)texture).width;
				int height = ((Texture)texture).height;
				Object.Destroy((Object)(object)texture);
				texture = null;
				failureReason = $"Decoded texture is too large ({width}x{height}, max {maxTextureSize}).";
				return false;
			}
			info = new CodeInfo
			{
				FormatVersion = payload.formatVersion,
				DesignName = payload.designName,
				BaseSuitName = payload.baseSuitName,
				SourceSuitId = payload.sourceSuitId,
				Width = ((Texture)texture).width,
				Height = ((Texture)texture).height,
				PngBytes = pngBytes.Length,
				JsonBytes = jsonBytes,
				PayloadBytes = payloadBytes,
				CompressedBytes = compressedBytes,
				CodeLength = code.Length
			};
			return true;
		}

		private static byte[] Compress(byte[] bytes)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, leaveOpen: true))
			{
				gZipStream.Write(bytes, 0, bytes.Length);
			}
			return memoryStream.ToArray();
		}

		private static byte[] Decompress(byte[] bytes, int maxBytes)
		{
			using MemoryStream stream = new MemoryStream(bytes);
			using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			byte[] array = new byte[8192];
			int num;
			while ((num = gZipStream.Read(array, 0, array.Length)) > 0)
			{
				if (memoryStream.Length + num > maxBytes)
				{
					throw new InvalidDataException("Decoded payload exceeds the maximum allowed size.");
				}
				memoryStream.Write(array, 0, num);
			}
			return memoryStream.ToArray();
		}

		private static string ToBase64Url(byte[] bytes)
		{
			return Convert.ToBase64String(bytes).TrimEnd('=').Replace('+', '-')
				.Replace('/', '_');
		}

		private static byte[] FromBase64Url(string value)
		{
			value = value.Replace('-', '+').Replace('_', '/');
			switch (value.Length % 4)
			{
			case 2:
				value += "==";
				break;
			case 3:
				value += "=";
				break;
			default:
				throw new FormatException("Invalid Base64Url padding.");
			case 0:
				break;
			}
			return Convert.FromBase64String(value);
		}

		private static string RemoveWhitespace(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(value.Length);
			for (int i = 0; i < value.Length; i++)
			{
				if (!char.IsWhiteSpace(value[i]))
				{
					stringBuilder.Append(value[i]);
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal sealed class DrawableSuitsConfig
	{
		public ConfigEntry<KeyCode> OpenEditorKey { get; }

		public ConfigEntry<KeyCode> EmergencyOpenKey { get; }

		public ConfigEntry<int> MaxTextureSize { get; }

		public ConfigEntry<int> MaxUndoStates { get; }

		public ConfigEntry<int> MaxSyncBytes { get; }

		public ConfigEntry<int> SyncChunkBytes { get; }

		public ConfigEntry<float> ControllerCursorSpeed { get; }

		public ConfigEntry<bool> EnableNetworkSync { get; }

		public ConfigEntry<bool> EnableExperimentalModelPreview { get; }

		public ConfigEntry<bool> StartInUvFallbackMode { get; }

		public ConfigEntry<float> ThirdPersonCameraDistance { get; }

		public ConfigEntry<string> RecentColors { get; }

		public ConfigEntry<bool> ApplyLocalFirstPersonArms { get; }

		public DrawableSuitsConfig(ConfigFile config)
		{
			OpenEditorKey = config.Bind<KeyCode>("Input", "OpenEditorKey", (KeyCode)289, "Keyboard key that opens or closes the suit editor.");
			EmergencyOpenKey = config.Bind<KeyCode>("Input", "EmergencyOpenKey", (KeyCode)291, "Keyboard key that opens the editor even when suit/player detection is incomplete.");
			ControllerCursorSpeed = config.Bind<float>("Input", "ControllerCursorSpeed", 900f, "Virtual cursor speed in pixels per second.");
			MaxTextureSize = config.Bind<int>("Textures", "MaxTextureSize", 1024, "Maximum width and height for editable and synced suit textures.");
			MaxUndoStates = config.Bind<int>("Editor", "MaxUndoStates", 12, "Maximum undo snapshots kept while editing.");
			EnableNetworkSync = config.Bind<bool>("Multiplayer", "EnableNetworkSync", true, "Sync applied and saved suit designs to other DrawableSuits users.");
			MaxSyncBytes = config.Bind<int>("Multiplayer", "MaxSyncBytes", 4194304, "Maximum PNG payload size allowed for multiplayer sync.");
			SyncChunkBytes = config.Bind<int>("Multiplayer", "SyncChunkBytes", 48000, "Byte size for each Netcode custom-message texture chunk.");
			EnableExperimentalModelPreview = config.Bind<bool>("Editor", "EnableExperimentalModelPreview", false, "Disabled by default. Uses the old camera/RenderTexture 3D model preview only for diagnostics; third-person world painting is the default.");
			StartInUvFallbackMode = config.Bind<bool>("Editor", "StartInUvFallbackMode", false, "Open directly into the old UV texture fallback instead of third-person world painting. Useful for diagnostics.");
			ThirdPersonCameraDistance = config.Bind<float>("Editor", "ThirdPersonCameraDistance", 3.4f, "Default third-person editor camera orbit distance.");
			RecentColors = config.Bind<string>("Editor", "RecentColors", string.Empty, "Recent brush colors as comma-separated #RRGGBB values. Colors are added only after Paint, Fill, or Text writes to the suit.");
			ApplyLocalFirstPersonArms = config.Bind<bool>("Compatibility", "ApplyLocalFirstPersonArms", false, "Experimental. When false, DrawableSuits does not apply edited materials to the local first-person arms/body outside the editor.");
		}
	}
	internal static class DrawableSuitsDiagnostics
	{
		private static readonly object SyncRoot = new object();

		private static string _logPath;

		private static bool _initialized;

		public static string LogPath => _logPath ?? Path.Combine(DrawableSuitsPaths.Logs, "diagnostics.log");

		public static void Initialize()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DrawableSuitsPaths.EnsureCreated();
				_logPath = Path.Combine(DrawableSuitsPaths.Logs, "diagnostics.log");
				Directory.CreateDirectory(Path.GetDirectoryName(_logPath));
				File.WriteAllText(_logPath, string.Empty);
				_initialized = true;
				Info("Diagnostics initialized.");
				Info("DrawableSuits 0.5.77 (com.toxcgang.drawablesuits) starting.");
				Info($"UnityVersion={Application.unityVersion}; ApplicationVersion={Application.version}; Platform={Application.platform}; ProductName={Application.productName}");
				Info("DataPath=" + Application.dataPath + "; PersistentDataPath=" + Application.persistentDataPath + "; ConfigRoot=" + DrawableSuitsPaths.Root);
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				activeScene = SceneManager.GetActiveScene();
				Info($"ActiveScene={name}; SceneBuildIndex={((Scene)(ref activeScene)).buildIndex}");
				AssemblyName[] referencedAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
				foreach (AssemblyName assemblyName in referencedAssemblies)
				{
					Info($"Reference={assemblyName.Name}, Version={assemblyName.Version}");
				}
			}
			catch (Exception arg)
			{
				_initialized = false;
				LogToBepInEx((LogLevel)2, $"DrawableSuits diagnostics failed to initialize: {arg}");
			}
		}

		public static void Info(string message)
		{
			Write((LogLevel)16, message);
		}

		public static void Warn(string message)
		{
			Write((LogLevel)4, message);
		}

		public static void Error(string message)
		{
			Write((LogLevel)2, message);
		}

		public static void Exception(string context, Exception exception)
		{
			if (exception == null)
			{
				Error(context + ": unknown exception.");
				return;
			}
			Write((LogLevel)2, context + ": " + exception.GetType().FullName + ": " + exception.Message + Environment.NewLine + exception.StackTrace);
		}

		private static void Write(LogLevel level, string message)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			string text = $"[{DateTime.Now:O}] [{level}] {message ?? string.Empty}";
			LogToBepInEx(level, message ?? string.Empty);
			if (!_initialized)
			{
				return;
			}
			try
			{
				lock (SyncRoot)
				{
					File.AppendAllText(LogPath, text + Environment.NewLine);
				}
			}
			catch
			{
			}
		}

		private static void LogToBepInEx(LogLevel level, string message)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			ManualLogSource modLogger = DrawableSuitsPlugin.ModLogger;
			if (modLogger == null)
			{
				Debug.Log((object)("[DrawableSuits] " + message));
			}
			else if ((int)level != 2)
			{
				if ((int)level != 4)
				{
					if ((int)level == 32)
					{
						modLogger.LogDebug((object)message);
					}
					else
					{
						modLogger.LogInfo((object)message);
					}
				}
				else
				{
					modLogger.LogWarning((object)message);
				}
			}
			else
			{
				modLogger.LogError((object)message);
			}
		}
	}
	internal static class DrawableSuitsInput
	{
		private static bool _legacyUnavailable;

		private static bool _legacyUnavailableLogged;

		internal static bool WasKeyPressed(Key defaultKey, KeyCode configuredKey)
		{
			//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_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Key key = MapKeyCode(configuredKey, defaultKey);
			if (Keyboard.current != null)
			{
				return WasInputSystemKeyPressed(key);
			}
			return WasLegacyKeyPressedOnceGuarded(configuredKey);
		}

		internal static bool WasKeyPressed(Key key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return WasInputSystemKeyPressed(key);
		}

		internal static bool IsKeyPressed(Key key)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Keyboard current = Keyboard.current;
				return current != null && ((ButtonControl)current[key]).isPressed;
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception($"Input System key held polling failed for {key}", exception);
				return false;
			}
		}

		internal static bool TryGetMousePosition(out Vector2 position)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mouse current = Mouse.current;
				if (current != null)
				{
					position = ((InputControl<Vector2>)(object)((Pointer)current).position).ReadValue();
					return true;
				}
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Input System mouse position polling failed", exception);
			}
			position = default(Vector2);
			return false;
		}

		internal static bool IsLeftMousePressed()
		{
			return IsMouseButtonPressed((Mouse mouse) => mouse.leftButton.isPressed, "left");
		}

		internal static bool IsRightMousePressed()
		{
			return IsMouseButtonPressed((Mouse mouse) => mouse.rightButton.isPressed, "right");
		}

		internal static float MouseDeltaX()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mouse current = Mouse.current;
				return (current != null) ? ((InputControl<Vector2>)(object)((Pointer)current).delta).ReadValue().x : 0f;
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Input System mouse delta polling failed", exception);
				return 0f;
			}
		}

		internal static float MouseDeltaY()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mouse current = Mouse.current;
				return (current != null) ? ((InputControl<Vector2>)(object)((Pointer)current).delta).ReadValue().y : 0f;
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Input System mouse delta polling failed", exception);
				return 0f;
			}
		}

		internal static bool WasMouseUsedThisFrame()
		{
			//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)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mouse current = Mouse.current;
				if (current == null)
				{
					return false;
				}
				Vector2 val = ((InputControl<Vector2>)(object)((Pointer)current).delta).ReadValue();
				return ((Vector2)(ref val)).sqrMagnitude > 0.01f || current.leftButton.isPressed || current.rightButton.isPressed || Mathf.Abs(((InputControl<Vector2>)(object)current.scroll).ReadValue().y) > 0.01f;
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Input System mouse activity polling failed", exception);
				return false;
			}
		}

		internal static float MouseScrollY()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mouse current = Mouse.current;
				if (current == null)
				{
					return 0f;
				}
				float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y;
				return (Mathf.Abs(y) > 10f) ? (y / 120f) : y;
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Input System mouse scroll polling failed", exception);
				return 0f;
			}
		}

		private static bool IsMouseButtonPressed(Func<Mouse, bool> accessor, string buttonName)
		{
			try
			{
				Mouse current = Mouse.current;
				return current != null && accessor(current);
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Input System " + buttonName + " mouse button polling failed", exception);
				return false;
			}
		}

		private static bool WasInputSystemKeyPressed(Key key)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Keyboard current = Keyboard.current;
				return current != null && ((ButtonControl)current[key]).wasPressedThisFrame;
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception($"Input System key polling failed for {key}", exception);
				return false;
			}
		}

		private static bool WasLegacyKeyPressedOnceGuarded(KeyCode key)
		{
			//IL_004c: 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)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (_legacyUnavailable)
			{
				return false;
			}
			try
			{
				return Input.GetKeyDown(key);
			}
			catch (InvalidOperationException ex)
			{
				_legacyUnavailable = true;
				if (!_legacyUnavailableLogged)
				{
					_legacyUnavailableLogged = true;
					DrawableSuitsDiagnostics.Warn($"Legacy UnityEngine.Input is disabled; using Unity Input System only. First legacy failure for {key}: {ex.Message}");
				}
				return false;
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception($"Legacy key polling failed once for {key}", exception);
				return false;
			}
		}

		private unsafe static Key MapKeyCode(KeyCode keyCode, Key fallback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (TryMapSpecialKey(keyCode, out var key))
			{
				return key;
			}
			if (Enum.TryParse<Key>(((object)(*(KeyCode*)(&keyCode))/*cast due to .constrained prefix*/).ToString(), ignoreCase: true, out key))
			{
				return key;
			}
			return fallback;
		}

		private static bool TryMapSpecialKey(KeyCode keyCode, out Key key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected I4, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected I4, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected I4, but got Unknown
			if ((int)keyCode <= 27)
			{
				if ((int)keyCode <= 9)
				{
					if ((int)keyCode == 8)
					{
						key = (Key)65;
						return true;
					}
					if ((int)keyCode == 9)
					{
						key = (Key)3;
						return true;
					}
				}
				else
				{
					if ((int)keyCode == 13)
					{
						key = (Key)2;
						return true;
					}
					if ((int)keyCode == 27)
					{
						key = (Key)60;
						return true;
					}
				}
			}
			else if ((int)keyCode <= 57)
			{
				if ((int)keyCode == 32)
				{
					key = (Key)1;
					return true;
				}
				switch (keyCode - 48)
				{
				case 0:
					key = (Key)50;
					return true;
				case 1:
					key = (Key)41;
					return true;
				case 2:
					key = (Key)42;
					return true;
				case 3:
					key = (Key)43;
					return true;
				case 4:
					key = (Key)44;
					return true;
				case 5:
					key = (Key)45;
					return true;
				case 6:
					key = (Key)46;
					return true;
				case 7:
					key = (Key)47;
					return true;
				case 8:
					key = (Key)48;
					return true;
				case 9:
					key = (Key)49;
					return true;
				}
			}
			else
			{
				if ((int)keyCode == 127)
				{
					key = (Key)71;
					return true;
				}
				switch (keyCode - 273)
				{
				case 0:
					key = (Key)63;
					return true;
				case 1:
					key = (Key)64;
					return true;
				case 3:
					key = (Key)61;
					return true;
				case 2:
					key = (Key)62;
					return true;
				case 4:
					key = (Key)70;
					return true;
				case 5:
					key = (Key)68;
					return true;
				case 6:
					key = (Key)69;
					return true;
				case 7:
					key = (Key)67;
					return true;
				case 8:
					key = (Key)66;
					return true;
				}
				switch (keyCode - 303)
				{
				case 1:
					key = (Key)51;
					return true;
				case 0:
					key = (Key)52;
					return true;
				case 3:
					key = (Key)55;
					return true;
				case 2:
					key = (Key)56;
					return true;
				case 5:
					key = (Key)53;
					return true;
				case 4:
					key = (Key)54;
					return true;
				}
			}
			key = (Key)0;
			return false;
		}
	}
	internal static class DrawableSuitsPaths
	{
		public static string Root => Path.Combine(Paths.ConfigPath, "DrawableSuits");

		public static string Saves => Path.Combine(Root, "Saves");

		public static string Textures => Path.Combine(Root, "Textures");

		public static string Decals => Path.Combine(Root, "Decals");

		public static string Logs => Path.Combine(Root, "Logs");

		public static void EnsureCreated()
		{
			Directory.CreateDirectory(Root);
			Directory.CreateDirectory(Saves);
			Directory.CreateDirectory(Textures);
			Directory.CreateDirectory(Decals);
			Directory.CreateDirectory(Logs);
		}
	}
	[BepInPlugin("com.toxcgang.drawablesuits", "DrawableSuits", "0.5.77")]
	[BepInProcess("Lethal Company.exe")]
	public sealed class DrawableSuitsPlugin : BaseUnityPlugin
	{
		private static GameObject _runtimeRoot;

		private Harmony _harmony;

		internal static DrawableSuitsPlugin Instance { get; private set; }

		internal static ManualLogSource ModLogger { get; private set; }

		internal static DrawableSuitsConfig ModConfig { get; private set; }

		internal static SuitTextureRegistry Registry { get; private set; }

		internal static SuitEditorController Editor { get; private set; }

		internal static DrawableSuitsRuntimeHost RuntimeHost { get; private set; }

		internal static SuitSyncManager Sync { get; private set; }

		internal static bool IsEditorOpen
		{
			get
			{
				if ((Object)(object)Editor != (Object)null)
				{
					return Editor.IsOpenForDiagnostics;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			Instance = this;
			ModLogger = ((BaseUnityPlugin)this).Logger;
			ModConfig = new DrawableSuitsConfig(((BaseUnityPlugin)this).Config);
			DrawableSuitsPaths.EnsureCreated();
			DrawableSuitsDiagnostics.Initialize();
			string[] obj = new string[6]
			{
				"Plugin Awake. pluginInstance=",
				DescribeUnityObject((Object)(object)this),
				"; pluginGameObject=",
				DescribeUnityObject((Object)(object)((Component)this).gameObject),
				"; scene=",
				null
			};
			Scene activeScene = SceneManager.GetActiveScene();
			obj[5] = ((Scene)(ref activeScene)).name;
			DrawableSuitsDiagnostics.Info(string.Concat(obj));
			DrawableSuitsDiagnostics.Info($"Config OpenEditorKey={ModConfig.OpenEditorKey.Value}; EmergencyOpenKey={ModConfig.EmergencyOpenKey.Value}; ControllerCursorSpeed={ModConfig.ControllerCursorSpeed.Value}; MaxTextureSize={ModConfig.MaxTextureSize.Value}; MaxUndoStates={ModConfig.MaxUndoStates.Value}; NetworkSync={ModConfig.EnableNetworkSync.Value}; MaxSyncBytes={ModConfig.MaxSyncBytes.Value}; SyncChunkBytes={ModConfig.SyncChunkBytes.Value}; ExperimentalModelPreview={ModConfig.EnableExperimentalModelPreview.Value}; StartInUvFallbackMode={ModConfig.StartInUvFallbackMode.Value}; ThirdPersonCameraDistance={ModConfig.ThirdPersonCameraDistance.Value}; ApplyLocalFirstPersonArms={ModConfig.ApplyLocalFirstPersonArms.Value}");
			_harmony = new Harmony("com.toxcgang.drawablesuits");
			try
			{
				DrawableSuitsDiagnostics.Info("Applying Harmony patches.");
				_harmony.PatchAll();
				PlayerControllerBPatches.ApplyOptionalGameplayInputPatches(_harmony);
				DrawableSuitsDiagnostics.Info("Harmony patches applied.");
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Harmony PatchAll failed", exception);
				throw;
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			EnsureRuntimeReady("Plugin.Awake");
			DrawableSuitsDiagnostics.Info("DrawableSuits 0.5.77 loaded with GUID com.toxcgang.drawablesuits.");
		}

		private void Start()
		{
			DrawableSuitsDiagnostics.Info("Plugin Start. plugin=" + DescribeUnityObject((Object)(object)this) + "; host=" + DescribeUnityObject((Object)(object)RuntimeHost) + "; editor=" + DescribeUnityObject((Object)(object)Editor));
			EnsureRuntimeReady("Plugin.Start");
			SessionSafetyGuard.Run("Plugin.Start", forceLog: true);
		}

		private void Update()
		{
			EnsureRuntimeReady("Plugin.Update");
		}

		private void OnDestroy()
		{
			DrawableSuitsDiagnostics.Info("DrawableSuitsPlugin.OnDestroy called.");
			if ((Object)(object)Editor != (Object)null && Editor.IsOpenForDiagnostics)
			{
				Editor.CloseEditorForPluginDestroy();
			}
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Registry = null;
			Sync = null;
			Editor = null;
			RuntimeHost = null;
			if ((Object)(object)_runtimeRoot != (Object)null)
			{
				Object.Destroy((Object)(object)_runtimeRoot);
				_runtimeRoot = null;
			}
			if (Instance == this)
			{
				Instance = null;
			}
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0018: 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)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			DrawableSuitsDiagnostics.Info($"Scene loaded. name={((Scene)(ref scene)).name}; buildIndex={((Scene)(ref scene)).buildIndex}; mode={mode}");
			bool num = ShouldCloseEditorForScene(scene, mode);
			EnsureRuntimeReady("SceneLoaded:" + ((Scene)(ref scene)).name);
			if (num && (Object)(object)Editor != (Object)null && Editor.IsOpenForDiagnostics)
			{
				DrawableSuitsDiagnostics.Info($"Closing editor because scene changed to '{((Scene)(ref scene)).name}' with mode={mode}.");
				Editor.CloseEditorForSceneChange();
			}
			Registry?.ReapplyAllIfReady("SceneLoaded:" + ((Scene)(ref scene)).name);
			SessionSafetyGuard.Run("SceneLoaded:" + ((Scene)(ref scene)).name, forceLog: true);
		}

		internal static bool HasSessionSafetyContext()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			if (!((Object)(object)StartOfRound.Instance != (Object)null) && !((Object)(object)Object.FindObjectOfType<GameNetworkManager>()?.localPlayerController != (Object)null))
			{
				return string.Equals(name, "SampleSceneRelay", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		internal static bool HasGameplayEditorContext()
		{
			if ((Object)(object)StartOfRound.Instance?.localPlayerController != (Object)null)
			{
				return (Object)(object)Camera.main != (Object)null;
			}
			return false;
		}

		private static bool ShouldCloseEditorForScene(Scene scene, LoadSceneMode mode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)mode != 1)
			{
				return true;
			}
			if (!string.Equals(((Scene)(ref scene)).name, "MainMenu", StringComparison.OrdinalIgnoreCase) && !string.Equals(((Scene)(ref scene)).name, "InitScene", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(((Scene)(ref scene)).name, "InitSceneLaunchOptions", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		internal static bool EnsureRuntimeReady(string reason)
		{
			if ((Object)(object)Instance == (Object)null)
			{
				DrawableSuitsDiagnostics.Warn("EnsureRuntimeReady(" + reason + ") failed: plugin instance is null.");
				return false;
			}
			GameObject orCreateRuntimeRoot = GetOrCreateRuntimeRoot(reason);
			if ((Object)(object)orCreateRuntimeRoot == (Object)null)
			{
				DrawableSuitsDiagnostics.Warn("EnsureRuntimeReady(" + reason + ") failed: runtime root is null.");
				return false;
			}
			Registry = EnsureComponent<SuitTextureRegistry>(Registry, orCreateRuntimeRoot, reason, "registry");
			Sync = EnsureComponent<SuitSyncManager>(Sync, orCreateRuntimeRoot, reason, "sync");
			Editor = EnsureComponent<SuitEditorController>(Editor, orCreateRuntimeRoot, reason, "editor");
			RuntimeHost = EnsureComponent<DrawableSuitsRuntimeHost>(RuntimeHost, orCreateRuntimeRoot, reason, "runtime host");
			bool flag = (Object)(object)Registry != (Object)null && (Object)(object)Sync != (Object)null && (Object)(object)Editor != (Object)null && (Object)(object)RuntimeHost != (Object)null;
			if (!flag)
			{
				DrawableSuitsDiagnostics.Warn("EnsureRuntimeReady(" + reason + ") incomplete. registry=" + DescribeUnityObject((Object)(object)Registry) + "; sync=" + DescribeUnityObject((Object)(object)Sync) + "; editor=" + DescribeUnityObject((Object)(object)Editor) + "; host=" + DescribeUnityObject((Object)(object)RuntimeHost));
			}
			return flag;
		}

		private static GameObject GetOrCreateRuntimeRoot(string reason)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if ((Object)(object)_runtimeRoot != (Object)null)
			{
				return _runtimeRoot;
			}
			_runtimeRoot = new GameObject("DrawableSuitsRuntimeRoot");
			((Object)_runtimeRoot).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)_runtimeRoot);
			DrawableSuitsDiagnostics.Info("Runtime root created. reason=" + reason + "; root=" + DescribeUnityObject((Object)(object)_runtimeRoot));
			return _runtimeRoot;
		}

		internal static bool RequestOpenEditor(string source)
		{
			bool flag = EnsureRuntimeReady("RequestOpenEditor:" + source);
			DrawableSuitsDiagnostics.Info($"RequestOpenEditor source={source}; runtimeReady={flag}; editor={DescribeUnityObject((Object)(object)Editor)}");
			if (!flag || (Object)(object)Editor == (Object)null)
			{
				return false;
			}
			bool flag2 = Editor.OpenEditor(source);
			DrawableSuitsDiagnostics.Info($"RequestOpenEditor result source={source}; opened={flag2}; editorOpen={Editor.IsOpenForDiagnostics}; canvasActive={Editor.CanvasActiveForDiagnostics}");
			return flag2;
		}

		internal static bool RequestToggleEditor(string source)
		{
			bool flag = EnsureRuntimeReady("RequestToggleEditor:" + source);
			DrawableSuitsDiagnostics.Info($"RequestToggleEditor source={source}; runtimeReady={flag}; editor={DescribeUnityObject((Object)(object)Editor)}");
			if (!flag || (Object)(object)Editor == (Object)null)
			{
				return false;
			}
			if (!Editor.IsOpenForDiagnostics)
			{
				return RequestOpenEditor(source);
			}
			return CloseEditor(source);
		}

		internal static bool CloseEditor(string source)
		{
			EnsureRuntimeReady("CloseEditor:" + source);
			if ((Object)(object)Editor == (Object)null)
			{
				DrawableSuitsDiagnostics.Warn("CloseEditor source=" + source + " ignored because editor is null.");
				return false;
			}
			DrawableSuitsDiagnostics.Info("CloseEditor source=" + source + "; editor=" + DescribeUnityObject((Object)(object)Editor));
			Editor.CloseEditor(source);
			return true;
		}

		internal static string DescribeUnityObject(Object unityObject)
		{
			if (unityObject == (Object)null)
			{
				return "null";
			}
			return $"{((object)unityObject).GetType().Name}(id={unityObject.GetInstanceID()}, name={unityObject.name})";
		}

		private static T EnsureComponent<T>(T current, GameObject hostObject, string reason, string label) where T : Component
		{
			if ((Object)(object)current != (Object)null)
			{
				return current;
			}
			T component = hostObject.GetComponent<T>();
			if ((Object)(object)component != (Object)null)
			{
				DrawableSuitsDiagnostics.Info("EnsureRuntimeReady(" + reason + ") recovered existing " + label + ": " + DescribeUnityObject((Object)(object)component));
				return component;
			}
			T val = hostObject.AddComponent<T>();
			DrawableSuitsDiagnostics.Info("EnsureRuntimeReady(" + reason + ") created " + label + ": " + DescribeUnityObject((Object)(object)val) + " on " + DescribeUnityObject((Object)(object)hostObject));
			return val;
		}
	}
	internal sealed class DrawableSuitsRuntimeHost : MonoBehaviour
	{
		private bool _firstUpdateLogged;

		private bool _controllerOpenChordWasHeld;

		private void Awake()
		{
			DrawableSuitsDiagnostics.Info("RuntimeHost Awake. host=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)this) + "; gameObject=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)((Component)this).gameObject));
		}

		private void Start()
		{
			DrawableSuitsDiagnostics.Info("RuntimeHost Start. editor=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)DrawableSuitsPlugin.Editor));
		}

		private void Update()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!_firstUpdateLogged)
			{
				_firstUpdateLogged = true;
				object arg = Time.frameCount;
				Scene activeScene = SceneManager.GetActiveScene();
				DrawableSuitsDiagnostics.Info($"RuntimeHost first Update. frame={arg}; scene={((Scene)(ref activeScene)).name}; editor={DrawableSuitsPlugin.DescribeUnityObject((Object)(object)DrawableSuitsPlugin.Editor)}");
			}
			DrawableSuitsPlugin.EnsureRuntimeReady("RuntimeHost.Update");
			HandleInput();
		}

		private void HandleInput()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (DrawableSuitsInput.WasKeyPressed((Key)103, DrawableSuitsPlugin.ModConfig.EmergencyOpenKey.Value))
			{
				DrawableSuitsDiagnostics.Info("RuntimeHost F10 emergency open. editor=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)DrawableSuitsPlugin.Editor));
				DrawableSuitsPlugin.RequestOpenEditor("F10Emergency");
			}
			if (DrawableSuitsInput.WasKeyPressed((Key)101, DrawableSuitsPlugin.ModConfig.OpenEditorKey.Value))
			{
				DrawableSuitsDiagnostics.Info("RuntimeHost F8 toggle. editor=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)DrawableSuitsPlugin.Editor));
				RequestGameplayToggle("F8Keyboard");
			}
			if (WasControllerOpenChordPressed())
			{
				DrawableSuitsDiagnostics.Info("RuntimeHost controller open chord. editor=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)DrawableSuitsPlugin.Editor));
				RequestGameplayToggle("ControllerViewBackY");
			}
		}

		private static void RequestGameplayToggle(string source)
		{
			SuitEditorController editor = DrawableSuitsPlugin.Editor;
			if (editor != null && editor.IsOpenForDiagnostics)
			{
				DrawableSuitsPlugin.RequestToggleEditor(source);
			}
			else if (!DrawableSuitsPlugin.HasGameplayEditorContext())
			{
				DrawableSuitsDiagnostics.Info("RuntimeHost ignored " + source + " open because no gameplay player/camera context is available. Use F10 for diagnostics.");
			}
			else
			{
				DrawableSuitsPlugin.RequestToggleEditor(source);
			}
		}

		private bool WasControllerOpenChordPressed()
		{
			Gamepad current = Gamepad.current;
			if (current == null)
			{
				_controllerOpenChordWasHeld = false;
				return false;
			}
			ButtonControl val = current.selectButton ?? ((InputControl)current).TryGetChildControl<ButtonControl>("backButton");
			bool flag = val != null && val.isPressed && current.buttonNorth.isPressed;
			bool result = flag && !_controllerOpenChordWasHeld;
			_controllerOpenChordWasHeld = flag;
			return result;
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("LoadUnlockables")]
		private static void LoadUnlockablesPostfix()
		{
			RunPatch("StartOfRound.LoadUnlockables", delegate
			{
				DrawableSuitsPlugin.Registry?.ReapplyAllIfReady("StartOfRound.LoadUnlockables");
				SessionSafetyGuard.Run("StartOfRound.LoadUnlockables", forceLog: true);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("PositionSuitsOnRack")]
		private static void PositionSuitsOnRackPostfix()
		{
			RunPatch("StartOfRound.PositionSuitsOnRack", delegate
			{
				DrawableSuitsPlugin.Registry?.ReapplyAllIfReady("StartOfRound.PositionSuitsOnRack");
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("SyncSuitsClientRpc")]
		private static void SyncSuitsClientRpcPostfix()
		{
			RunPatch("StartOfRound.SyncSuitsClientRpc", delegate
			{
				DrawableSuitsPlugin.Registry?.ReapplyAllIfReady("StartOfRound.SyncSuitsClientRpc");
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnPlayerConnectedClientRpc")]
		private static void OnPlayerConnectedClientRpcPostfix()
		{
			RunPatch("StartOfRound.OnPlayerConnectedClientRpc", delegate
			{
				DrawableSuitsPlugin.Registry?.ReapplyAllIfReady("StartOfRound.OnPlayerConnectedClientRpc");
				SessionSafetyGuard.Run("StartOfRound.OnPlayerConnectedClientRpc", forceLog: true);
				DrawableSuitsPlugin.Sync?.RequestActiveDesigns();
			});
		}

		private static void RunPatch(string context, Action action)
		{
			try
			{
				DrawableSuitsPlugin.EnsureRuntimeReady(context);
				action();
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Patch failed: " + context, exception);
			}
		}
	}
	[HarmonyPatch(typeof(UnlockableSuit))]
	internal static class UnlockableSuitPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("SwitchSuitForPlayer")]
		private static void SwitchSuitForPlayerPostfix(PlayerControllerB player)
		{
			RunPatch("UnlockableSuit.SwitchSuitForPlayer", delegate
			{
				DrawableSuitsPlugin.Registry?.RecordPlayerSuitSnapshot(player, "UnlockableSuit.SwitchSuitForPlayer");
				DrawableSuitsPlugin.Registry?.ApplyToPlayer(player);
				DrawableSuitsPlugin.Registry?.ScheduleReapplyAll("UnlockableSuit.SwitchSuitForPlayer");
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("SwitchSuitForAllPlayers")]
		private static void SwitchSuitForAllPlayersPostfix()
		{
			RunPatch("UnlockableSuit.SwitchSuitForAllPlayers", delegate
			{
				DrawableSuitsPlugin.Registry?.ReapplyAllIfReady("UnlockableSuit.SwitchSuitForAllPlayers");
			});
		}

		private static void RunPatch(string context, Action action)
		{
			try
			{
				DrawableSuitsPlugin.EnsureRuntimeReady(context);
				action();
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Patch failed: " + context, exception);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal static class PlayerControllerBPatches
	{
		private static readonly string[] OptionalBlockedInputMethods = new string[25]
		{
			"ScrollMouse_performed", "ScrollMouse_canceled", "SwitchItem_performed", "SwitchItem_canceled", "NextItem_performed", "PreviousItem_performed", "Scan_performed", "PingScan_performed", "ItemPrimaryUse_performed", "ItemInteract_performed",
			"ItemSecondaryUse_performed", "ItemTertiaryUse_performed", "ActivateItem_performed", "ActivateItem_canceled", "Discard_performed", "Crouch_performed", "InspectItem_performed", "UseUtilitySlot_performed", "Emote1_performed", "Emote2_performed",
			"SetFreeCamera_performed", "SpeedCheat_performed", "BuildMode_performed", "ConfirmBuildMode_performed", "Delete_performed"
		};

		private static readonly HashSet<string> OptionalPatchedMethods = new HashSet<string>(StringComparer.Ordinal);

		private static float _lastBlockedInputLogTime;

		private static string _lastBlockedInputMethod;

		internal static void ApplyOptionalGameplayInputPatches(Harmony harmony)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			if (harmony == null)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerControllerBPatches), "OptionalGameplayInputPrefix", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				DrawableSuitsDiagnostics.Warn("Optional gameplay input prefix was not found; scan/inventory fallback patches were not applied.");
				return;
			}
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			for (int i = 0; i < OptionalBlockedInputMethods.Length; i++)
			{
				string text = OptionalBlockedInputMethods[i];
				if (OptionalPatchedMethods.Contains(text))
				{
					continue;
				}
				MethodInfo methodInfo2 = null;
				try
				{
					methodInfo2 = AccessTools.Method(typeof(PlayerControllerB), text, (Type[])null, (Type[])null);
				}
				catch (Exception exception)
				{
					DrawableSuitsDiagnostics.Exception("Optional PlayerControllerB input method lookup failed for " + text, exception);
					list2.Add(text);
					continue;
				}
				if (methodInfo2 == null)
				{
					list2.Add(text);
					continue;
				}
				try
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					OptionalPatchedMethods.Add(text);
					list.Add(text);
				}
				catch (Exception exception2)
				{
					DrawableSuitsDiagnostics.Exception("Failed to apply optional PlayerControllerB input block for " + text, exception2);
				}
			}
			DrawableSuitsDiagnostics.Info("Optional gameplay input patches applied. patched=[" + string.Join(", ", list) + "]; missing=[" + string.Join(", ", list2) + "]");
		}

		[HarmonyPostfix]
		[HarmonyPatch("ConnectClientToPlayerObject")]
		private static void ConnectClientToPlayerObjectPostfix(PlayerControllerB __instance)
		{
			RunPatch("PlayerControllerB.ConnectClientToPlayerObject", delegate
			{
				DrawableSuitsPlugin.Registry?.RecordPlayerSuitSnapshot(__instance, "PlayerControllerB.ConnectClientToPlayerObject");
				DrawableSuitsPlugin.Registry?.ApplyToPlayer(__instance);
				DrawableSuitsPlugin.Registry?.ScheduleReapplyAll("PlayerControllerB.ConnectClientToPlayerObject");
				SessionSafetyGuard.Run("PlayerControllerB.ConnectClientToPlayerObject", forceLog: true);
				DrawableSuitsPlugin.Sync?.RequestActiveDesigns();
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("SpawnPlayerAnimation")]
		private static void SpawnPlayerAnimationPostfix(PlayerControllerB __instance)
		{
			RunPatch("PlayerControllerB.SpawnPlayerAnimation", delegate
			{
				DrawableSuitsPlugin.Registry?.RecordPlayerSuitSnapshot(__instance, "PlayerControllerB.SpawnPlayerAnimation");
				DrawableSuitsPlugin.Registry?.ApplyToPlayer(__instance);
				DrawableSuitsPlugin.Registry?.ScheduleReapplyAll("PlayerControllerB.SpawnPlayerAnimation");
				SessionSafetyGuard.Run("PlayerControllerB.SpawnPlayerAnimation", forceLog: true);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("SpawnDeadBody", new Type[]
		{
			typeof(int),
			typeof(Vector3),
			typeof(int),
			typeof(PlayerControllerB),
			typeof(int),
			typeof(Transform),
			typeof(Transform),
			typeof(Vector3)
		})]
		private static void SpawnDeadBodyPostfix(int playerId, PlayerControllerB deadPlayerController)
		{
			RunPatch("PlayerControllerB.SpawnDeadBody", delegate
			{
				DrawableSuitsPlugin.Registry?.RecordPlayerSuitSnapshot(deadPlayerController, "PlayerControllerB.SpawnDeadBody");
				DeadBodyInfo val = deadPlayerController?.deadBody;
				if ((Object)(object)val != (Object)null)
				{
					DrawableSuitsPlugin.Registry?.ApplyToDeadBody(val, "PlayerControllerB.SpawnDeadBody:deadPlayerController.deadBody");
					DrawableSuitsPlugin.Registry?.ScheduleDeadBodyReapply(val, "PlayerControllerB.SpawnDeadBody:deadPlayerController.deadBody");
					DrawableSuitsDiagnostics.Info($"DeadBodySuitSpawnPatch: playerId={playerId}; exactBody={((Object)val).name}; deadPlayer={DrawableSuitsPlugin.DescribeUnityObject((Object)(object)deadPlayerController)}");
				}
				else
				{
					DeadBodyInfo[] array = Object.FindObjectsOfType<DeadBodyInfo>();
					int num = 0;
					if (array != null)
					{
						foreach (DeadBodyInfo val2 in array)
						{
							if (!((Object)(object)val2 == (Object)null) && val2.playerObjectId == playerId)
							{
								DrawableSuitsPlugin.Registry?.ApplyToDeadBody(val2, "PlayerControllerB.SpawnDeadBody");
								DrawableSuitsPlugin.Registry?.ScheduleDeadBodyReapply(val2, "PlayerControllerB.SpawnDeadBody");
								num++;
							}
						}
					}
					DrawableSuitsDiagnostics.Info($"DeadBodySuitSpawnPatch: playerId={playerId}; matchedBodies={num}; deadPlayer={DrawableSuitsPlugin.DescribeUnityObject((Object)(object)deadPlayerController)}");
				}
			});
		}

		[HarmonyPrefix]
		[HarmonyPatch("Jump_performed")]
		private static bool JumpPerformedPrefix(PlayerControllerB __instance)
		{
			return AllowGameplayInput("Jump_performed", __instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("Interact_performed")]
		private static bool InteractPerformedPrefix(PlayerControllerB __instance)
		{
			return AllowGameplayInput("Interact_performed", __instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("QEItemInteract_performed")]
		private static bool QeItemInteractPerformedPrefix(PlayerControllerB __instance)
		{
			return AllowGameplayInput("QEItemInteract_performed", __instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("Look_performed")]
		private static bool LookPerformedPrefix(PlayerControllerB __instance)
		{
			return AllowGameplayInput("Look_performed", __instance);
		}

		private static bool OptionalGameplayInputPrefix(PlayerControllerB __instance, MethodBase __originalMethod)
		{
			return AllowGameplayInput(__originalMethod?.Name ?? "OptionalGameplayInput", __instance);
		}

		private static void RunPatch(string context, Action action)
		{
			try
			{
				DrawableSuitsPlugin.EnsureRuntimeReady(context);
				action();
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Patch failed: " + context, exception);
			}
		}

		private static bool AllowGameplayInput(string method, PlayerControllerB player)
		{
			if (!DrawableSuitsPlugin.IsEditorOpen)
			{
				return true;
			}
			if (Time.unscaledTime - _lastBlockedInputLogTime > 0.75f || !string.Equals(_lastBlockedInputMethod, method, StringComparison.Ordinal))
			{
				_lastBlockedInputLogTime = Time.unscaledTime;
				_lastBlockedInputMethod = method;
				DrawableSuitsDiagnostics.Info("Blocked PlayerControllerB." + method + " while DrawableSuits editor is open. player=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)player));
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(DeadBodyInfo))]
	internal static class DeadBodyInfoPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("ChangeMesh")]
		private static void ChangeMeshPrefix(DeadBodyInfo __instance, ref Material changeMaterial)
		{
			try
			{
				DrawableSuitsPlugin.EnsureRuntimeReady("DeadBodyInfo.ChangeMesh.prefix");
				if ((Object)(object)DrawableSuitsPlugin.Registry != (Object)null && DrawableSuitsPlugin.Registry.TryGetDeadBodyRuntimeMaterial(__instance, "DeadBodyInfo.ChangeMesh.prefix", out var material, out var reason))
				{
					string text = (((Object)(object)changeMaterial != (Object)null) ? ((Object)changeMaterial).name : "null");
					changeMaterial = material;
					DrawableSuitsDiagnostics.Info("DeadBodySuitMaterialSubstituted: context=DeadBodyInfo.ChangeMesh.prefix; previousMaterial=" + text + "; newMaterial=" + ((Object)material).name + "; reason=" + reason + "; body=" + DrawableSuitsPlugin.DescribeUnityObject((Object)(object)__instance));
				}
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Patch failed: DeadBodyInfo.ChangeMesh.prefix", exception);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(DeadBodyInfo __instance)
		{
			RunPatch("DeadBodyInfo.Start", __instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch("ChangeMesh")]
		private static void ChangeMeshPostfix(DeadBodyInfo __instance)
		{
			RunPatch("DeadBodyInfo.ChangeMesh", __instance);
		}

		private static void RunPatch(string context, DeadBodyInfo body)
		{
			try
			{
				DrawableSuitsPlugin.EnsureRuntimeReady(context);
				DrawableSuitsPlugin.Registry?.ApplyToDeadBody(body, context);
				DrawableSuitsPlugin.Registry?.ScheduleDeadBodyReapply(body, context);
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Patch failed: " + context, exception);
			}
		}
	}
	[HarmonyPatch(typeof(QuickMenuManager))]
	internal static class QuickMenuManagerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(QuickMenuManager __instance)
		{
			RunPatch("QuickMenuManager.Start", delegate
			{
				PauseMenuButtonInjector.EnsureButton(__instance);
			});
		}

		[HarmonyPostfix]
		[HarmonyPatch("OpenQuickMenu")]
		private static void OpenQuickMenuPostfix(QuickMenuManager __instance)
		{
			RunPatch("QuickMenuManager.OpenQuickMenu", delegate
			{
				PauseMenuButtonInjector.EnsureButton(__instance);
				PauseMenuButtonInjector.SelectIfNeeded(__instance);
			});
		}

		private static void RunPatch(string context, Action action)
		{
			try
			{
				DrawableSuitsPlugin.EnsureRuntimeReady(context);
				action();
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Patch failed: " + context, exception);
			}
		}
	}
	internal static class PauseMenuButtonInjector
	{
		private sealed class MenuRow
		{
			public GameObject GameObject { get; }

			public RectTransform RectTransform { get; }

			public Button Button { get; }

			public string LabelText { get; }

			public bool IsDrawable
			{
				get
				{
					if (!(((Object)GameObject).name == "DrawableSuitsButton"))
					{
						return Normalize(LabelText).Contains("drawablesuits");
					}
					return true;
				}
			}

			public MenuRow(GameObject gameObject, RectTransform rectTransform, Button button, string labelText)
			{
				GameObject = gameObject;
				RectTransform = rectTransform;
				Button = button;
				LabelText = labelText ?? string.Empty;
			}
		}

		private const string ButtonName = "DrawableSuitsButton";

		private const string ButtonText = "DrawableSuits";

		private const string ButtonTextWithInlinePrefix = "> DrawableSuits";

		private const string PrefixText = ">";

		private const float MinimumRowSpacing = 36f;

		private const float FallbackRowSpacing = 92f;

		public static void EnsureButton(QuickMenuManager quickMenu)
		{
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)quickMenu == (Object)null || (Object)(object)quickMenu.mainButtonsPanel == (Object)null)
			{
				DrawableSuitsDiagnostics.Warn($"EnsureButton skipped. quickMenuNull={(Object)(object)quickMenu == (Object)null}; mainButtonsPanelNull={(Object)(object)quickMenu?.mainButtonsPanel == (Object)null}");
				return;
			}
			RectTransform component = quickMenu.mainButtonsPanel.GetComponent<RectTransform>();
			if ((Object)(object)component == (Object)null)
			{
				DrawableSuitsDiagnostics.Warn("EnsureButton skipped because QuickMenuManager.mainButtonsPanel has no RectTransform.");
				return;
			}
			List<MenuRow> list = CollectRows((Transform)(object)component);
			DrawableSuitsDiagnostics.Info($"EnsureButton started. menuOpen={quickMenu.isMenuOpen}; panel={((Object)component).name}; rowsFound={list.Count}; labels=[{DescribeRows(list)}]");
			MenuRow menuRow = ChooseTemplateRow(list);
			DrawableSuitsDiagnostics.Info("Pause-menu DrawableSuits template selected: label=" + (menuRow?.LabelText ?? "none") + "; object=" + (((menuRow != null) ? ((Object)menuRow.GameObject).name : null) ?? "none") + "; sibling=" + (((menuRow != null) ? ((Transform)menuRow.RectTransform).GetSiblingIndex().ToString() : null) ?? "none"));
			GameObject val = FindExistingButton((Transform)(object)component);
			if ((Object)(object)val != (Object)null && menuRow != null)
			{
				DrawableSuitsDiagnostics.Info("Replacing existing DrawableSuits pause button with a fresh clone so native prefix/arrow children match the current menu template.");
				val.SetActive(false);
				Object.Destroy((Object)(object)val);
				val = null;
			}
			if ((Object)(object)val == (Object)null)
			{
				DrawableSuitsDiagnostics.Info("No existing DrawableSuits pause button. template=" + ((menuRow != null) ? (menuRow.LabelText + "/" + ((Object)menuRow.GameObject).name) : "none") + ".");
				val = ((menuRow != null) ? CloneTemplate(menuRow) : CreateFallbackButton((Transform)(object)component));
			}
			else
			{
				DrawableSuitsDiagnostics.Info($"Reusing existing DrawableSuits pause button. active={val.activeSelf}; siblingIndex={val.transform.GetSiblingIndex()}");
			}
			if ((Object)(object)val == (Object)null)
			{
				DrawableSuitsDiagnostics.Warn("Could not create pause-menu DrawableSuits button.");
				return;
			}
			RemoveDuplicateButtons((Transform)(object)component, val);
			ConfigureButton(val, quickMenu, menuRow);
			PlaceButtonAndRows(component, val);
			RebuildNavigation(component);
			RectTransform component2 = val.GetComponent<RectTransform>();
			Button component3 = val.GetComponent<Button>();
			DrawableSuitsDiagnostics.Info(string.Format("EnsureButton complete. exists={0}; active={1}; anchoredPosition={2}; siblingIndex={3}; nav={4}; colors={5}; rowsAfter={6}", (Object)(object)val != (Object)null, val.activeSelf, ((component2 != null) ? ((object)component2.anchoredPosition/*cast due to .constrained prefix*/).ToString() : null) ?? "null", val.transform.GetSiblingIndex(), DescribeNavigation(component3), DescribeButtonColors(component3), CollectRows((Transform)(object)component).Count));
		}

		public static void SelectIfNeeded(QuickMenuManager quickMenu)
		{
			if (!((Object)(object)quickMenu == (Object)null) && quickMenu.isMenuOpen && !((Object)(object)quickMenu.mainButtonsPanel == (Object)null) && !((Object)(object)EventSystem.current == (Object)null) && !((Object)(object)EventSystem.current.currentSelectedGameObject != (Object)null))
			{
				List<MenuRow> rowsInVisualOrder = GetRowsInVisualOrder(quickMenu.mainButtonsPanel.GetComponent<RectTransform>());
				if (rowsInVisualOrder.Count > 0)
				{
					EventSystem.current.SetSelectedGameObject(rowsInVisualOrder[0].GameObject);
				}
			}
		}

		private static GameObject FindExistingButton(Transform panel)
		{
			Button[] componentsInChildren = ((Component)panel).GetComponentsInChildren<Button>(true);
			foreach (Button val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name == "DrawableSuitsButton")
				{
					return ((Component)val).gameObject;
				}
			}
			return null;
		}

		private static void RemoveDuplicateButtons(Transform panel, GameObject keep)
		{
			Button[] componentsInChildren = ((Component)panel).GetComponentsInChildren<Button>(true);
			foreach (Button val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)(object)keep) && !(((Object)((Component)val).gameObject).name != "DrawableSuitsButton"))
				{
					((Component)val).gameObject.SetActive(false);
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
		}

		private static GameObject CloneTemplate(MenuRow template)
		{
			//IL_0065: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Object.Instantiate<GameObject>(template.GameObject, ((Transform)template.RectTransform).parent, false);
			((Object)obj).name = "DrawableSuitsButton";
			obj.transform.SetAsLastSibling();
			obj.SetActive(true);
			DrawableSuitsDiagnostics.Info("Cloned pause-menu template '" + template.LabelText + "' into DrawableSuitsButton.");
			RectTransform component = obj.GetComponent<RectTransform>();
			if ((Object)(object)component != (Object)null)
			{
				component.anchorMin = template.RectTransform.anchorMin;
				component.anchorMax = template.RectTransform.anchorMax;
				component.pivot = template.RectTransform.pivot;
				component.sizeDelta = template.RectTransform.sizeDelta;
				((Transform)component).localScale = ((Transform)template.RectTransform).localScale;
			}
			return obj;
		}

		private static GameObject CreateFallbackButton(Transform panel)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0084: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("DrawableSuitsButton", new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(Button),
				typeof(LayoutElement)
			});
			val.transform.SetParent(panel, false);
			val.transform.SetAsLastSibling();
			DrawableSuitsDiagnostics.Warn("Created fallback pause-menu DrawableSuits button because no cloneable row template was found.");
			val.GetComponent<RectTransform>().sizeDelta = new Vector2(260f, 54f);
			((Graphic)val.GetComponent<Image>()).color = new Color(0.08f, 0.08f, 0.08f, 0.86f);
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.preferredWidth = 260f;
			component.preferredHeight = 54f;
			component.minHeight = 42f;
			GameObject val2 = new GameObject("Label", new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			val2.transform.SetParent(val.transform, false);
			RectTransform component2 = val2.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = new Vector2(8f, 2f);
			component2.offsetMax = new Vector2(-8f, -2f);
			TextMeshProUGUI component3 = val2.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component3).alignment = (TextAlignmentOptions)514;
			((TMP_Text)component3).fontSize = 24f;
			((Graphic)component3).color = Color.white;
			TextMeshProUGUI componentInChildren = ((Component)panel).GetComponentInChildren<TextMeshProUGUI>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((TMP_Text)component3).font = ((TMP_Text)componentInChildren).font;
				((TMP_Text)component3).fontSharedMaterial = ((TMP_Text)componentInChildren).fontSharedMaterial;
				((TMP_Text)component3).fontSize = ((TMP_Text)componentInChildren).fontSize;
				((Graphic)component3).color = ((Graphic)componentInChildren).color;
			}
			return val;
		}

		private static void ConfigureButton(GameObject buttonObject, QuickMenuManager quickMenu, MenuRow template)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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)
			((Object)buttonObject).name = "DrawableSuitsButton";
			buttonObject.SetActive(true);
			if (template != null)
			{
				ApplyTemplateStyle(template, buttonObject);
			}
			SetButtonText(buttonObject, template?.LabelText);
			EnsureNativePrefix(buttonObject, template);
			Button val = buttonObject.GetComponent<Button>() ?? buttonObject.AddComponent<Button>();
			((Selectable)val).interactable = true;
			val.onClick = new ButtonClickedEvent();
			((UnityEvent)val.onClick).AddListener((UnityAction)delegate
			{
				OpenEditorFromPauseMenu(quickMenu);
			});
			DrawableSuitsDiagnostics.Info($"Configured pause-menu button listener. button={((Object)buttonObject).name}; interactable={((Selectable)val).interactable}; targetQuickMenuNull={(Object)(object)quickMenu == (Object)null}");
			Navigation navigation = ((Selectable)val).navigation;
			((Navigation)(ref navigation)).mode = (Mode)3;
			((Selectable)val).navigation = navigation;
		}

		private static void ApplyTemplateStyle(MenuRow template, GameObject buttonObject)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = buttonObject.GetComponent<RectTransform>();
			if ((Object)(object)component != (Object)null)
			{
				CopyRectTemplate(template.RectTransform, component);
			}
			Button button = template.Button;
			Button val = buttonObject.GetComponent<Button>() ?? buttonObject.AddComponent<Button>();
			((Selectable)val).transition = ((Selectable)button).transition;
			((Selectable)val).colors = ((Selectable)button).colors;
			((Selectable)val).spriteState = ((Selectable)button).spriteState;
			((Selectable)val).animationTriggers = ((Selectable)button).animationTriggers;
			((Selectable)val).targetGraphic = FindMatchingGraphic(((Selectable)button).targetGraphic, template.GameObject.transform, buttonObject.transform) ?? buttonObject.GetComponent<Graphic>() ?? buttonObject.GetComponentInChildren<Graphic>(true);
			Image component2 = template.GameObject.GetComponent<Image>();
			Image component3 = buttonObject.GetComponent<Image>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null)
			{
				component3.sprite = component2.sprite;
				component3.overrideSprite = component2.overrideSprite;
				component3.type = component2.type;
				component3.preserveAspect = component2.preserveAspect;
				component3.fillCenter = component2.fillCenter;
				component3.fillMethod = component2.fillMethod;
				component3.fillAmount = component2.fillAmount;
				component3.fillClockwise = component2.fillClockwise;
				component3.fillOrigin = component2.fillOrigin;
				((Graphic)component3).color = ((Graphic)component2).color;
				((Graphic)component3).material = ((Graphic)component2).material;
				((Graphic)component3).raycastTarget = ((Graphic)component2).raycastTarget;
			}
			LayoutElement component4 = template.GameObject.GetComponent<LayoutElement>();
			LayoutElement val2 = buttonObject.GetComponent<LayoutElement>();
			if ((Object)(object)component4 != (Object)null)
			{
				if (val2 == null)
				{
					val2 = buttonObject.AddComponent<LayoutElement>();
				}
				val2.ignoreLayout = component4.ignoreLayout;
				val2.minWidth = component4.minWidth;
				val2.minHeight = component4.minHeight;
				val2.preferredWidth = component4.preferredWidth;
				val2.preferredHeight = component4.preferredHeight;
				val2.flexibleWidth = component4.flexibleWidth;
				val2.flexibleHeight = component4.flexibleHeight;
				val2.layoutPriority = component4.layoutPriority;
			}
			DrawableSuitsDiagnostics.Info("Applied pause-menu template style. template=" + template.LabelText + "/" + ((Object)template.GameObject).name + "; target=" + ((Object)buttonObject).name + "; colors=" + DescribeButtonColors(val));
		}

		private static void SetButtonText(GameObject buttonObject, string templateLabelText)
		{
			TextMeshProUGUI[] componentsInChildren = buttonObject.GetComponentsInChildren<TextMeshProUGUI>(true);
			TextMeshProUGUI val = FindPrimaryTmpLabel(componentsInChildren, templateLabelText);
			List<string> list = new List<string>();
			TextMeshProUGUI[] array = componentsInChildren;
			foreach (TextMeshProUGUI val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					if ((Object)(object)val2 == (Object)(object)val)
					{
						((TMP_Text)val2).text = "DrawableSuits";
						((TMP_Text)val2).enableWordWrapping = false;
					}
					else
					{
						list.Add(((TMP_Text)val2).text ?? string.Empty);
					}
				}
			}
			Text[] componentsInChildren2 = buttonObject.GetComponentsInChildren<Text>(true);
			Text val3 = (((Object)(object)val == (Object)null) ? FindPrimaryLegacyLabel(componentsInChildren2, templateLabelText) : null);
			Text[] array2 = componentsInChildren2;
			foreach (Text val4 in array2)
			{
				if (!((Object)(object)val4 == (Object)null))
				{
					if ((Object)(object)val4 == (Object)(object)val3)
					{
						val4.text = "DrawableSuits";
					}
					else
					{
						list.Add(val4.text ?? string.Empty);
					}
				}
			}
			DrawableSuitsDiagnostics.Info("Pause-menu DrawableSuits text configured. templateLabel=" + (templateLabelText ?? "none") + "; primaryTmp=" + DescribeTmpLabel(val) + "; primaryLegacy=" + DescribeLegacyLabel(val3) + "; preserved=[" + string.Join(", ", list) + "]");
		}

		private static void EnsureNativePrefix(GameObject buttonObject, MenuRow template)
		{
			TextMeshProUGUI val = FindPrefixText(buttonObject);
			if ((Object)(object)val != (Object)null)
			{
				TextMeshProUGUI label = FindPrimaryTmpLabel(buttonObject.GetComponentsInChildren<TextMeshProUGUI>(true), "DrawableSuits");
				DrawableSuitsDiagnostics.Info($"PauseMenuPrefixMode mode=PreservedChild; prefix={((Object)((Component)val).gameObject).name}; prefixText='{((TMP_Text)val).text}'; primary={DescribeTmpLabel(label)}; rowRect={DescribeRect(buttonObject.GetComponent<RectTransform>())}; sibling={buttonObject.transform.GetSiblingIndex()}");
				return;
			}
			Text val2 = FindPrefixLegacyText(buttonObject);
			if ((Object)(object)val2 != (Object)null)
			{
				Text label2 = FindPrimaryLegacyLabel(buttonObject.GetComponentsInChildren<Text>(true), "DrawableSuits");
				DrawableSuitsDiagnostics.Info($"PauseMenuPrefixMode mode=PreservedChild; prefix={((Object)((Component)val2).gameObject).name}; prefixText='{val2.text}'; primary={DescribeLegacyLabel(label2)}; rowRect={DescribeRect(buttonObject.GetComponent<RectTransform>())}; sibling={buttonObject.transform.GetSiblingIndex()}");
				return;
			}
			TextMeshProUGUI val3 = FindPrimaryTmpLabel(buttonObject.GetComponentsInChildren<TextMeshProUGUI>(true), "DrawableSuits");
			if ((Object)(object)val3 != (Object)null)
			{
				((TMP_Text)val3).text = "> DrawableSuits";
				((TMP_Text)val3).enableWordWrapping = false;
				DrawableSuitsDiagnostics.Info($"PauseMenuPrefixMode mode=InlineLabel; displayed='{((TMP_Text)val3).text}'; primary={DescribeTmpLabel(val3)}; rowRect={DescribeRect(buttonObject.GetComponent<RectTransform>())}; sibling={buttonObject.transform.GetSiblingIndex()}");
				return;
			}
			Text val4 = FindPrimaryLegacyLabel(buttonObject.GetComponentsInChildren<Text>(true), "DrawableSuits");
			if ((Object)(object)val4 != (Object)null)
			{
				val4.text = "> DrawableSuits";
				DrawableSuitsDiagnostics.Info($"PauseMenuPrefixMode mode=InlineLabel; displayed='{val4.text}'; primary={DescribeLegacyLabel(val4)}; rowRect={DescribeRect(buttonObject.GetComponent<RectTransform>())}; sibling={buttonObject.transform.GetSiblingIndex()}");
			}
			else
			{
				DrawableSuitsDiagnostics.Warn(string.Format("PauseMenuPrefixMode mode=SkippedNoPrimaryLabel; template={0}; button={1}; rowRect={2}; sibling={3}", template?.LabelText ?? "none", ((Object)buttonObject).name, DescribeRect(buttonObject.GetComponent<RectTransform>()), buttonObject.transform.GetSiblingIndex()));
			}
		}

		private static TextMeshProUGUI FindPrefixText(GameObject buttonObject)
		{
			TextMeshProUGUI[] componentsInChildren = buttonObject.GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && Normalize(((TMP_Text)val).text) == ">")
				{
					return val;
				}
			}
			return null;
		}

		private static Text FindPrefixLegacyText(GameObject buttonObject)
		{
			Text[] componentsInChildren = buttonObject.GetComponentsInChildren<Text>(true);
			foreach (Text val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && Normalize(val.text) == ">")
				{
					return val;
				}
			}
			return null;
		}

		private static void PlaceButtonAndRows(RectTransform panel, GameObject buttonObject)
		{
			List<MenuRow> rows = CollectRows((Transform)(object)panel);
			MenuRow menuRow = FindRowFor(buttonObject, rows);
			if (menuRow == null)
			{
				DrawableSuitsDiagnostics.Warn("PlaceButtonAndRows could not find the DrawableSuits row after collection.");
				return;
			}
			LayoutGroup component = ((Component)panel).GetComponent<LayoutGroup>();
			if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled)
			{
				DrawableSuitsDiagnostics.Info("PlaceButtonAndRows using layout group " + ((object)component).GetType().Name + ".");
				InsertAfterResumeBySibling(rows, menuRow);
				LayoutRebuilder.ForceRebuildLayoutImmediate(panel);
			}
			else
			{
				DrawableSuitsDiagnostics.Info("PlaceButtonAndRows using explicit anchored positions.");
				PlaceRowsExplicitly(rows, menuRow);
			}
		}

		private static void InsertAfterResumeBySibling(List<MenuRow> rows, MenuRow drawable)
		{
			MenuRow menuRow = FindResumeRow(rows) ?? FirstNonDrawableRow(rows);
			if (menuRow == null)
			{
				((Transform)drawable.RectTransform).SetAsLastSibling();
			}
			else
			{
				((Transform)drawable.RectTransform).SetSiblingIndex(((Transform)menuRow.RectTransform).GetSiblingIndex() + 1);
			}
		}

		private static void PlaceRowsExplicitly(List<MenuRow> rows, MenuRow drawable)
		{
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			List<MenuRow> list = new List<MenuRow>();
			foreach (MenuRow row in rows)
			{
				if ((Object)(object)((Transform)row.RectTransform).parent == (Object)(object)((Transform)drawable.RectTransform).parent)
				{
					list.Add(row);
				}
			}
			if (list.Count == 0)
			{
				DrawableSuitsDiagnostics.Warn("PlaceRowsExplicitly found no same-parent rows.");
				return;
			}
			MenuRow menuRow = FindResumeRow(list) ?? FirstNonDrawableRow(list);
			if (menuRow == null)
			{
				DrawableSuitsDiagnostics.Warn("PlaceRowsExplicitly found no resume or non-Drawable row.");
				return;
			}
			CopyRectTemplate(menuRow.RectTransform, drawable.RectTransform);
			list.Sort(CompareTopToBottom);
			List<MenuRow> list2 = new List<MenuRow>();
			foreach (MenuRow item in list)
			{
				if (!item.IsDrawable)
				{
					list2.Add(item);
				}
			}
			int num = list2.IndexOf(menuRow);
			if (num < 0)
			{
				num = 0;
			}
			float num2 = DetectRowSpacing(list2);
			MenuRow menuRow2 = ((num + 1 < list2.Count) ? list2[num + 1] : null);
			float num3 = ((menuRow2 != null) ? Mathf.Abs(menuRow.RectTransform.anchoredPosition.y - menuRow2.RectTransform.anchoredPosition.y) : float.PositiveInfinity);
			bool num4 = menuRow2 != null && num3 < num2 * 1.45f;
			float y = menuRow.RectTransform.anchoredPosition.y - num2;
			int num5 = ((Transform)menuRow.RectTransform).GetSiblingIndex() + 1;
			Vector2 anchoredPosition = menuRow.RectTransform.anchoredPosition;
			anchoredPosition.y = y;
			drawable.RectTransform.anchoredPosition = anchoredPosition;
			((Transform)drawable.RectTransform).SetSiblingIndex(num5);
			int num6 = 0;
			if (num4)
			{
				for (int i = num + 1; i < list2.Count; i++)
				{
					MenuRow menuRow3 = list2[i];
					Vector2 anchoredPosition2 = menuRow3.RectTransform.anchoredPosition;
					anchoredPosition2.y -= num2;
					menuRow3.RectTransform.anchoredPosition = anchoredPosition2;
					((Transform)menuRow3.RectTransform).SetSiblingIndex(num5 + 1 + (i - num - 1));
					num6++;
				}
			}
			DrawableSuitsDiagnostics.Info(string.Format("PlaceRowsExplicitly nativeCount={0}; resume={1}; next={2}; spacing={3}; gapToNext={4}; shiftedLowerRows={5}; drawablePosition={6}; drawableSibling={7}", list2.Count, menuRow.LabelText, menuRow2?.LabelText ?? "none", num2, num3, num6, drawable.RectTransform.anchoredPosition, ((Transform)drawable.RectTransform).GetSiblingIndex()));
		}

		private static void CopyRectTemplate(RectTransform source, RectTransform target)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			target.anchorMin = source.anchorMin;
			target.anchorMax = source.anchorMax;
			target.pivot = source.pivot;
			target.sizeDelta = source.sizeDelta;
			((Transform)target).localScale = ((Transform)source).localScale;
		}

		private static float DetectRowSpacing(List<MenuRow> rows)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			List<float> list = new List<float>();
			foreach (MenuRow row in rows)
			{
				list.Add(row.RectTransform.anchoredPosition.y);
			}
			list.Sort((float a, float b) => b.CompareTo(a));
			List<float> list2 = new List<float>();
			for (int num = 0; num < list.Count - 1; num++)
			{
				float num2 = Mathf.Abs(list[num] - list[num + 1]);
				if (num2 >= 36f && num2 <= 240f)
				{
					list2.Add(num2);
				}
			}
			if (list2.Count > 0)
			{
				list2.Sort();
				return Mathf.Max(36f, list2[list2.Count / 2]);
			}
			float num3 = 0f;
			foreach (MenuRow row2 in rows)
			{
				float[] obj = new float[3] { num3, 0f, 0f };
				Rect rect = row2.RectTransform.rect;
				obj[1] = ((Rect)(ref rect)).height;
				obj[2] = row2.RectTransform.sizeDelta.y;
				num3 = Mathf.Max(obj);
			}
			return Mathf.Max(92f, num3 + 24f);
		}

		private static Graphic FindMatchingGraphic(Graphic templateGraphic, Transform templateRoot, Transform targetRoot)
		{
			if ((Object)(object)templateGraphic == (Object)null || (Object)(object)templateRoot == (Object)null || (Object)(object)targetRoot == (Object)null)
			{
				return null;
			}
			string relativePath = GetRelativePath(templateRoot, ((Component)templateGraphic).transform);
			Transform val = (string.IsNullOrEmpty(relativePath) ? targetRoot : targetRoot.Find(relativePath));
			Graphic val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Graphic>() : null);
			DrawableSuitsDiagnostics.Info("Pause-menu targetGraphic mapping. templateGraphic=" + ((Object)templateGraphic).name + "; path=" + relativePath + "; mapped=" + (((val2 != null) ? ((Object)val2).name : null) ?? "none"));
			return val2;
		}

		private static string GetRelativePath(Transform root, Transform child)
		{
			if ((Object)(object)root == (Object)null || (Object)(object)child == (Object)null || (Object)(object)child == (Object)(object)root)
			{
				return string.Empty;
			}
			List<string> list = new List<string>();
			Transform val = child;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Insert(0, ((Object)val).name);
				val = val.parent;
			}
			if (!((Object)(object)val == (Object)(object)root))
			{
				return string.Empty;
			}
			return string.Join("/", list);
		}

		private static void RebuildNavigation(RectTransform panel)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			List<MenuRow> rowsInVisualOrder = GetRowsInVisualOrder(panel);
			if (rowsInVisualOrder.Count == 0)
			{
				DrawableSuitsDiagnostics.Warn("RebuildNavigation skipped because no rows were collected.");
				return;
			}
			for (int i = 0; i < rowsInVisualOrder.Count; i++)
			{
				Button button = rowsInVisualOrder[i].Button;
				Navigation navigation = ((Selectable)button).navigation;
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)((i > 0) ? rowsInVisualOrder[i - 1].Button : null);
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)((i < rowsInVisualOrder.Count - 1) ? rowsInVisualOrder[i + 1].Button : null);
				((Navigation)(ref navigation)).selectOnLeft = null;
				((Navigation)(ref navigation)).selectOnRight = null;
				((Selectable)button).navigation = navigation;
			}
			DrawableSuitsDiagnostics.Info($"RebuildNavigation complete. rowCount={rowsInVisualOrder.Count}; rows=[{DescribeRows(rowsInVisualOrder)}]");
		}

		private static List<MenuRow> GetRowsInVisualOrder(RectTransform panel)
		{
			List<MenuRow> list = CollectRows((Transform)(object)panel);
			list.Sort(CompareTopToBottom);
			return list;
		}

		private static List<MenuRow> CollectRows(Transform root)
		{
			List<MenuRow> list = new List<MenuRow>();
			if ((Object)(object)root == (Object)null)
			{
				return list;
			}
			Button[] componentsInChildren = ((Component)root).GetComponentsInChildren<Button>(true);
			foreach (Button val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeSelf)
				{
					continue;
				}
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				if (!((Object)(object)component == (Object)null))
				{
					string labelText = GetLabelText(((Component)val).gameObject);
					if (!string.IsNullOrWhiteSpace(labelText) || !(((Object)((Component)val).gameObject).name != "DrawableSuitsButton"))
					{
						list.Add(new MenuRow(((Component)val).gameObject, component, val, labelText));
					}
				}
			}
			return list;
		}

		private static string GetLabelText(GameObject gameObject)
		{
			TextMeshProUGUI val = FindPrimaryTmpLabel(gameObject.GetComponentsInChildren<TextMeshProUGUI>(true), null);
			if ((Object)(object)val != (Object)null)
			{
				return ((TMP_Text)val).text ?? string.Empty;
			}
			Text val2 = FindPrimaryLegacyLabel(gameObject.GetComponentsInChildren<Text>(true), null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return string.Empty;
			}
			return val2.text ?? string.Empty;
		}

		private static MenuRow ChooseTemplateRow(List<MenuRow> rows)
		{
			return FindResumeRow(rows) ?? FindRowContaining(rows, "invite") ?? FindRowContaining(rows, "settings") ?? FindRowContaining(rows, "lethalconfig") ?? FirstNonDrawableRow(rows);
		}

		private static MenuRow FindResumeRow(List<MenuRow> rows)
		{
			return FindRowContaining(rows, "resume");
		}

		private static MenuRow FindRowContaining(List<MenuRow> rows, string token)
		{
			foreach (MenuRow row in rows)
			{
				if (!row.IsDrawable && Normalize(row.LabelText).Contains(token))
				{
					return row;
				}
			}
			return null;
		}

		private static MenuRow FirstNonDrawableRow(List<MenuRow> rows)
		{
			foreach (MenuRow row in rows)
			{
				if (!row.IsDrawable)
				{
					return row;
				}
			}
			return null;
		}

		private static MenuRow FindRowFor(GameObject gameObject, List<MenuRow> rows)
		{
			foreach (MenuRow row in rows)
			{
				if ((Object)(object)row.GameObject == (Object)(object)gameObject)
				{
					return row;
				}
			}
			return null;
		}

		private static int CompareTopToBottom(MenuRow a, MenuRow b)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			int num = b.RectTransform.anchoredPosition.y.CompareTo(a.RectTransform.anchoredPosition.y);
			if (num == 0)
			{
				return ((Transform)a.RectTransform).GetSiblingIndex().CompareTo(((Transform)b.RectTransform).GetSiblingIndex());
			}
			return num;
		}

		private static string Normalize(string value)
		{
			return (value ?? string.Empty).Replace(" ", string.Empty).Replace("\n", string.Empty).ToLowerInvariant();
		}

		private static TextMeshProUGUI FindPrimaryTmpLabel(TextMeshProUGUI[] labels, string preferredText)
		{
			TextMeshProUGUI result = null;
			float num = float.MinValue;
			string preferred = Normalize(preferredText);
			foreach (TextMeshProUGUI val in labels)
			{
				if (!((Object)(object)val == (Object)null))
				{
					float num2 = ScoreLabelCandidate(((TMP_Text)val).text, ((TMP_Text)val).rectTransform, ((TMP_Text)val).fontSize, preferred);
					if (num2 > num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private static Text FindPrimaryLegacyLabel(Text[] labels, string preferredText)
		{
			Text result = null;
			float num = float.MinValue;
			string preferred = Normalize(preferredText);
			foreach (Text val in labels)
			{
				if (!((Object)(object)val == (Object)null))
				{
					float num2 = ScoreLabelCandidate(val.text, ((Graphic)val).rectTransform, val.fontSize, preferred);
					if (num2 > num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private static float ScoreLabelCandidate(string text, RectTransform rect, float fontSize, string preferred)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			string text2 = Normalize(text);
			if (string.IsNullOrEmpty(text2))
			{
				return -100000f;
			}
			float num = 0f;
			if (!string.IsNullOrEmpty(preferred) && text2.Contains(preferred))
			{
				num += 100000f;
			}
			num = ((!HasLetterOrDigit(text2)) ? (num - 1000f) : (num + (1000f + (float)text2.Length * 25f)));
			if ((Object)(object)rect != (Object)null)
			{
				float num2 = num;
				Rect rect2 = rect.rect;
				num = num2 + Mathf.Max(0f, ((Rect)(ref rect2)).width) * 0.2f;
				float num3 = num;
				rect2 = rect.rect;
				num = num3 + Mathf.Max(0f, ((Rect)(ref rect2)).height) * 0.1f;
			}
			return num + fontSize;
		}

		private static bool HasLetterOrDigit(string value)
		{
			for (int i = 0; i < value.Length; i++)
			{
				if (char.IsLetterOrDigit(value[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static string DescribeTmpLabel(TextMeshProUGUI label)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)label == (Object)null))
			{
				return $"{((Object)((Component)label).gameObject).name}='{((TMP_Text)label).text}' rect={((TMP_Text)label).rectTransform.rect}";
			}
			return "none";
		}

		private static string DescribeLegacyLabel(Text label)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)label == (Object)null))
			{
				return $"{((Object)((Component)label).gameObject).name}='{label.text}' rect={((Graphic)label).rectTransform.rect}";
			}
			return "none";
		}

		private static string DescribeRect(RectTransform rect)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rect == (Object)null))
			{
				return $"rect={rect.rect}; anchored={rect.anchoredPosition}; sizeDelta={rect.sizeDelta}";
			}
			return "rect=null";
		}

		private static string DescribeButtonColors(Button button)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)button == (Object)null)
			{
				return "button=null";
			}
			ColorBlock colors = ((Selectable)button).colors;
			object[] obj = new object[7]
			{
				((Selectable)button).transition,
				((ColorBlock)(ref colors)).normalColor,
				((ColorBlock)(ref colors)).highlightedColor,
				((ColorBlock)(ref colors)).selectedColor,
				((ColorBlock)(ref colors)).pressedColor,
				((ColorBlock)(ref colors)).disabledColor,
				null
			};
			Graphic targetGraphic = ((Selectable)button).targetGraphic;
			obj[6] = ((targetGraphic != null) ? ((Object)targetGraphic).name : null) ?? "null";
			return string.Format("transition={0}; normal={1}; highlighted={2}; selected={3}; pressed={4}; disabled={5}; targetGraphic={6}", obj);
		}

		private static string DescribeNavigation(Button button)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)button == (Object)null)
			{
				return "button=null";
			}
			Navigation navigation = ((Selectable)button).navigation;
			object arg = ((Navigation)(ref navigation)).mode;
			Selectable selectOnUp = ((Navigation)(ref navigation)).selectOnUp;
			string arg2 = ((selectOnUp != null) ? ((Object)((Component)selectOnUp).gameObject).name : null) ?? "null";
			Selectable selectOnDown = ((Navigation)(ref navigation)).selectOnDown;
			return string.Format("mode={0}; up={1}; down={2}", arg, arg2, ((selectOnDown != null) ? ((Object)((Component)selectOnDown).gameObject).name : null) ?? "null");
		}

		private static void OpenEditorFromPauseMenu(QuickMenuManager quickMenu)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			DrawableSuitsDiagnostics.Info($"Pause-menu DrawableSuits button clicked. quickMenuNull={(Object)(object)quickMenu == (Object)null}; menuOpenBeforeClose={quickMenu?.isMenuOpen}; cursorVisible={Cursor.visible}; cursorLock={Cursor.lockState}");
			try
			{
				if (quickMenu != null)
				{
					quickMenu.CloseQuickMenu();
				}
				DrawableSuitsDiagnostics.Info($"Quick menu close requested. menuOpenAfterClose={quickMenu?.isMenuOpen}");
			}
			catch (Exception exception)
			{
				DrawableSuitsDiagnostics.Exception("Failed to close quick menu before opening editor", exception);
			}
			bool flag = DrawableSuitsPlugin.EnsureRuntimeRe