Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CombinedMeltdownPlaylist v1.6.0
CombinedMeltdownPlaylistSync.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
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