Decompiled source of CombinedMeltdownPlaylist v1.6.0

CombinedMeltdownPlaylistSync.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FacilityMeltdown.API;
using FacilityMeltdown.MeltdownSequence.Behaviours;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using PizzaTowerEscapeMusic;
using PizzaTowerEscapeMusic.Scripting;
using PizzaTowerEscapeMusic.Scripting.ScriptEvents;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.TextCore;
using UnityEngine.TextCore.LowLevel;
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("CombinedMeltdownPlaylistSync")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.6.0.0")]
[assembly: AssemblyInformationalVersion("1.6.0+0a64f431b310f2e03a4c4184fc3ceb9955e24135")]
[assembly: AssemblyProduct("CombinedMeltdownPlaylistSync")]
[assembly: AssemblyTitle("CombinedMeltdownPlaylistSync")]
[assembly: AssemblyVersion("1.6.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CombinedMeltdownPlaylistSync
{
	internal static class ApparatusLocatorRegistry
	{
		private const int LocatorItemId = 912042;

		private const string LocatorItemName = "Apparatus locator";

		private static Item? _locatorItem;

		private static bool _registered;

		private static bool _removedFromStore;

		private static int _appliedPrice = -1;

		private static LocatorScanMode _appliedScanMode = (LocatorScanMode)(-1);

		private static int _appliedBurstCharges = -1;

		private static float _appliedBatterySeconds = -1f;

		private static float _nextRegistrationAttempt;

		private static bool _loggedWaitingForMapper;

		internal static void EnsureRegistered(StartOfRound? round = null)
		{
			if (_registered || ((Object)(object)round == (Object)null && Time.unscaledTime < _nextRegistrationAttempt))
			{
				return;
			}
			_nextRegistrationAttempt = Time.unscaledTime + 1f;
			Item val = FindMapperItem(round);
			if ((Object)(object)val == (Object)null || (Object)(object)val.spawnPrefab == (Object)null)
			{
				if (!_loggedWaitingForMapper)
				{
					_loggedWaitingForMapper = true;
					Plugin.ModLog.LogDebug((object)"The vanilla Mapper item is not loaded yet; locator registration will retry when StartOfRound awakens.");
				}
				return;
			}
			try
			{
				_locatorItem = Object.Instantiate<Item>(val);
				((Object)_locatorItem).name = "ApparatusLocator (Item)";
				_locatorItem.itemId = 912042;
				_locatorItem.itemName = "Apparatus locator";
				_locatorItem.isScrap = false;
				_locatorItem.creditsWorth = LocatorConfig.Price.Value;
				_locatorItem.requiresBattery = true;
				_locatorItem.itemIsTrigger = LocatorConfig.ScanMode.Value == LocatorScanMode.Burst;
				_locatorItem.batteryUsage = (_locatorItem.itemIsTrigger ? (1f / (float)LocatorConfig.BurstCharges.Value) : LocatorConfig.BatterySeconds.Value);
				_locatorItem.automaticallySetUsingPower = true;
				_locatorItem.holdButtonUse = false;
				_locatorItem.syncUseFunction = true;
				_locatorItem.saveItemVariable = false;
				_locatorItem.canBeGrabbedBeforeGameStart = true;
				_locatorItem.toolTips = new string[1] { "Toggle apparatus locator : [LMB]" };
				GameObject spawnPrefab = val.spawnPrefab;
				MapDevice component = spawnPrefab.GetComponent<MapDevice>();
				if ((Object)(object)component == (Object)null)
				{
					throw new InvalidOperationException("The vanilla Mapper prefab no longer has a MapDevice component.");
				}
				((GrabbableObject)component).itemProperties = _locatorItem;
				if ((Object)(object)spawnPrefab.GetComponent<ApparatusLocatorDisplay>() == (Object)null)
				{
					spawnPrefab.AddComponent<ApparatusLocatorDisplay>();
				}
				_locatorItem.spawnPrefab = spawnPrefab;
				TerminalNode val2 = ScriptableObject.CreateInstance<TerminalNode>();
				((Object)val2).name = "ApparatusLocatorInfoNode";
				val2.displayText = "APPARATUS LOCATOR\n\nA battery-powered locator built from an unused Mapper chassis. While switched on, it detects the docked apparatus assigned to the current facility.\n\n";
				val2.clearPreviousText = true;
				val2.maxCharactersToType = 35;
				Items.RegisterShopItem(_locatorItem, (TerminalNode)null, (TerminalNode)null, val2, LocatorConfig.Price.Value);
				_registered = true;
				_loggedWaitingForMapper = false;
				Plugin.ModLog.LogInfo((object)("Registered the apparatus locator for " + $"{LocatorConfig.Price.Value} credits."));
			}
			catch (Exception arg)
			{
				Plugin.ModLog.LogError((object)$"Could not register the apparatus locator: {arg}");
			}
		}

		internal static void Tick()
		{
			if (!_registered)
			{
				EnsureRegistered(StartOfRound.Instance);
			}
			if ((Object)(object)_locatorItem == (Object)null)
			{
				return;
			}
			SyncedConfigSnapshot current = HostConfigSynchronizer.Current;
			if (_appliedScanMode != current.LocatorMode || _appliedBurstCharges != current.LocatorBurstCharges || !Mathf.Approximately(_appliedBatterySeconds, current.LocatorBatterySeconds))
			{
				_appliedScanMode = current.LocatorMode;
				_appliedBurstCharges = current.LocatorBurstCharges;
				_appliedBatterySeconds = current.LocatorBatterySeconds;
				bool flag = current.LocatorMode == LocatorScanMode.Burst;
				_locatorItem.itemIsTrigger = flag;
				_locatorItem.batteryUsage = (flag ? (1f / (float)current.LocatorBurstCharges) : current.LocatorBatterySeconds);
			}
			if ((Object)(object)Items.terminal == (Object)null || HostConfigSynchronizer.WaitingForHostSnapshot)
			{
				return;
			}
			if (!current.EnableLocator)
			{
				if (!_removedFromStore)
				{
					try
					{
						Items.RemoveShopItem(_locatorItem);
						_removedFromStore = true;
						Plugin.ModLog.LogInfo((object)"Removed the apparatus locator from the store because the host disabled it.");
					}
					catch (Exception ex)
					{
						Plugin.ModLog.LogWarning((object)("Could not hide the disabled apparatus locator: " + ex.Message));
					}
				}
			}
			else if (!_removedFromStore && _appliedPrice != current.LocatorPrice)
			{
				try
				{
					Items.UpdateShopItemPrice(_locatorItem, current.LocatorPrice);
					_appliedPrice = current.LocatorPrice;
				}
				catch (Exception ex2)
				{
					Plugin.ModLog.LogWarning((object)("Could not update the apparatus locator price: " + ex2.Message));
				}
			}
		}

		internal static void Destroy()
		{
			ApparatusLocatorDisplay.DestroySharedAssets();
		}

		internal static bool IsLocator(MapDevice device)
		{
			return string.Equals(((GrabbableObject)device).itemProperties?.itemName, "Apparatus locator", StringComparison.OrdinalIgnoreCase);
		}

		internal static ApparatusLocatorDisplay GetOrAttachDisplay(MapDevice device)
		{
			ApparatusLocatorDisplay component = ((Component)device).GetComponent<ApparatusLocatorDisplay>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			component = ((Component)device).gameObject.AddComponent<ApparatusLocatorDisplay>();
			Plugin.ModLog.LogInfo((object)"Attached the apparatus-locator display to a spawned Mapper instance.");
			return component;
		}

		private static Item? FindMapperItem(StartOfRound? round)
		{
			Item val = ((IEnumerable<Item>)(round?.allItemsList?.itemsList?.Where((Item item) => (Object)(object)item != (Object)null).ToArray() ?? Array.Empty<Item>())).FirstOrDefault((Func<Item, bool>)IsMapperItem);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			return ((IEnumerable<Item>)Resources.FindObjectsOfTypeAll<Item>()).FirstOrDefault((Func<Item, bool>)IsMapperItem);
		}

		private static bool IsMapperItem(Item item)
		{
			string obj = ((Object)item).name ?? string.Empty;
			string a = item.itemName ?? string.Empty;
			GameObject spawnPrefab = item.spawnPrefab;
			string text = ((spawnPrefab != null) ? ((Object)spawnPrefab).name : null) ?? string.Empty;
			if (obj.IndexOf("MapDevice", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("MapDevice", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return string.Equals(a, "Mapper", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Awake")]
	internal static class ApparatusLocatorRegistrationPatch
	{
		[HarmonyPostfix]
		private static void Postfix(StartOfRound __instance)
		{
			ApparatusLocatorRegistry.EnsureRegistered(__instance);
		}
	}
	[HarmonyPatch(typeof(MapDevice), "ItemActivate")]
	internal static class ApparatusLocatorActivationPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(MapDevice __instance, bool used, bool buttonDown)
		{
			if (!ApparatusLocatorRegistry.IsLocator(__instance))
			{
				return true;
			}
			ApparatusLocatorRegistry.GetOrAttachDisplay(__instance).OnActivated(used, buttonDown);
			return false;
		}
	}
	[HarmonyPatch(typeof(MapDevice), "Start")]
	internal static class ApparatusLocatorRuntimeAttachmentPatch
	{
		[HarmonyPostfix]
		private static void Postfix(MapDevice __instance)
		{
			if (ApparatusLocatorRegistry.IsLocator(__instance))
			{
				ApparatusLocatorRegistry.GetOrAttachDisplay(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(GrabbableObject), "UseItemOnClient")]
	internal static class ApparatusLocatorUseFallbackPatch
	{
		[HarmonyPostfix]
		private static void Postfix(GrabbableObject __instance)
		{
			MapDevice val = (MapDevice)(object)((__instance is MapDevice) ? __instance : null);
			if (val != null && ApparatusLocatorRegistry.IsLocator(val))
			{
				ApparatusLocatorRegistry.GetOrAttachDisplay(val).OnActivated(((GrabbableObject)val).isBeingUsed, buttonDown: true);
			}
		}
	}
	[HarmonyPatch(typeof(MapDevice), "EquipItem")]
	internal static class ApparatusLocatorEquipPatch
	{
		[HarmonyPostfix]
		private static void Postfix(MapDevice __instance)
		{
			if (ApparatusLocatorRegistry.IsLocator(__instance) && (Object)(object)((GrabbableObject)__instance).playerHeldBy != (Object)null)
			{
				((GrabbableObject)__instance).playerHeldBy.equippedUsableItemQE = false;
			}
		}
	}
	internal sealed class ApparatusLocatorDisplay : MonoBehaviour
	{
		private const float TargetRefreshSeconds = 0.1f;

		private const int DisplayWidth = 320;

		private const int DisplayHeight = 180;

		private const int DisplayLayer = 31;

		private static Texture2D? _arrowTexture;

		private static Sprite? _arrowSprite;

		private static AudioClip? _scanClip;

		private MapDevice? _device;

		private MeshRenderer? _modelRenderer;

		private Material? _originalScreenMaterial;

		private Material? _locatorScreenMaterial;

		private int _screenMaterialIndex = -1;

		private RenderTexture? _displayTexture;

		private Camera? _renderCamera;

		private GameObject? _renderRoot;

		private RectTransform? _canvasRect;

		private TextMeshProUGUI? _statusText;

		private Image? _arrowImage;

		private AudioSource? _scanAudioSource;

		private float _nextTargetRefresh;

		private float _nextRadarRefresh;

		private LungProp? _target;

		private bool _screenShowingLocator;

		private bool _hasBurstReading;

		private bool _modeInitialized;

		private LocatorScanMode _currentMode;

		private int _lastActivationFrame = -1;

		private void Awake()
		{
			_device = ((Component)this).GetComponent<MapDevice>();
		}

		private void OnDestroy()
		{
			RestoreOriginalScreenMaterial();
			if ((Object)(object)_renderRoot != (Object)null)
			{
				Object.Destroy((Object)(object)_renderRoot);
			}
			if ((Object)(object)_locatorScreenMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_locatorScreenMaterial);
			}
			if ((Object)(object)_displayTexture != (Object)null)
			{
				_displayTexture.Release();
				Object.Destroy((Object)(object)_displayTexture);
			}
			_renderRoot = null;
			_renderCamera = null;
			_displayTexture = null;
			_locatorScreenMaterial = null;
			_canvasRect = null;
		}

		internal void OnActivated(bool used, bool buttonDown)
		{
			if (Time.frameCount == _lastActivationFrame)
			{
				return;
			}
			_lastActivationFrame = Time.frameCount;
			SyncedConfigSnapshot current = HostConfigSynchronizer.Current;
			ApplyModeChange(current.LocatorMode);
			switch (current.LocatorMode)
			{
			case LocatorScanMode.Burst:
				if (buttonDown)
				{
					_hasBurstReading = true;
					PerformScan(current, playSound: true);
				}
				break;
			case LocatorScanMode.Radar:
				if (!used)
				{
					Hide();
					break;
				}
				_nextRadarRefresh = Time.unscaledTime + current.LocatorRadarIntervalSeconds;
				PerformScan(current, playSound: true);
				break;
			default:
				if (!used)
				{
					Hide();
				}
				else
				{
					_nextTargetRefresh = 0f;
				}
				break;
			}
		}

		private void LateUpdate()
		{
			if ((Object)(object)_device == (Object)null)
			{
				return;
			}
			EnsureUi();
			SyncedConfigSnapshot current = HostConfigSynchronizer.Current;
			ApplyModeChange(current.LocatorMode);
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			bool flag = (Object)(object)val != (Object)null && ((GrabbableObject)_device).playerHeldBy == val;
			bool flag2 = ((GrabbableObject)_device).insertedBattery == null || (!((GrabbableObject)_device).insertedBattery.empty && ((GrabbableObject)_device).insertedBattery.charge > 0f);
			if (!(current.EnableLocator && flag) || !((GrabbableObject)_device).isHeld || ((GrabbableObject)_device).isPocketed)
			{
				Hide();
				return;
			}
			switch (current.LocatorMode)
			{
			case LocatorScanMode.Burst:
				if (!_hasBurstReading)
				{
					Hide();
				}
				else
				{
					ShowLocatorScreen();
				}
				break;
			case LocatorScanMode.Radar:
				if (!((GrabbableObject)_device).isBeingUsed || !flag2)
				{
					Hide();
					break;
				}
				ShowLocatorScreen();
				if (Time.unscaledTime >= _nextRadarRefresh)
				{
					_nextRadarRefresh = Time.unscaledTime + current.LocatorRadarIntervalSeconds;
					PerformScan(current, playSound: true);
				}
				break;
			default:
				if (!((GrabbableObject)_device).isBeingUsed || !flag2)
				{
					Hide();
					break;
				}
				ShowLocatorScreen();
				if (Time.unscaledTime >= _nextTargetRefresh)
				{
					_nextTargetRefresh = Time.unscaledTime + 0.1f;
					PerformScan(current, playSound: false);
				}
				break;
			}
		}

		private void ApplyModeChange(LocatorScanMode mode)
		{
			if (!_modeInitialized || _currentMode != mode)
			{
				_modeInitialized = true;
				_currentMode = mode;
				_hasBurstReading = false;
				_nextTargetRefresh = 0f;
				_nextRadarRefresh = 0f;
				Hide();
			}
		}

		private void PerformScan(SyncedConfigSnapshot config, bool playSound)
		{
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)_device == (Object)null || (Object)(object)val == (Object)null || ((GrabbableObject)_device).playerHeldBy != val)
			{
				return;
			}
			EnsureUi();
			if (!((Object)(object)_canvasRect == (Object)null) && !((Object)(object)_displayTexture == (Object)null) && !((Object)(object)_renderCamera == (Object)null))
			{
				ShowLocatorScreen();
				_target = FindCurrentApparatus();
				UpdateReadout(val, config);
				if (playSound)
				{
					PlayScanSound(config.LocatorScanSoundVolume);
				}
				RenderDisplay();
			}
		}

		private void EnsureUi()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0049: 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_0059: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: 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)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Expected O, but got Unknown
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: 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)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvasRect != (Object)null) && TryReplaceModelScreenMaterial())
			{
				TMP_FontAsset orCreate = VcrFontFactory.GetOrCreate();
				_renderRoot = new GameObject("Apparatus Locator Display Renderer");
				((Object)_renderRoot).hideFlags = (HideFlags)61;
				_displayTexture = new RenderTexture(320, 180, 16, (RenderTextureFormat)0)
				{
					name = "Apparatus Locator Display",
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1,
					useMipMap = false,
					autoGenerateMips = false,
					hideFlags = (HideFlags)61
				};
				_displayTexture.Create();
				GameObject val = new GameObject("Apparatus Locator Display Camera", new Type[1] { typeof(Camera) });
				((Object)val).hideFlags = (HideFlags)61;
				val.layer = 31;
				val.transform.SetParent(_renderRoot.transform, false);
				_renderCamera = val.GetComponent<Camera>();
				((Behaviour)_renderCamera).enabled = false;
				_renderCamera.clearFlags = (CameraClearFlags)2;
				_renderCamera.backgroundColor = new Color(0.01f, 0.025f, 0.018f, 1f);
				_renderCamera.orthographic = true;
				_renderCamera.orthographicSize = 90f;
				_renderCamera.nearClipPlane = 0.01f;
				_renderCamera.farClipPlane = 10f;
				_renderCamera.cullingMask = int.MinValue;
				_renderCamera.targetTexture = _displayTexture;
				GameObject val2 = new GameObject("Apparatus Locator Display Canvas", new Type[3]
				{
					typeof(RectTransform),
					typeof(Canvas),
					typeof(CanvasScaler)
				})
				{
					hideFlags = (HideFlags)61,
					layer = 31
				};
				val2.transform.SetParent(_renderRoot.transform, false);
				RectTransform parent = (RectTransform)val2.transform;
				Canvas component = val2.GetComponent<Canvas>();
				component.renderMode = (RenderMode)1;
				component.worldCamera = _renderCamera;
				component.planeDistance = 1f;
				component.pixelPerfect = true;
				component.overrideSorting = true;
				component.sortingOrder = 0;
				CanvasScaler component2 = val2.GetComponent<CanvasScaler>();
				component2.uiScaleMode = (ScaleMode)1;
				component2.referenceResolution = new Vector2(320f, 180f);
				component2.screenMatchMode = (ScreenMatchMode)0;
				component2.matchWidthOrHeight = 0f;
				_canvasRect = CreateRect(parent, "Locator Panel", Vector2.zero, new Vector2(320f, 180f));
				Image obj = ((Component)CreateRect(_canvasRect, "Screen Background", Vector2.zero, new Vector2(320f, 180f))).gameObject.AddComponent<Image>();
				((Graphic)obj).color = new Color(0.01f, 0.025f, 0.018f, 1f);
				((Graphic)obj).raycastTarget = false;
				_statusText = CreateText(_canvasRect, "Locator Status", orCreate, 36f, Vector2.zero, new Vector2(306f, 166f));
				((TMP_Text)_statusText).text = "LOCATOR ACTIVE";
				RectTransform val3 = CreateRect(_canvasRect, "Direction Arrow", new Vector2(0f, 38f), new Vector2(72f, 72f));
				_arrowImage = ((Component)val3).gameObject.AddComponent<Image>();
				_arrowImage.sprite = GetArrowSprite();
				((Graphic)_arrowImage).color = new Color(0.24f, 1f, 0.42f, 1f);
				_arrowImage.preserveAspect = true;
				((Graphic)_arrowImage).raycastTarget = false;
				_scanAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				_scanAudioSource.playOnAwake = false;
				_scanAudioSource.loop = false;
				_scanAudioSource.spatialBlend = 0.15f;
				Hide();
			}
		}

		private void UpdateReadout(PlayerControllerB player, SyncedConfigSnapshot config)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: 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_0211: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_statusText == (Object)null || (Object)(object)_arrowImage == (Object)null)
			{
				return;
			}
			if (!player.isInsideFactory)
			{
				ShowMessage("NO APPARATUS\nDETECTED");
				return;
			}
			if ((Object)(object)_target == (Object)null)
			{
				ShowMessage("NO APPARATUS\nDETECTED");
				return;
			}
			float num = ConvertDistance(Vector3.Distance(((Component)player).transform.position, ((Component)_target).transform.position), config.LocatorDistanceUnits);
			if (config.RequireLocatorDetectionRange && num > config.LocatorDetectionRange)
			{
				ShowMessage("NO APPARATUS\nDETECTED NEARBY");
				return;
			}
			bool showLocatorDistance = config.ShowLocatorDistance;
			bool showLocatorArrow = config.ShowLocatorArrow;
			((Component)_statusText).gameObject.SetActive(showLocatorDistance || !showLocatorArrow);
			((Component)_arrowImage).gameObject.SetActive(showLocatorArrow);
			if (showLocatorDistance)
			{
				((TMP_Text)_statusText).rectTransform.anchoredPosition = (Vector2)(showLocatorArrow ? new Vector2(0f, -44f) : Vector2.zero);
				((TMP_Text)_statusText).rectTransform.sizeDelta = (showLocatorArrow ? new Vector2(306f, 76f) : new Vector2(306f, 166f));
				((TMP_Text)_statusText).fontSize = (showLocatorArrow ? 34f : 42f);
				((TMP_Text)_statusText).text = "APPARATUS " + num.ToString("F0", CultureInfo.InvariantCulture) + " " + DistanceSuffix(config.LocatorDistanceUnits);
			}
			else if (!showLocatorArrow)
			{
				((TMP_Text)_statusText).rectTransform.anchoredPosition = Vector2.zero;
				((TMP_Text)_statusText).rectTransform.sizeDelta = new Vector2(306f, 166f);
				((TMP_Text)_statusText).fontSize = 40f;
				((TMP_Text)_statusText).text = "APPARATUS\nDETECTED";
			}
			if (showLocatorArrow)
			{
				((Graphic)_arrowImage).rectTransform.anchoredPosition = (Vector2)(showLocatorDistance ? new Vector2(0f, 38f) : Vector2.zero);
				RotateArrowToward(player, ((Component)_target).transform.position);
			}
		}

		private void ShowMessage(string message)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_statusText == (Object)null) && !((Object)(object)_arrowImage == (Object)null))
			{
				((Component)_arrowImage).gameObject.SetActive(false);
				((Component)_statusText).gameObject.SetActive(true);
				((TMP_Text)_statusText).rectTransform.anchoredPosition = Vector2.zero;
				((TMP_Text)_statusText).rectTransform.sizeDelta = new Vector2(306f, 166f);
				((TMP_Text)_statusText).fontSize = (message.Contains("NEARBY") ? 34f : 40f);
				((TMP_Text)_statusText).text = message;
			}
		}

		private void RotateArrowToward(PlayerControllerB player, Vector3 target)
		{
			//IL_000f: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_arrowImage == (Object)null))
			{
				Vector3 val = target - ((Component)player).transform.position;
				val.y = 0f;
				Vector3 val2 = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.forward : ((Component)player).transform.forward);
				val2.y = 0f;
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.001f) && !(((Vector3)(ref val2)).sqrMagnitude < 0.001f))
				{
					float num = Vector3.SignedAngle(((Vector3)(ref val2)).normalized, ((Vector3)(ref val)).normalized, Vector3.up);
					((Transform)((Graphic)_arrowImage).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 0f - num);
				}
			}
		}

		private void PlayScanSound(float volume)
		{
			if (!((Object)(object)_scanAudioSource == (Object)null) && !(volume <= 0f))
			{
				_scanAudioSource.volume = Mathf.Clamp01(volume);
				_scanAudioSource.PlayOneShot(GetScanClip());
			}
		}

		private bool TryReplaceModelScreenMaterial()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			if ((Object)(object)_locatorScreenMaterial != (Object)null)
			{
				return true;
			}
			MeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<MeshRenderer>(true);
			foreach (MeshRenderer val in componentsInChildren)
			{
				Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val2 = sharedMaterials[j];
					if (!((Object)(object)val2 == (Object)null) && ((Object)val2).name.StartsWith("MapScreen", StringComparison.OrdinalIgnoreCase))
					{
						_modelRenderer = val;
						_screenMaterialIndex = j;
						_originalScreenMaterial = val2;
						_locatorScreenMaterial = new Material(val2)
						{
							name = "Apparatus Locator Screen (Instance)",
							hideFlags = (HideFlags)61
						};
						sharedMaterials[j] = _locatorScreenMaterial;
						((Renderer)val).sharedMaterials = sharedMaterials;
						SetScreenTexture((Texture)(object)Texture2D.blackTexture);
						Plugin.ModLog.LogInfo((object)($"Replaced Mapper model material slot {j} on " + "'" + ((Object)((Component)val).gameObject).name + "' with the locator display."));
						return true;
					}
				}
			}
			Plugin.ModLog.LogError((object)"Could not find the Mapper model's MapScreen material; the locator display cannot be attached to its physical screen.");
			((Behaviour)this).enabled = false;
			return false;
		}

		private void RestoreOriginalScreenMaterial()
		{
			if (!((Object)(object)_modelRenderer == (Object)null) && !((Object)(object)_originalScreenMaterial == (Object)null) && _screenMaterialIndex >= 0)
			{
				Material[] sharedMaterials = ((Renderer)_modelRenderer).sharedMaterials;
				if (_screenMaterialIndex < sharedMaterials.Length)
				{
					sharedMaterials[_screenMaterialIndex] = _originalScreenMaterial;
					((Renderer)_modelRenderer).sharedMaterials = sharedMaterials;
				}
			}
		}

		private void ShowLocatorScreen()
		{
			if (!_screenShowingLocator && !((Object)(object)_displayTexture == (Object)null))
			{
				SetScreenTexture((Texture)(object)_displayTexture);
				_screenShowingLocator = true;
				_nextTargetRefresh = 0f;
			}
		}

		private void SetScreenTexture(Texture texture)
		{
			if (!((Object)(object)_locatorScreenMaterial == (Object)null))
			{
				_locatorScreenMaterial.mainTexture = texture;
				SetTextureIfPresent(_locatorScreenMaterial, "_MainTex", texture);
				SetTextureIfPresent(_locatorScreenMaterial, "_UnlitColorMap", texture);
				SetTextureIfPresent(_locatorScreenMaterial, "_BaseColorMap", texture);
				SetTextureIfPresent(_locatorScreenMaterial, "_EmissiveColorMap", texture);
			}
		}

		private static void SetTextureIfPresent(Material material, string property, Texture texture)
		{
			if (material.HasProperty(property))
			{
				material.SetTexture(property, texture);
			}
		}

		private void RenderDisplay()
		{
			if (!((Object)(object)_renderCamera == (Object)null))
			{
				Canvas.ForceUpdateCanvases();
				_renderCamera.Render();
			}
		}

		private static LungProp? FindCurrentApparatus()
		{
			return (from lung in Object.FindObjectsOfType<LungProp>()
				where (Object)(object)lung != (Object)null && ((Component)lung).gameObject.activeInHierarchy && lung.isLungDocked && !lung.isLungDockedInElevator && !((GrabbableObject)lung).isInShipRoom
				orderby ((Object)lung).GetInstanceID()
				select lung).FirstOrDefault();
		}

		private static float ConvertDistance(float gameDistance, DistanceUnit unit)
		{
			if (unit != DistanceUnit.Feet)
			{
				return gameDistance;
			}
			return gameDistance * 3.28084f;
		}

		private static string DistanceSuffix(DistanceUnit unit)
		{
			return unit switch
			{
				DistanceUnit.Feet => "FT", 
				DistanceUnit.GameUnits => "U", 
				_ => "M", 
			};
		}

		private static RectTransform CreateRect(RectTransform parent, string name, Vector2 anchoredPosition, Vector2 size)
		{
			//IL_0014: 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)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) })
			{
				layer = ((Component)parent).gameObject.layer
			}.transform;
			((Transform)val).SetParent((Transform)(object)parent, false);
			val.anchorMin = new Vector2(0.5f, 0.5f);
			val.anchorMax = new Vector2(0.5f, 0.5f);
			val.pivot = new Vector2(0.5f, 0.5f);
			val.anchoredPosition = anchoredPosition;
			val.sizeDelta = size;
			return val;
		}

		private static TextMeshProUGUI CreateText(RectTransform parent, string name, TMP_FontAsset font, float size, Vector2 position, Vector2 dimensions)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = ((Component)CreateRect(parent, name, position, dimensions)).gameObject.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).font = font;
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)514;
			((TMP_Text)obj).enableWordWrapping = true;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
			((Graphic)obj).color = new Color(0.24f, 1f, 0.42f, 1f);
			((TMP_Text)obj).outlineWidth = 0.1f;
			((TMP_Text)obj).outlineColor = new Color32((byte)0, (byte)20, (byte)6, (byte)220);
			((Graphic)obj).raycastTarget = false;
			return obj;
		}

		private static Sprite GetArrowSprite()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_00fd: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_arrowSprite != (Object)null)
			{
				return _arrowSprite;
			}
			_arrowTexture = new Texture2D(64, 64, (TextureFormat)4, false)
			{
				name = "Apparatus Locator Arrow",
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
			Color[] array = (Color[])(object)new Color[4096];
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					bool flag = j >= 28 && j <= 35 && i >= 12 && i <= 43;
					int num = Mathf.Max(0, 58 - i);
					bool flag2 = i >= 38 && i <= 58 && Mathf.Abs(j - 31) <= num;
					array[i * 64 + j] = ((flag || flag2) ? Color.white : Color.clear);
				}
			}
			_arrowTexture.SetPixels(array);
			_arrowTexture.Apply(false, true);
			_arrowSprite = Sprite.Create(_arrowTexture, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f);
			((Object)_arrowSprite).name = "Apparatus Locator Arrow";
			((Object)_arrowSprite).hideFlags = (HideFlags)61;
			return _arrowSprite;
		}

		private static AudioClip GetScanClip()
		{
			if ((Object)(object)_scanClip != (Object)null)
			{
				return _scanClip;
			}
			int num = Mathf.CeilToInt(14112f);
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				float num2 = (float)i / 44100f;
				float num3 = num2 / 0.32f;
				float num4 = MathF.PI * 2f * (440f * num2 + 700f * num2 * num2 / 0.32f);
				float num5 = Mathf.Exp(-7f * num3) * Mathf.SmoothStep(0f, 1f, Mathf.Min(1f, num3 * 30f));
				float num6 = Mathf.Sin(num4);
				float num7 = Mathf.Sin(num4 * 2.01f) * 0.22f;
				array[i] = (num6 + num7) * num5 * 0.55f;
			}
			_scanClip = AudioClip.Create("Apparatus Locator Scan", num, 1, 44100, false);
			_scanClip.SetData(array, 0);
			return _scanClip;
		}

		internal static void DestroySharedAssets()
		{
			if ((Object)(object)_arrowSprite != (Object)null)
			{
				Object.Destroy((Object)(object)_arrowSprite);
			}
			if ((Object)(object)_arrowTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_arrowTexture);
			}
			if ((Object)(object)_scanClip != (Object)null)
			{
				Object.Destroy((Object)(object)_scanClip);
			}
			_arrowSprite = null;
			_arrowTexture = null;
			_scanClip = null;
		}

		private void Hide()
		{
			if (_screenShowingLocator)
			{
				SetScreenTexture((Texture)(object)Texture2D.blackTexture);
				_screenShowingLocator = false;
			}
		}
	}
	internal static class EscapeSpeedConfig
	{
		internal static ConfigEntry<bool> EnableDistanceBoost { get; private set; }

		internal static ConfigEntry<float> FirstThreshold { get; private set; }

		internal static ConfigEntry<float> FirstBoostPercent { get; private set; }

		internal static ConfigEntry<float> SecondThreshold { get; private set; }

		internal static ConfigEntry<float> SecondBoostPercent { get; private set; }

		internal static void Bind(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			EnableDistanceBoost = config.Bind<bool>("Meltdown Escape Speed", "EnableDistanceBoost", true, "Add a movement-speed bonus while outside and far from the ship door during an active meltdown.");
			FirstThreshold = config.Bind<float>("Meltdown Escape Speed", "FirstDistance", 100f, new ConfigDescription("Distance from the ship door where the first speed bonus begins.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5000f), Array.Empty<object>()));
			FirstBoostPercent = config.Bind<float>("Meltdown Escape Speed", "FirstSpeedPercent", 5f, new ConfigDescription("Additive percentage speed bonus at FirstDistance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f), Array.Empty<object>()));
			SecondThreshold = config.Bind<float>("Meltdown Escape Speed", "SecondDistance", 150f, new ConfigDescription("Distance from the ship door where the larger speed bonus begins.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5000f), Array.Empty<object>()));
			SecondBoostPercent = config.Bind<float>("Meltdown Escape Speed", "SecondSpeedPercent", 10f, new ConfigDescription("Additive percentage speed bonus at SecondDistance. This replaces the first tier rather than stacking with it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f), Array.Empty<object>()));
		}
	}
	[Serializable]
	internal sealed class SyncedConfigSnapshot
	{
		public float ExtraStaminaPercent;

		public float ExtraStaminaRegenPercent;

		public bool PlaylistMode;

		public float MusicVolume;

		public float DepartureFadeSeconds;

		public bool EnableDistanceSpeedBoost;

		public float FirstSpeedDistance;

		public float FirstSpeedPercent;

		public float SecondSpeedDistance;

		public float SecondSpeedPercent;

		public bool EnableHud;

		public float HudScale;

		public float HudOpacity;

		public string BaseColor = "#FF2020";

		public string FlashColor = "#FFD21A";

		public bool ShowReactorTimer;

		public bool ShowHundredths;

		public bool ShowTimerPanel;

		public float TimerPanelOpacity;

		public bool ShowDistance;

		public bool ShowSelectedTrack;

		public bool ShowTrackAuthor;

		public bool ShowDisc;

		public DistanceUnit DistanceUnits;

		public int DistanceDecimals;

		public float DiscSpinSpeed;

		public bool EnableFlashing;

		public bool UseTrackBpm;

		public HudBeatCadence BeatCadence;

		public float FixedFlashIntervalSeconds;

		public float FlashFadeSeconds;

		public float TimerTransitionSpeed;

		public float OutsideTimerOffsetX;

		public float OutsideTimerOffsetY;

		public float InsideTimerOffsetX;

		public float InsideTimerOffsetY;

		public float SpectatorTimerOffsetX;

		public float SpectatorTimerOffsetY;

		public float DistanceOffsetX;

		public float DistanceOffsetY;

		public float TrackOffsetX;

		public float TrackOffsetY;

		public bool EnableLocator;

		public int LocatorPrice;

		public LocatorScanMode LocatorMode;

		public int LocatorBurstCharges;

		public float LocatorBatterySeconds;

		public float LocatorRadarIntervalSeconds;

		public float LocatorScanSoundVolume;

		public bool ShowLocatorDistance;

		public bool ShowLocatorArrow;

		public DistanceUnit LocatorDistanceUnits;

		public bool RequireLocatorDetectionRange;

		public float LocatorDetectionRange;

		internal static SyncedConfigSnapshot CaptureLocal()
		{
			return new SyncedConfigSnapshot
			{
				ExtraStaminaPercent = Plugin.ExtraStaminaPercent.Value,
				ExtraStaminaRegenPercent = Plugin.ExtraStaminaRegenPercent.Value,
				PlaylistMode = Plugin.PlaylistMode.Value,
				MusicVolume = Plugin.MusicVolume.Value,
				DepartureFadeSeconds = Plugin.DepartureFadeSeconds.Value,
				EnableDistanceSpeedBoost = EscapeSpeedConfig.EnableDistanceBoost.Value,
				FirstSpeedDistance = EscapeSpeedConfig.FirstThreshold.Value,
				FirstSpeedPercent = EscapeSpeedConfig.FirstBoostPercent.Value,
				SecondSpeedDistance = EscapeSpeedConfig.SecondThreshold.Value,
				SecondSpeedPercent = EscapeSpeedConfig.SecondBoostPercent.Value,
				EnableHud = HudConfig.EnableHud.Value,
				HudScale = 0.8f + HudConfig.HudScaleAdjustment.Value,
				HudOpacity = HudConfig.HudOpacity.Value,
				BaseColor = HudConfig.BaseColor.Value,
				FlashColor = HudConfig.FlashColor.Value,
				ShowReactorTimer = HudConfig.ShowReactorTimer.Value,
				ShowHundredths = HudConfig.ShowHundredths.Value,
				ShowTimerPanel = HudConfig.ShowTimerPanel.Value,
				TimerPanelOpacity = HudConfig.TimerPanelOpacity.Value,
				ShowDistance = HudConfig.ShowDistance.Value,
				ShowSelectedTrack = HudConfig.ShowSelectedTrack.Value,
				ShowTrackAuthor = HudConfig.ShowTrackAuthor.Value,
				ShowDisc = HudConfig.ShowDisc.Value,
				DistanceUnits = HudConfig.DistanceUnits.Value,
				DistanceDecimals = HudConfig.DistanceDecimals.Value,
				DiscSpinSpeed = HudConfig.DiscSpinSpeed.Value,
				EnableFlashing = HudConfig.EnableFlashing.Value,
				UseTrackBpm = HudConfig.UseTrackBpm.Value,
				BeatCadence = HudConfig.BeatCadence.Value,
				FixedFlashIntervalSeconds = HudConfig.FixedFlashIntervalSeconds.Value,
				FlashFadeSeconds = HudConfig.FlashFadeSeconds.Value,
				TimerTransitionSpeed = HudConfig.TimerTransitionSpeed.Value,
				OutsideTimerOffsetX = HudConfig.OutsideTimerOffsetX.Value,
				OutsideTimerOffsetY = HudConfig.OutsideTimerOffsetY.Value,
				InsideTimerOffsetX = HudConfig.InsideTimerOffsetX.Value,
				InsideTimerOffsetY = HudConfig.InsideTimerOffsetY.Value,
				SpectatorTimerOffsetX = HudConfig.SpectatorTimerOffsetX.Value,
				SpectatorTimerOffsetY = HudConfig.SpectatorTimerOffsetY.Value,
				DistanceOffsetX = HudConfig.DistanceOffsetX.Value,
				DistanceOffsetY = HudConfig.DistanceOffsetY.Value,
				TrackOffsetX = HudConfig.TrackOffsetX.Value,
				TrackOffsetY = HudConfig.TrackOffsetY.Value,
				EnableLocator = LocatorConfig.EnableLocator.Value,
				LocatorPrice = LocatorConfig.Price.Value,
				LocatorMode = LocatorConfig.ScanMode.Value,
				LocatorBurstCharges = LocatorConfig.BurstCharges.Value,
				LocatorBatterySeconds = LocatorConfig.BatterySeconds.Value,
				LocatorRadarIntervalSeconds = LocatorConfig.RadarIntervalSeconds.Value,
				LocatorScanSoundVolume = LocatorConfig.ScanSoundVolume.Value,
				ShowLocatorDistance = LocatorConfig.ShowDistance.Value,
				ShowLocatorArrow = LocatorConfig.ShowArrow.Value,
				LocatorDistanceUnits = LocatorConfig.DistanceUnits.Value,
				RequireLocatorDetectionRange = LocatorConfig.RequireDetectionRange.Value,
				LocatorDetectionRange = LocatorConfig.DetectionRange.Value
			};
		}

		internal void Validate()
		{
			ExtraStaminaPercent = Mathf.Clamp(ExtraStaminaPercent, 0f, 1000f);
			ExtraStaminaRegenPercent = Mathf.Clamp(ExtraStaminaRegenPercent, 0f, 1000f);
			MusicVolume = Mathf.Clamp01(MusicVolume);
			DepartureFadeSeconds = Mathf.Clamp(DepartureFadeSeconds, 0f, 10f);
			FirstSpeedDistance = Mathf.Clamp(FirstSpeedDistance, 0f, 5000f);
			FirstSpeedPercent = Mathf.Clamp(FirstSpeedPercent, 0f, 500f);
			SecondSpeedDistance = Mathf.Clamp(SecondSpeedDistance, 0f, 5000f);
			SecondSpeedPercent = Mathf.Clamp(SecondSpeedPercent, 0f, 500f);
			HudScale = Mathf.Clamp(HudScale, 0.5f, 2.5f);
			HudOpacity = Mathf.Clamp01(HudOpacity);
			TimerPanelOpacity = Mathf.Clamp01(TimerPanelOpacity);
			DistanceDecimals = Mathf.Clamp(DistanceDecimals, 0, 2);
			DiscSpinSpeed = Mathf.Clamp(DiscSpinSpeed, -720f, 720f);
			FixedFlashIntervalSeconds = Mathf.Clamp(FixedFlashIntervalSeconds, 0.25f, 30f);
			FlashFadeSeconds = Mathf.Clamp(FlashFadeSeconds, 0.05f, 5f);
			TimerTransitionSpeed = Mathf.Clamp(TimerTransitionSpeed, 0.5f, 30f);
			LocatorPrice = Mathf.Clamp(LocatorPrice, 0, 10000);
			LocatorBurstCharges = Mathf.Clamp(LocatorBurstCharges, 1, 100);
			LocatorBatterySeconds = Mathf.Clamp(LocatorBatterySeconds, 5f, 3600f);
			LocatorRadarIntervalSeconds = Mathf.Clamp(LocatorRadarIntervalSeconds, 0.25f, 60f);
			LocatorScanSoundVolume = Mathf.Clamp01(LocatorScanSoundVolume);
			LocatorDetectionRange = Mathf.Clamp(LocatorDetectionRange, 1f, 5000f);
			if (!Enum.IsDefined(typeof(DistanceUnit), DistanceUnits))
			{
				DistanceUnits = DistanceUnit.Meters;
			}
			if (!Enum.IsDefined(typeof(HudBeatCadence), BeatCadence))
			{
				BeatCadence = HudBeatCadence.EveryFourBeats;
			}
			if (!Enum.IsDefined(typeof(DistanceUnit), LocatorDistanceUnits))
			{
				LocatorDistanceUnits = DistanceUnit.Meters;
			}
			if (!Enum.IsDefined(typeof(LocatorScanMode), LocatorMode))
			{
				LocatorMode = LocatorScanMode.Burst;
			}
			if (BaseColor == null)
			{
				BaseColor = "#FF2020";
			}
			if (FlashColor == null)
			{
				FlashColor = "#FFD21A";
			}
		}
	}
	internal static class HostConfigSynchronizer
	{
		private const float RefreshIntervalSeconds = 0.5f;

		private static SyncedConfigSnapshot? _local;

		private static SyncedConfigSnapshot? _host;

		private static string? _lastSentJson;

		private static int _lastClientCount = -1;

		private static float _nextRefreshTime;

		internal static bool WaitingForHostSnapshot
		{
			get
			{
				NetworkManager registeredNetworkManager = Plugin.RegisteredNetworkManager;
				if ((Object)(object)registeredNetworkManager != (Object)null && registeredNetworkManager.IsListening && !registeredNetworkManager.IsServer)
				{
					return _host == null;
				}
				return false;
			}
		}

		internal static SyncedConfigSnapshot Current
		{
			get
			{
				NetworkManager registeredNetworkManager = Plugin.RegisteredNetworkManager;
				if ((Object)(object)registeredNetworkManager != (Object)null && registeredNetworkManager.IsListening && !registeredNetworkManager.IsServer && _host != null)
				{
					return _host;
				}
				return _local ?? (_local = CaptureValidatedLocal());
			}
		}

		internal static void Tick()
		{
			if (Time.unscaledTime < _nextRefreshTime)
			{
				return;
			}
			_nextRefreshTime = Time.unscaledTime + 0.5f;
			_local = CaptureValidatedLocal();
			NetworkManager registeredNetworkManager = Plugin.RegisteredNetworkManager;
			if (!((Object)(object)registeredNetworkManager == (Object)null) && registeredNetworkManager.IsListening && registeredNetworkManager.IsServer)
			{
				string text = JsonUtility.ToJson((object)_local);
				int count = registeredNetworkManager.ConnectedClientsIds.Count;
				if (!string.Equals(text, _lastSentJson, StringComparison.Ordinal) || count != _lastClientCount)
				{
					Broadcast(text);
					_lastSentJson = text;
					_lastClientCount = count;
				}
			}
		}

		internal static void ForceBroadcast()
		{
			_local = CaptureValidatedLocal();
			NetworkManager registeredNetworkManager = Plugin.RegisteredNetworkManager;
			if (!((Object)(object)registeredNetworkManager == (Object)null) && registeredNetworkManager.IsListening && registeredNetworkManager.IsServer)
			{
				string text = JsonUtility.ToJson((object)_local);
				Broadcast(text);
				_lastSentJson = text;
				_lastClientCount = registeredNetworkManager.ConnectedClientsIds.Count;
			}
		}

		internal static void Receive(ulong senderClientId, FastBufferReader reader)
		{
			NetworkManager registeredNetworkManager = Plugin.RegisteredNetworkManager;
			if ((Object)(object)registeredNetworkManager == (Object)null || registeredNetworkManager.IsServer)
			{
				return;
			}
			if (senderClientId != 0L)
			{
				Plugin.ModLog.LogWarning((object)$"Ignored configuration from non-host client {senderClientId}.");
				return;
			}
			try
			{
				string text = default(string);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref text, true);
				SyncedConfigSnapshot obj = JsonUtility.FromJson<SyncedConfigSnapshot>(text) ?? throw new InvalidOperationException("The host snapshot was empty.");
				obj.Validate();
				_host = obj;
				Plugin.ModLog.LogInfo((object)"Applied the host's music, stamina, escape-speed, HUD, and apparatus-locator configuration for this lobby.");
			}
			catch (Exception arg)
			{
				Plugin.ModLog.LogError((object)$"Could not read the host's configuration: {arg}");
			}
		}

		internal static void Reset()
		{
			_local = CaptureValidatedLocal();
			_host = null;
			_lastSentJson = null;
			_lastClientCount = -1;
			_nextRefreshTime = 0f;
		}

		private static SyncedConfigSnapshot CaptureValidatedLocal()
		{
			SyncedConfigSnapshot syncedConfigSnapshot = SyncedConfigSnapshot.CaptureLocal();
			syncedConfigSnapshot.Validate();
			return syncedConfigSnapshot;
		}

		private unsafe static void Broadcast(string json)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager registeredNetworkManager = Plugin.RegisteredNetworkManager;
			if ((Object)(object)registeredNetworkManager == (Object)null)
			{
				return;
			}
			try
			{
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(4096, (Allocator)2, -1);
				try
				{
					((FastBufferWriter)(ref val)).WriteValueSafe(json, true);
					registeredNetworkManager.CustomMessagingManager.SendNamedMessageToAll("CombinedMeltdownPlaylist.Config.v2", val, (NetworkDelivery)3);
				}
				finally
				{
					((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
				}
			}
			catch (Exception arg)
			{
				Plugin.ModLog.LogError((object)$"Could not broadcast the host's configuration: {arg}");
			}
		}
	}
	internal enum DistanceUnit
	{
		Meters,
		Feet,
		GameUnits
	}
	internal enum HudBeatCadence
	{
		EveryBeat,
		EveryFourBeats
	}
	internal static class HudConfig
	{
		internal const float BaseScale = 0.8f;

		internal static ConfigEntry<bool> EnableHud { get; private set; }

		internal static ConfigEntry<float> HudScaleAdjustment { get; private set; }

		internal static ConfigEntry<float> HudOpacity { get; private set; }

		internal static ConfigEntry<string> BaseColor { get; private set; }

		internal static ConfigEntry<string> FlashColor { get; private set; }

		internal static ConfigEntry<bool> ShowReactorTimer { get; private set; }

		internal static ConfigEntry<bool> ShowHundredths { get; private set; }

		internal static ConfigEntry<bool> ShowTimerPanel { get; private set; }

		internal static ConfigEntry<float> TimerPanelOpacity { get; private set; }

		internal static ConfigEntry<bool> ShowDistance { get; private set; }

		internal static ConfigEntry<bool> ShowSelectedTrack { get; private set; }

		internal static ConfigEntry<bool> ShowTrackAuthor { get; private set; }

		internal static ConfigEntry<bool> ShowDisc { get; private set; }

		internal static ConfigEntry<DistanceUnit> DistanceUnits { get; private set; }

		internal static ConfigEntry<int> DistanceDecimals { get; private set; }

		internal static ConfigEntry<float> DiscSpinSpeed { get; private set; }

		internal static ConfigEntry<bool> EnableFlashing { get; private set; }

		internal static ConfigEntry<bool> UseTrackBpm { get; private set; }

		internal static ConfigEntry<HudBeatCadence> BeatCadence { get; private set; }

		internal static ConfigEntry<float> FixedFlashIntervalSeconds { get; private set; }

		internal static ConfigEntry<float> FlashFadeSeconds { get; private set; }

		internal static ConfigEntry<float> TimerTransitionSpeed { get; private set; }

		internal static ConfigEntry<float> OutsideTimerOffsetX { get; private set; }

		internal static ConfigEntry<float> OutsideTimerOffsetY { get; private set; }

		internal static ConfigEntry<float> InsideTimerOffsetX { get; private set; }

		internal static ConfigEntry<float> InsideTimerOffsetY { get; private set; }

		internal static ConfigEntry<float> SpectatorTimerOffsetX { get; private set; }

		internal static ConfigEntry<float> SpectatorTimerOffsetY { get; private set; }

		internal static ConfigEntry<float> DistanceOffsetX { get; private set; }

		internal static ConfigEntry<float> DistanceOffsetY { get; private set; }

		internal static ConfigEntry<float> TrackOffsetX { get; private set; }

		internal static ConfigEntry<float> TrackOffsetY { get; private set; }

		internal static void Bind(ConfigFile config)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Expected O, but got Unknown
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Expected O, but got Unknown
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Expected O, but got Unknown
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Expected O, but got Unknown
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Expected O, but got Unknown
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Expected O, but got Unknown
			AcceptableValueRange<float> val = new AcceptableValueRange<float>(-0.3f, 1.7f);
			AcceptableValueRange<float> val2 = new AcceptableValueRange<float>(0.1f, 1f);
			AcceptableValueRange<float> range = new AcceptableValueRange<float>(-2000f, 2000f);
			EnableHud = config.Bind<bool>("Meltdown HUD - General", "EnableHud", true, "Enable all custom meltdown HUD elements.");
			HudScaleAdjustment = config.Bind<float>("Meltdown HUD - General", "HudScaleAdjustment", 0f, new ConfigDescription("Adjustment added to the natural 0.8 HUD scale. Leave at 0 for the recommended size.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			HudOpacity = config.Bind<float>("Meltdown HUD - General", "HudOpacity", 1f, new ConfigDescription("Global opacity for every custom HUD element.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
			BaseColor = config.Bind<string>("Meltdown HUD - General", "BaseColor", "#FF2020", "Normal HUD color in HTML hex format.");
			FlashColor = config.Bind<string>("Meltdown HUD - General", "FlashColor", "#FFD21A", "Beat-flash HUD color in HTML hex format.");
			ShowReactorTimer = config.Bind<bool>("Meltdown HUD - Elements", "ShowReactorTimer", true, "Show the CRITICAL FAILURE countdown.");
			ShowHundredths = config.Bind<bool>("Meltdown HUD - Elements", "ShowHundredths", true, "Show small hundredths next to the large total-seconds countdown.");
			ShowTimerPanel = config.Bind<bool>("Meltdown HUD - Elements", "ShowTimerPanel", true, "Show the rounded translucent reactor enclosure and separator line.");
			TimerPanelOpacity = config.Bind<float>("Meltdown HUD - Elements", "TimerPanelOpacity", 0.32f, new ConfigDescription("Opacity of the rounded reactor panel background.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ShowDistance = config.Bind<bool>("Meltdown HUD - Elements", "ShowDistance", true, "Show distance to the ship outside and main entrance inside.");
			ShowSelectedTrack = config.Bind<bool>("Meltdown HUD - Elements", "ShowSelectedTrack", true, "Show the selected track on the right side.");
			ShowTrackAuthor = config.Bind<bool>("Meltdown HUD - Elements", "ShowTrackAuthor", true, "Show confirmed track authors when available.");
			ShowDisc = config.Bind<bool>("Meltdown HUD - Elements", "ShowDisc", true, "Show the spinning transparent music disc.");
			DistanceUnits = config.Bind<DistanceUnit>("Meltdown HUD - Elements", "DistanceUnits", DistanceUnit.Meters, "Distance units: Meters, Feet, or GameUnits.");
			DistanceDecimals = config.Bind<int>("Meltdown HUD - Elements", "DistanceDecimals", 0, new ConfigDescription("Number of decimal places in distance values.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 2), Array.Empty<object>()));
			DiscSpinSpeed = config.Bind<float>("Meltdown HUD - Elements", "DiscSpinSpeed", 90f, new ConfigDescription("Disc rotation speed in degrees per second. Negative values reverse it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-720f, 720f), Array.Empty<object>()));
			EnableFlashing = config.Bind<bool>("Meltdown HUD - Flash", "EnableFlashing", true, "Enable red-to-yellow HUD pulses.");
			UseTrackBpm = config.Bind<bool>("Meltdown HUD - Flash", "UseTrackBpm", true, "Use the current track BPM. If disabled, use FixedFlashIntervalSeconds.");
			BeatCadence = config.Bind<HudBeatCadence>("Meltdown HUD - Flash", "BeatCadence", HudBeatCadence.EveryFourBeats, "Pulse on EveryBeat or EveryFourBeats.");
			FixedFlashIntervalSeconds = config.Bind<float>("Meltdown HUD - Flash", "FixedFlashIntervalSeconds", 4f, new ConfigDescription("Pulse interval when BPM sync is disabled or metadata is unavailable.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 30f), Array.Empty<object>()));
			FlashFadeSeconds = config.Bind<float>("Meltdown HUD - Flash", "FlashFadeSeconds", 0.45f, new ConfigDescription("Seconds for yellow to fade back to red. It is shortened automatically when needed so every pulse has red resting time.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>()));
			TimerTransitionSpeed = config.Bind<float>("Meltdown HUD - Layout", "TimerTransitionSpeed", 8f, new ConfigDescription("How quickly the reactor panel glides between its inside, outside, ship, and spectator positions. Higher values move faster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
			OutsideTimerOffsetX = BindOffset(config, "OutsideTimerOffsetX", "Horizontal adjustment for the timer beside the outside clock.", range);
			OutsideTimerOffsetY = BindOffset(config, "OutsideTimerOffsetY", "Vertical adjustment for the timer beside the outside clock.", range);
			InsideTimerOffsetX = BindOffset(config, "InsideTimerOffsetX", "Horizontal adjustment for the inside top-center timer.", range);
			InsideTimerOffsetY = BindOffset(config, "InsideTimerOffsetY", "Vertical adjustment for the inside top-center timer.", range);
			SpectatorTimerOffsetX = BindOffset(config, "SpectatorTimerOffsetX", "Horizontal adjustment for the spectator bottom-left timer.", range);
			SpectatorTimerOffsetY = BindOffset(config, "SpectatorTimerOffsetY", "Vertical adjustment for the spectator bottom-left timer.", range);
			DistanceOffsetX = BindOffset(config, "DistanceOffsetX", "Horizontal adjustment for the bottom-left distance.", range);
			DistanceOffsetY = BindOffset(config, "DistanceOffsetY", "Vertical adjustment for the lowered bottom-left distance.", range);
			TrackOffsetX = BindOffset(config, "TrackOffsetX", "Horizontal adjustment for the right-center track panel.", range);
			TrackOffsetY = BindOffset(config, "TrackOffsetY", "Vertical adjustment for the right-center track panel.", range);
		}

		private static ConfigEntry<float> BindOffset(ConfigFile config, string key, string description, AcceptableValueRange<float> range)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return config.Bind<float>("Meltdown HUD - Layout", key, 0f, new ConfigDescription(description, (AcceptableValueBase)(object)range, Array.Empty<object>()));
		}
	}
	internal enum LocatorScanMode
	{
		Burst,
		Continuous,
		Radar
	}
	internal static class LocatorConfig
	{
		internal static ConfigEntry<bool> EnableLocator { get; private set; }

		internal static ConfigEntry<int> Price { get; private set; }

		internal static ConfigEntry<LocatorScanMode> ScanMode { get; private set; }

		internal static ConfigEntry<int> BurstCharges { get; private set; }

		internal static ConfigEntry<float> BatterySeconds { get; private set; }

		internal static ConfigEntry<float> RadarIntervalSeconds { get; private set; }

		internal static ConfigEntry<float> ScanSoundVolume { get; private set; }

		internal static ConfigEntry<bool> ShowDistance { get; private set; }

		internal static ConfigEntry<bool> ShowArrow { get; private set; }

		internal static ConfigEntry<DistanceUnit> DistanceUnits { get; private set; }

		internal static ConfigEntry<bool> RequireDetectionRange { get; private set; }

		internal static ConfigEntry<float> DetectionRange { get; private set; }

		internal static void Bind(ConfigFile config)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			EnableLocator = config.Bind<bool>("Apparatus Locator", "EnableLocator", true, "Make the apparatus locator available in the terminal store. Changing this setting requires a game restart.");
			Price = config.Bind<int>("Apparatus Locator", "Price", 350, new ConfigDescription("Terminal store price in credits.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000), Array.Empty<object>()));
			ScanMode = config.Bind<LocatorScanMode>("Apparatus Locator", "ScanMode", LocatorScanMode.Burst, "Burst consumes one battery charge per left-click and freezes each reading. Continuous updates constantly while switched on. Radar updates at RadarIntervalSeconds while switched on.");
			BurstCharges = config.Bind<int>("Apparatus Locator", "BurstCharges", 8, new ConfigDescription("Number of scans represented by a full battery in Burst mode.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			BatterySeconds = config.Bind<float>("Apparatus Locator", "BatterySeconds", 120f, new ConfigDescription("Approximate powered-on lifetime of a full battery in Continuous and Radar modes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 3600f), Array.Empty<object>()));
			RadarIntervalSeconds = config.Bind<float>("Apparatus Locator", "RadarIntervalSeconds", 3f, new ConfigDescription("Seconds between frozen reading updates in Radar mode.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 60f), Array.Empty<object>()));
			ScanSoundVolume = config.Bind<float>("Apparatus Locator", "ScanSoundVolume", 0.65f, new ConfigDescription("Volume of the locator's scan ping.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ShowDistance = config.Bind<bool>("Apparatus Locator", "ShowDistance", true, "Show the distance to the current moon's docked apparatus.");
			ShowArrow = config.Bind<bool>("Apparatus Locator", "ShowArrow", false, "Show a compass arrow that points toward the apparatus.");
			DistanceUnits = config.Bind<DistanceUnit>("Apparatus Locator", "DistanceUnits", DistanceUnit.Meters, "Distance units: Meters, Feet, or GameUnits.");
			RequireDetectionRange = config.Bind<bool>("Apparatus Locator", "RequireDetectionRange", false, "Only detect the apparatus while it is inside DetectionRange.");
			DetectionRange = config.Bind<float>("Apparatus Locator", "DetectionRange", 50f, new ConfigDescription("Maximum detection distance when RequireDetectionRange is enabled, measured in the selected DistanceUnits.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5000f), Array.Empty<object>()));
		}
	}
	internal static class StaminaBoostController
	{
		private static bool _wasActive;

		internal static bool IsActive
		{
			get
			{
				StartOfRound instance = StartOfRound.Instance;
				if ((Object)(object)instance != (Object)null && instance.shipHasLanded && !instance.inShipPhase)
				{
					return MeltdownAPI.MeltdownStarted;
				}
				return false;
			}
		}

		internal static void Tick()
		{
			bool isActive = IsActive;
			if (isActive != _wasActive)
			{
				_wasActive = isActive;
				if (isActive)
				{
					SyncedConfigSnapshot current = HostConfigSynchronizer.Current;
					Plugin.ModLog.LogInfo((object)("Meltdown stamina boosts enabled: " + $"+{current.ExtraStaminaPercent:0.##}% effective stamina, " + $"+{current.ExtraStaminaRegenPercent:0.##}% regeneration."));
				}
				else
				{
					Plugin.ModLog.LogInfo((object)"Meltdown stamina boosts disabled.");
				}
			}
		}

		internal static void ForceDeactivate(string reason)
		{
			if (_wasActive)
			{
				Plugin.ModLog.LogInfo((object)("Meltdown stamina boosts disabled (" + reason + ")."));
			}
			_wasActive = false;
		}

		internal static StaminaSnapshot Capture(PlayerControllerB player)
		{
			if (!IsLocalPlayer(player) || !IsActive)
			{
				return default(StaminaSnapshot);
			}
			return new StaminaSnapshot(tracked: true, player.sprintMeter);
		}

		internal static void ApplyFrameDelta(PlayerControllerB player, StaminaSnapshot snapshot, bool includeRegeneration)
		{
			if (!snapshot.Tracked || !IsLocalPlayer(player) || !IsActive)
			{
				return;
			}
			float sprintMeter = player.sprintMeter;
			float num = sprintMeter - snapshot.Before;
			if (num < 0f)
			{
				SyncedConfigSnapshot current = HostConfigSynchronizer.Current;
				float num2 = 1f + current.ExtraStaminaPercent / 100f;
				float num3 = 0f - num;
				player.sprintMeter = snapshot.Before - num3 / num2;
			}
			else if (includeRegeneration && num > 0f)
			{
				SyncedConfigSnapshot current2 = HostConfigSynchronizer.Current;
				float num4 = num * current2.ExtraStaminaRegenPercent / 100f;
				float num5 = sprintMeter + num4;
				if (snapshot.Before > 1f || sprintMeter > 1f)
				{
					player.sprintMeter = num5;
				}
				else
				{
					player.sprintMeter = Mathf.Min(1f, num5);
				}
			}
			if ((Object)(object)player.sprintMeterUI != (Object)null)
			{
				player.sprintMeterUI.fillAmount = player.sprintMeter;
			}
		}

		private static bool IsLocalPlayer(PlayerControllerB player)
		{
			if ((Object)(object)GameNetworkManager.Instance != (Object)null)
			{
				return player == GameNetworkManager.Instance.localPlayerController;
			}
			return false;
		}
	}
	internal readonly struct StaminaSnapshot
	{
		internal bool Tracked { get; }

		internal float Before { get; }

		internal StaminaSnapshot(bool tracked, float before)
		{
			Tracked = tracked;
			Before = before;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	internal static class MeltdownDistanceSpeedPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(0)]
		private static void Prefix(PlayerControllerB __instance, out MovementSpeedSnapshot __state)
		{
			__state = MovementSpeedSnapshot.Capture(__instance);
			if (__state.AddedSpeed > 0f)
			{
				__instance.movementSpeed += __state.AddedSpeed;
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void Postfix(PlayerControllerB __instance, MovementSpeedSnapshot __state)
		{
			if (__state.AddedSpeed > 0f)
			{
				__instance.movementSpeed -= __state.AddedSpeed;
			}
		}
	}
	internal readonly struct MovementSpeedSnapshot
	{
		internal float AddedSpeed { get; }

		private MovementSpeedSnapshot(float addedSpeed)
		{
			AddedSpeed = addedSpeed;
		}

		internal static MovementSpeedSnapshot Capture(PlayerControllerB player)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!StaminaBoostController.IsActive || !IsLocalPlayer(player) || player.isInsideFactory || player.isInHangarShipRoom)
			{
				return default(MovementSpeedSnapshot);
			}
			SyncedConfigSnapshot current = HostConfigSynchronizer.Current;
			if (!current.EnableDistanceSpeedBoost)
			{
				return default(MovementSpeedSnapshot);
			}
			Transform val = StartOfRound.Instance?.shipDoorNode;
			if ((Object)(object)val == (Object)null)
			{
				return default(MovementSpeedSnapshot);
			}
			float num = Vector3.Distance(((Component)player).transform.position, val.position);
			float num2;
			if (num >= current.SecondSpeedDistance)
			{
				num2 = current.SecondSpeedPercent;
			}
			else
			{
				if (!(num >= current.FirstSpeedDistance))
				{
					return default(MovementSpeedSnapshot);
				}
				num2 = current.FirstSpeedPercent;
			}
			float num3 = player.movementSpeed * num2 / 100f;
			if (!(num3 > 0f))
			{
				return default(MovementSpeedSnapshot);
			}
			return new MovementSpeedSnapshot(num3);
		}

		private static bool IsLocalPlayer(PlayerControllerB player)
		{
			if ((Object)(object)GameNetworkManager.Instance != (Object)null)
			{
				return player == GameNetworkManager.Instance.localPlayerController;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
	internal static class PlayerStaminaLateUpdatePatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(PlayerControllerB __instance, out StaminaSnapshot __state)
		{
			__state = StaminaBoostController.Capture(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(PlayerControllerB __instance, StaminaSnapshot __state)
		{
			StaminaBoostController.ApplyFrameDelta(__instance, __state, includeRegeneration: true);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Jump_performed")]
	internal static class PlayerJumpStaminaPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(PlayerControllerB __instance, out StaminaSnapshot __state)
		{
			__state = StaminaBoostController.Capture(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(PlayerControllerB __instance, StaminaSnapshot __state)
		{
			StaminaBoostController.ApplyFrameDelta(__instance, __state, includeRegeneration: false);
		}
	}
	[HarmonyPatch(typeof(MeltdownHandler), "HandleEnemies")]
	internal static class FacilityMeltdownEnemyCompatibilityPatch
	{
		[HarmonyFinalizer]
		private static Exception? Finalizer(Exception? __exception)
		{
			if (__exception == null)
			{
				return null;
			}
			Plugin.ModLog.LogError((object)("FacilityMeltdown's optional enemy handling failed. The exception was contained so host-side meltdown initialization and forced takeoff can continue. " + $"Original error: {__exception}"));
			return null;
		}
	}
	[HarmonyPatch(typeof(MeltdownHandler), "Update")]
	internal static class FacilityMeltdownUpdatePatch
	{
		[HarmonyPostfix]
		private static void Postfix(MeltdownHandler __instance)
		{
			ForcedTakeoffFailsafe.Observe(__instance);
			MeltdownHudController.Observe(__instance);
		}
	}
	[HarmonyPatch(typeof(MeltdownHandler), "OnDisable")]
	internal static class FacilityMeltdownCleanupPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			StaminaBoostController.ForceDeactivate("meltdown handler cleanup");
			ForcedTakeoffFailsafe.Reset();
			if (MeltdownDepartureController.IsShipDeparting)
			{
				MeltdownDepartureController.Begin();
				return;
			}
			LazyMusicPlayer.Stop();
			MeltdownHudController.ResetSession();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
	internal static class ShipLeaveCleanupPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			StaminaBoostController.ForceDeactivate("ship departure");
			MeltdownDepartureController.Begin();
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "EndOfGame")]
	internal static class EndOfGameCleanupPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			StaminaBoostController.ForceDeactivate("end of round");
			MeltdownDepartureController.Begin();
		}
	}
	internal static class MeltdownDepartureController
	{
		internal static bool IsShipDeparting
		{
			get
			{
				StartOfRound instance = StartOfRound.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					if (!instance.shipIsLeaving && instance.shipHasLanded)
					{
						return instance.inShipPhase;
					}
					return true;
				}
				return false;
			}
		}

		internal static void Begin()
		{
			float departureFadeSeconds = HostConfigSynchronizer.Current.DepartureFadeSeconds;
			LazyMusicPlayer.BeginFadeOut(departureFadeSeconds);
			MeltdownHudController.BeginFadeOut(departureFadeSeconds);
		}

		internal static void StopImmediatelyOrFade()
		{
			if (IsShipDeparting)
			{
				Begin();
			}
			else
			{
				LazyMusicPlayer.Stop();
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "SetSpectateCameraToGameOverMode")]
	internal static class MeltdownAlivePlayerSpectateFix
	{
		[HarmonyPrefix]
		private static bool Prefix(bool enableGameOver, PlayerControllerB? localPlayer)
		{
			if (!enableGameOver || (Object)(object)localPlayer != (Object)null || !MeltdownAPI.MeltdownStarted)
			{
				return true;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)val == (Object)null || (Object)(object)instance == (Object)null || val.isPlayerDead || !instance.shipIsLeaving || (!val.isInElevator && !val.isInHangarShipRoom))
			{
				return true;
			}
			Plugin.ModLog.LogInfo((object)"Prevented FacilityMeltdown from forcing a living ship survivor into the game-over spectator camera.");
			return false;
		}
	}
	internal static class ForcedTakeoffFailsafe
	{
		private const float GraceSecondsAfterOriginalTakeoff = 7f;

		private const float RetryDelaySeconds = 2f;

		private const int MaximumAttempts = 3;

		private static readonly MethodInfo? ShipLeaveMethod = AccessTools.Method(typeof(StartOfRound), "ShipLeave", (Type[])null, (Type[])null);

		private static bool _armed;

		private static float _nextAttemptTime;

		private static int _attempts;

		internal static void Observe(MeltdownHandler handler)
		{
			if (!_armed && IsHost() && !(handler.TimeLeftUntilMeltdown > 3f))
			{
				_armed = true;
				_attempts = 0;
				_nextAttemptTime = Time.realtimeSinceStartup + 7f;
				Plugin.ModLog.LogDebug((object)"Armed the host forced-takeoff failsafe.");
			}
		}

		internal static void Tick()
		{
			if (!_armed)
			{
				return;
			}
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || instance.inShipPhase || !MeltdownAPI.MeltdownStarted)
			{
				Reset();
			}
			else
			{
				if (!IsHost() || !instance.shipHasLanded || Time.realtimeSinceStartup < _nextAttemptTime || _attempts >= 3)
				{
					return;
				}
				_attempts++;
				_nextAttemptTime = Time.realtimeSinceStartup + 2f;
				if (!(ShipLeaveMethod == null))
				{
					try
					{
						Plugin.ModLog.LogWarning((object)("FacilityMeltdown's host departure did not complete; running takeoff " + $"failsafe attempt {_attempts}/{3}."));
						instance.shipLeftAutomatically = true;
						instance.shipIsLeaving = true;
						ShipLeaveMethod.Invoke(instance, Array.Empty<object>());
						return;
					}
					catch (Exception arg)
					{
						Plugin.ModLog.LogError((object)$"Forced-takeoff failsafe attempt {_attempts} failed: {arg}");
						return;
					}
				}
				Plugin.ModLog.LogError((object)"Could not locate StartOfRound.ShipLeave for the forced-takeoff failsafe.");
				_attempts = 3;
			}
		}

		internal static void Reset()
		{
			_armed = false;
			_nextAttemptTime = 0f;
			_attempts = 0;
		}

		private static bool IsHost()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && singleton.IsListening)
			{
				return singleton.IsHost;
			}
			return false;
		}
	}
	internal static class MeltdownHudController
	{
		private const float DistanceUpdateInterval = 0.1f;

		private const float NaturalTrackRightMargin = 24f;

		private static MeltdownHandler? _handler;

		private static HUDManager? _hudManager;

		private static GameObject? _root;

		private static RectTransform? _rootRect;

		private static CanvasGroup? _canvasGroup;

		private static Canvas? _hudCanvas;

		private static RectTransform? _timerRoot;

		private static Image? _timerPanel;

		private static Image? _timerHighlight;

		private static TextMeshProUGUI? _timerHeader;

		private static TextMeshProUGUI? _timerSeconds;

		private static TextMeshProUGUI? _timerHundredths;

		private static RectTransform? _distanceRoot;

		private static TextMeshProUGUI? _distanceText;

		private static RectTransform? _trackRoot;

		private static TextMeshProUGUI? _trackHeader;

		private static TextMeshProUGUI? _trackTitle;

		private static TextMeshProUGUI? _trackAuthor;

		private static RectTransform? _discRect;

		private static Image? _discImage;

		private static Image? _tonearmImage;

		private static Texture2D? _discTexture;

		private static Sprite? _discSprite;

		private static Texture2D? _tonearmTexture;

		private static Sprite? _tonearmSprite;

		private static Texture2D? _timerPanelTexture;

		private static Sprite? _timerPanelSprite;

		private static Texture2D? _timerHighlightTexture;

		private static Sprite? _timerHighlightSprite;

		private static TrackInfo? _currentTrack;

		private static double _trackStartDsp;

		private static double _sessionStartDsp;

		private static double _lastPulseDsp = double.NegativeInfinity;

		private static long _lastPulseIndex = long.MinValue;

		private static float _lastPulseInterval = -1f;

		private static float _lastPulseOffset = -1f;

		private static bool _wasActive;

		private static float _nextDistanceUpdate;

		private static bool _hasEntrancePosition;

		private static Vector3 _entrancePosition;

		private static float _discAngle;

		private static bool _timerPositionInitialized;

		private static bool _fadingOut;

		private static float _fadeStartTime;

		private static float _fadeDuration;

		private static float _fadeStartOpacity;

		private static string? _cachedBaseColorText;

		private static string? _cachedFlashColorText;

		private static Color _cachedBaseColor = new Color(1f, 0.125f, 0.125f, 1f);

		private static Color _cachedFlashColor = new Color(1f, 0.824f, 0.102f, 1f);

		internal static void Observe(MeltdownHandler handler)
		{
			_handler = handler;
		}

		internal static void OnTrackStarted(string filename)
		{
			_currentTrack = TrackMetadata.Resolve(filename);
			_trackStartDsp = AudioSettings.dspTime;
			_lastPulseDsp = double.NegativeInfinity;
			_lastPulseIndex = long.MinValue;
			_lastPulseInterval = -1f;
			_lastPulseOffset = -1f;
			UpdateTrackText();
			Plugin.ModLog.LogInfo((object)("HUD track metadata: '" + _currentTrack.Title + "', " + (_currentTrack.HasBpm ? $"{_currentTrack.Bpm:0.###} BPM." : "fixed-interval pulse fallback.")));
		}

		internal static void Tick()
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if (_fadingOut)
			{
				UpdateDepartureFade();
				return;
			}
			SyncedConfigSnapshot current = HostConfigSynchronizer.Current;
			if (!current.EnableHud || !IsMeltdownActive())
			{
				if (_wasActive)
				{
					Hide();
				}
				_wasActive = false;
				return;
			}
			if (!_wasActive)
			{
				_sessionStartDsp = AudioSettings.dspTime;
				_lastPulseIndex = long.MinValue;
				_lastPulseDsp = double.NegativeInfinity;
			}
			_wasActive = true;
			HUDManager instance = HUDManager.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.HUDContainer == (Object)null)
			{
				return;
			}
			EnsureCreated(instance);
			if (!((Object)(object)_root == (Object)null))
			{
				if (!instance.HUDContainer.activeInHierarchy)
				{
					Hide();
					return;
				}
				_root.SetActive(true);
				UpdateVisibilityAndLayout(current);
				UpdateTimer();
				UpdateDistance(current);
				UpdateDisc(current);
				ApplySharedColor(CalculatePulseColor(current), current);
			}
		}

		internal static void BeginFadeOut(float seconds)
		{
			if (!_fadingOut)
			{
				if (seconds <= 0f || (Object)(object)_root == (Object)null || !_root.activeSelf || (Object)(object)_canvasGroup == (Object)null)
				{
					ResetSession();
					return;
				}
				_handler = null;
				_wasActive = false;
				_fadingOut = true;
				_fadeStartTime = Time.unscaledTime;
				_fadeDuration = Mathf.Max(0.01f, seconds);
				_fadeStartOpacity = _canvasGroup.alpha;
				Plugin.ModLog.LogDebug((object)$"Fading meltdown HUD out over {_fadeDuration:0.##} seconds.");
			}
		}

		internal static void ResetSession()
		{
			_handler = null;
			_currentTrack = null;
			_trackStartDsp = 0.0;
			_sessionStartDsp = 0.0;
			_lastPulseDsp = double.NegativeInfinity;
			_lastPulseIndex = long.MinValue;
			_lastPulseInterval = -1f;
			_lastPulseOffset = -1f;
			_nextDistanceUpdate = 0f;
			_hasEntrancePosition = false;
			_timerPositionInitialized = false;
			_wasActive = false;
			_fadingOut = false;
			_fadeStartTime = 0f;
			_fadeDuration = 0f;
			_fadeStartOpacity = 0f;
			Hide();
			UpdateTrackText();
		}

		private static void UpdateDepartureFade()
		{
			if ((Object)(object)_root == (Object)null || (Object)(object)_canvasGroup == (Object)null)
			{
				ResetSession();
				return;
			}
			float num = Mathf.Clamp01((Time.unscaledTime - _fadeStartTime) / _fadeDuration);
			_canvasGroup.alpha = _fadeStartOpacity * (1f - num);
			if (num >= 1f)
			{
				ResetSession();
			}
		}

		internal static void Destroy()
		{
			ResetSession();
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			if ((Object)(object)_discSprite != (Object)null)
			{
				Object.Destroy((Object)(object)_discSprite);
			}
			if ((Object)(object)_discTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_discTexture);
			}
			if ((Object)(object)_tonearmSprite != (Object)null)
			{
				Object.Destroy((Object)(object)_tonearmSprite);
			}
			if ((Object)(object)_tonearmTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_tonearmTexture);
			}
			if ((Object)(object)_timerPanelSprite != (Object)null)
			{
				Object.Destroy((Object)(object)_timerPanelSprite);
			}
			if ((Object)(object)_timerPanelTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_timerPanelTexture);
			}
			if ((Object)(object)_timerHighlightSprite != (Object)null)
			{
				Object.Destroy((Object)(object)_timerHighlightSprite);
			}
			if ((Object)(object)_timerHighlightTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_timerHighlightTexture);
			}
			_root = null;
			_rootRect = null;
			_canvasGroup = null;
			_hudCanvas = null;
			_timerRoot = null;
			_timerPanel = null;
			_timerHighlight = null;
			_timerHeader = null;
			_timerSeconds = null;
			_timerHundredths = null;
			_distanceRoot = null;
			_distanceText = null;
			_trackRoot = null;
			_trackHeader = null;
			_trackTitle = null;
			_trackAuthor = null;
			_discRect = null;
			_discImage = null;
			_tonearmImage = null;
			_discTexture = null;
			_discSprite = null;
			_tonearmTexture = null;
			_tonearmSprite = null;
			_timerPanelTexture = null;
			_timerPanelSprite = null;
			_timerHighlightTexture = null;
			_timerHighlightSprite = null;
			_hudManager = null;
			VcrFontFactory.Destroy();
		}

		private static bool IsMeltdownActive()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && instance.shipHasLanded && !instance.inShipPhase)
			{
				return MeltdownAPI.MeltdownStarted;
			}
			return false;
		}

		private static void EnsureCreated(HUDManager hudManager)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			if (!((Object)(object)_root != (Object)null) || _hudManager != hudManager)
			{
				if ((Object)(object)_root != (Object)null)
				{
					Object.Destroy((Object)(object)_root);
				}
				_hudManager = hudManager;
				TMP_FontAsset orCreate = VcrFontFactory.GetOrCreate();
				_root = new GameObject("CombinedMeltdownPlaylist HUD", new Type[2]
				{
					typeof(RectTransform),
					typeof(CanvasGroup)
				});
				Canvas componentInParent = hudManager.HUDContainer.GetComponentInParent<Canvas>();
				Canvas val = (_hudCanvas = ((componentInParent != null) ? componentInParent.rootCanvas : null));
				Transform val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : hudManager.HUDContainer.transform);
				_root.transform.SetParent(val2, false);
				_root.transform.SetAsLastSibling();
				_rootRect = (RectTransform)_root.transform;
				StretchToParent(_rootRect);
				_canvasGroup = _root.GetComponent<CanvasGroup>();
				_canvasGroup.interactable = false;
				_canvasGroup.blocksRaycasts = false;
				BuildTimer(orCreate);
				BuildDistance(orCreate);
				BuildTrackPanel(orCreate);
				UpdateTrackText();
				Plugin.ModLog.LogInfo((object)"Created the meltdown HUD.");
			}
		}

		private static void BuildTimer(TMP_FontAsset font)
		{
			//IL_0014: 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)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			_timerRoot = CreateRect(_rootRect, "Reactor Timer", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(184f, 86f), Vector2.zero);
			_timerPanel = ((Component)CreateRect(_timerRoot, "Rounded Reactor Enclosure", Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(184f, 86f), Vector2.zero)).gameObject.AddComponent<Image>();
			((Graphic)_timerPanel).raycastTarget = false;
			_timerPanelSprite = CreateTimerPanelSprite();
			_timerPanel.sprite = _timerPanelSprite;
			_timerHighlight = ((Component)CreateRect(_timerRoot, "Reactor Border And Separator", Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(184f, 86f), Vector2.zero)).gameObject.AddComponent<Image>();
			((Graphic)_timerHighlight).raycastTarget = false;
			_timerHighlightSprite = CreateTimerHighlightSprite();
			_timerHighlight.sprite = _timerHighlightSprite;
			_timerHeader = CreateText(_timerRoot, "Critical Failure Label", font, 15f, (TextAlignmentOptions)514, new Vector2(8f, 61f), new Vector2(168f, 20f));
			((TMP_Text)_timerHeader).text = "CRITICAL FAILURE";
			_timerSeconds = CreateText(_timerRoot, "Reactor Seconds", font, 51f, (TextAlignmentOptions)4100, new Vector2(7f, 4f), new Vector2(120f, 52f));
			((TMP_Text)_timerSeconds).text = "150";
			_timerHundredths = CreateText(_timerRoot, "Reactor Hundredths", font, 21f, (TextAlignmentOptions)1025, new Vector2(131f, 9f), new Vector2(45f, 31f));
			((TMP_Text)_timerHundredths).text = "00";
		}

		private static void BuildDistance(TMP_FontAsset font)
		{
			//IL_0014: 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)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			_distanceRoot = CreateRect(_rootRect, "Distance", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), new Vector2(380f, 44f), Vector2.zero);
			_distanceText = CreateText(_distanceRoot, "Distance Text", font, 25f, (TextAlignmentOptions)1025, Vector2.zero, new Vector2(380f, 44f));
		}

		private static void BuildTrackPanel(TMP_FontAsset font)
		{
			//IL_0014: 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)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			_trackRoot = CreateRect(_rootRect, "Now Playing", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(1f, 0.5f), new Vector2(338f, 82f), Vector2.zero);
			_discRect = CreateRect(_trackRoot, "Spinning Disc", new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(52f, 52f), new Vector2(27f, 0f));
			_discImage = ((Component)_discRect).gameObject.AddComponent<Image>();
			((Graphic)_discImage).raycastTarget = false;
			_discImage.preserveAspect = true;
			_discSprite = CreateDiscSprite();
			_discImage.sprite = _discSprite;
			_tonearmImage = ((Component)CreateRect(_trackRoot, "Record Player Tonearm", new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(52f, 52f), new Vector2(30f, 4f))).gameObject.AddComponent<Image>();
			((Graphic)_tonearmImage).raycastTarget = false;
			_tonearmImage.preserveAspect = true;
			_tonearmSprite = CreateTonearmSprite();
			_tonearmImage.sprite = _tonearmSprite;
			_trackHeader = CreateText(_trackRoot, "Now Playing Label", font, 13f, (TextAlignmentOptions)1025, new Vector2(59f, 54f), new Vector2(273f, 20f));
			((TMP_Text)_trackHeader).text = "NOW PLAYING";
			_trackTitle = CreateText(_trackRoot, "Track Title", font, 21f, (TextAlignmentOptions)4097, new Vector2(59f, 27f), new Vector2(273f, 31f));
			_trackAuthor = CreateText(_trackRoot, "Track Author", font, 13f, (TextAlignmentOptions)257, new Vector2(59f, 4f), new Vector2(273f, 23f));
		}

		private static void UpdateVisibilityAndLayout(SyncedConfigSnapshot config)
		{
			//IL_00a2: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: 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)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_rootRect == (Object)null) && !((Object)(object)_timerRoot == (Object)null) && !((Object)(object)_distanceRoot == (Object)null) && !((Object)(object)_trackRoot == (Object)null) && !((Object)(object)_timerHundredths == (Object)null) && !((Object)(object)_canvasGroup == (Object)null))
			{
				PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
				bool flag = (Object)(object)val == (Object)null || val.isPlayerDead;
				bool flag2 = (Object)(object)val != (Object)null && val.isInsideFactory;
				bool flag3 = (Object)(object)val != (Object)null && val.isInHangarShipRoom;
				float hudScale = config.HudScale;
				Vector3 localScale = Vector3.one * hudScale;
				((Transform)_timerRoot).localScale = localScale;
				((Transform)_distanceRoot).localScale = localScale;
				((Transform)_trackRoot).localScale = localScale;
				_canvasGroup.alpha = config.HudOpacity;
				((Component)_timerRoot).gameObject.SetActive(config.ShowReactorTimer);
				((Component)_timerHundredths).gameObject.SetActive(config.ShowHundredths);
				if ((Object)(object)_timerPanel != (Object)null)
				{
					((Component)_timerPanel).gameObject.SetActive(config.ShowTimerPanel);
				}
				if ((Object)(object)_timerHighlight != (Object)null)
				{
					((Component)_timerHighlight).gameObject.SetActive(config.ShowTimerPanel);
				}
				bool active = config.ShowDistance && (Object)(object)val != (Object)null && !flag && !flag3;
				((Component)_distanceRoot).gameObject.SetActive(active);
				bool flag4 = config.ShowSelectedTrack && _currentTrack != null;
				((Component)_trackRoot).gameObject.SetActive(flag4);
				if ((Object)(object)_trackAuthor != (Object)null)
				{
					((Component)_trackAuthor).gameObject.SetActive(flag4 && config.ShowTrackAuthor && !string.IsNullOrWhiteSpace(_currentTrack?.Author));
				}
				if ((Object)(object)_discRect != (Object)null)
				{
					((Component)_discRect).gameObject.SetActive(flag4 && config.ShowDisc);
				}
				if ((Object)(object)_tonearmImage != (Object)null)
				{
					((Component)_tonearmImage).gameObject.SetActive(flag4 && config.ShowDisc);
				}
				Vector2 topCenterTimerTarget = GetTopCenterTimerTarget(config, hudScale);
				Vector2 val2 = (flag ? (ScreenToRootLocal(new Vector2(35f, 110f)) + new Vector2(_timerRoot.sizeDelta.x * hudScale * 0.5f + config.SpectatorTimerOffsetX, _timerRoot.sizeDelta.y * hudScale * 0.5f + config.SpectatorTimerOffsetY)) : ((!(flag2 || flag3) && IsOutsideClockVisible()) ? GetOutsideTimerTarget(config, hudScale) : topCenterTimerTarget));
				SetAnchoredLayout(_timerRoot, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), _timerRoot.anchoredPosition);
				if (!_timerPositionInitialized)
				{
					_timerRoot.anchoredPosition = topCenterTimerTarget;
					_timer