using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; 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 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.4.1.0")] [assembly: AssemblyInformationalVersion("1.4.1")] [assembly: AssemblyProduct("CombinedMeltdownPlaylistSync")] [assembly: AssemblyTitle("CombinedMeltdownPlaylistSync")] [assembly: AssemblyVersion("1.4.1.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 { [Serializable] internal sealed class SyncedConfigSnapshot { public float ExtraStaminaPercent; public float ExtraStaminaRegenPercent; 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; internal static SyncedConfigSnapshot CaptureLocal() { return new SyncedConfigSnapshot { ExtraStaminaPercent = Plugin.ExtraStaminaPercent.Value, ExtraStaminaRegenPercent = Plugin.ExtraStaminaRegenPercent.Value, EnableHud = HudConfig.EnableHud.Value, HudScale = HudConfig.HudScale.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 }; } internal void Validate() { ExtraStaminaPercent = Mathf.Clamp(ExtraStaminaPercent, 0f, 1000f); ExtraStaminaRegenPercent = Mathf.Clamp(ExtraStaminaRegenPercent, 0f, 1000f); 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); if (!Enum.IsDefined(typeof(DistanceUnit), DistanceUnits)) { DistanceUnits = DistanceUnit.Meters; } if (!Enum.IsDefined(typeof(HudBeatCadence), BeatCadence)) { BeatCadence = HudBeatCadence.EveryFourBeats; } 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 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(text) ?? throw new InvalidOperationException("The host snapshot was empty."); obj.Validate(); _host = obj; Plugin.ModLog.LogInfo((object)"Applied the host's meltdown stamina and HUD 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.v1", 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 static ConfigEntry EnableHud { get; private set; } internal static ConfigEntry HudScale { get; private set; } internal static ConfigEntry HudOpacity { get; private set; } internal static ConfigEntry BaseColor { get; private set; } internal static ConfigEntry FlashColor { get; private set; } internal static ConfigEntry ShowReactorTimer { get; private set; } internal static ConfigEntry ShowHundredths { get; private set; } internal static ConfigEntry ShowTimerPanel { get; private set; } internal static ConfigEntry TimerPanelOpacity { get; private set; } internal static ConfigEntry ShowDistance { get; private set; } internal static ConfigEntry ShowSelectedTrack { get; private set; } internal static ConfigEntry ShowTrackAuthor { get; private set; } internal static ConfigEntry ShowDisc { get; private set; } internal static ConfigEntry DistanceUnits { get; private set; } internal static ConfigEntry DistanceDecimals { get; private set; } internal static ConfigEntry DiscSpinSpeed { get; private set; } internal static ConfigEntry EnableFlashing { get; private set; } internal static ConfigEntry UseTrackBpm { get; private set; } internal static ConfigEntry BeatCadence { get; private set; } internal static ConfigEntry FixedFlashIntervalSeconds { get; private set; } internal static ConfigEntry FlashFadeSeconds { get; private set; } internal static ConfigEntry TimerTransitionSpeed { get; private set; } internal static ConfigEntry OutsideTimerOffsetX { get; private set; } internal static ConfigEntry OutsideTimerOffsetY { get; private set; } internal static ConfigEntry InsideTimerOffsetX { get; private set; } internal static ConfigEntry InsideTimerOffsetY { get; private set; } internal static ConfigEntry SpectatorTimerOffsetX { get; private set; } internal static ConfigEntry SpectatorTimerOffsetY { get; private set; } internal static ConfigEntry DistanceOffsetX { get; private set; } internal static ConfigEntry DistanceOffsetY { get; private set; } internal static ConfigEntry TrackOffsetX { get; private set; } internal static ConfigEntry 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 val = new AcceptableValueRange(0.5f, 2.5f); AcceptableValueRange val2 = new AcceptableValueRange(0.1f, 1f); AcceptableValueRange range = new AcceptableValueRange(-2000f, 2000f); EnableHud = config.Bind("Meltdown HUD - General", "EnableHud", true, "Enable all custom meltdown HUD elements."); HudScale = config.Bind("Meltdown HUD - General", "HudScale", 1f, new ConfigDescription("Global scale for every custom HUD element.", (AcceptableValueBase)(object)val, Array.Empty())); HudOpacity = config.Bind("Meltdown HUD - General", "HudOpacity", 1f, new ConfigDescription("Global opacity for every custom HUD element.", (AcceptableValueBase)(object)val2, Array.Empty())); BaseColor = config.Bind("Meltdown HUD - General", "BaseColor", "#FF2020", "Normal HUD color in HTML hex format."); FlashColor = config.Bind("Meltdown HUD - General", "FlashColor", "#FFD21A", "Beat-flash HUD color in HTML hex format."); ShowReactorTimer = config.Bind("Meltdown HUD - Elements", "ShowReactorTimer", true, "Show the CRITICAL FAILURE countdown."); ShowHundredths = config.Bind("Meltdown HUD - Elements", "ShowHundredths", true, "Show small hundredths next to the large total-seconds countdown."); ShowTimerPanel = config.Bind("Meltdown HUD - Elements", "ShowTimerPanel", true, "Show the rounded translucent reactor enclosure and separator line."); TimerPanelOpacity = config.Bind("Meltdown HUD - Elements", "TimerPanelOpacity", 0.32f, new ConfigDescription("Opacity of the rounded reactor panel background.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ShowDistance = config.Bind("Meltdown HUD - Elements", "ShowDistance", true, "Show distance to the ship outside and main entrance inside."); ShowSelectedTrack = config.Bind("Meltdown HUD - Elements", "ShowSelectedTrack", true, "Show the selected track on the right side."); ShowTrackAuthor = config.Bind("Meltdown HUD - Elements", "ShowTrackAuthor", true, "Show confirmed track authors when available."); ShowDisc = config.Bind("Meltdown HUD - Elements", "ShowDisc", true, "Show the spinning transparent music disc."); DistanceUnits = config.Bind("Meltdown HUD - Elements", "DistanceUnits", DistanceUnit.Meters, "Distance units: Meters, Feet, or GameUnits."); DistanceDecimals = config.Bind("Meltdown HUD - Elements", "DistanceDecimals", 0, new ConfigDescription("Number of decimal places in distance values.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 2), Array.Empty())); DiscSpinSpeed = config.Bind("Meltdown HUD - Elements", "DiscSpinSpeed", 90f, new ConfigDescription("Disc rotation speed in degrees per second. Negative values reverse it.", (AcceptableValueBase)(object)new AcceptableValueRange(-720f, 720f), Array.Empty())); EnableFlashing = config.Bind("Meltdown HUD - Flash", "EnableFlashing", true, "Enable red-to-yellow HUD pulses."); UseTrackBpm = config.Bind("Meltdown HUD - Flash", "UseTrackBpm", true, "Use the current track BPM. If disabled, use FixedFlashIntervalSeconds."); BeatCadence = config.Bind("Meltdown HUD - Flash", "BeatCadence", HudBeatCadence.EveryFourBeats, "Pulse on EveryBeat or EveryFourBeats."); FixedFlashIntervalSeconds = config.Bind("Meltdown HUD - Flash", "FixedFlashIntervalSeconds", 4f, new ConfigDescription("Pulse interval when BPM sync is disabled or metadata is unavailable.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 30f), Array.Empty())); FlashFadeSeconds = config.Bind("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(0.05f, 5f), Array.Empty())); TimerTransitionSpeed = config.Bind("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(0.5f, 30f), Array.Empty())); 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 BindOffset(ConfigFile config, string key, string description, AcceptableValueRange 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("Meltdown HUD - Layout", key, 0f, new ConfigDescription(description, (AcceptableValueBase)(object)range, Array.Empty())); } } 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), "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(); LazyMusicPlayer.Stop(); MeltdownHudController.ResetSession(); } } [HarmonyPatch(typeof(StartOfRound), "ShipLeave")] internal static class ShipLeaveCleanupPatch { [HarmonyPrefix] private static void Prefix() { StaminaBoostController.ForceDeactivate("ship departure"); LazyMusicPlayer.Stop(); MeltdownHudController.ResetSession(); } } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] internal static class EndOfGameCleanupPatch { [HarmonyPrefix] private static void Prefix() { StaminaBoostController.ForceDeactivate("end of round"); LazyMusicPlayer.Stop(); MeltdownHudController.ResetSession(); } } 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()); 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 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 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_00c6: Unknown result type (might be due to invalid IL or missing references) 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 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; Hide(); UpdateTrackText(); } 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 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.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(202f, 94f), Vector2.zero); _timerPanel = ((Component)CreateRect(_timerRoot, "Rounded Reactor Enclosure", Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(202f, 94f), Vector2.zero)).gameObject.AddComponent(); ((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(202f, 94f), Vector2.zero)).gameObject.AddComponent(); ((Graphic)_timerHighlight).raycastTarget = false; _timerHighlightSprite = CreateTimerHighlightSprite(); _timerHighlight.sprite = _timerHighlightSprite; _timerHeader = CreateText(_timerRoot, "Critical Failure Label", font, 17f, (TextAlignmentOptions)514, new Vector2(9f, 66f), new Vector2(184f, 23f)); ((TMP_Text)_timerHeader).text = "CRITICAL FAILURE"; _timerSeconds = CreateText(_timerRoot, "Reactor Seconds", font, 56f, (TextAlignmentOptions)4100, new Vector2(8f, 5f), new Vector2(132f, 58f)); ((TMP_Text)_timerSeconds).text = "150"; _timerHundredths = CreateText(_timerRoot, "Reactor Hundredths", font, 23f, (TextAlignmentOptions)1025, new Vector2(143f, 10f), new Vector2(50f, 34f)); ((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(382f, 94f), 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(61f, 61f), new Vector2(32f, 0f)); _discImage = ((Component)_discRect).gameObject.AddComponent(); ((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(61f, 61f), new Vector2(35f, 5f))).gameObject.AddComponent(); ((Graphic)_tonearmImage).raycastTarget = false; _tonearmImage.preserveAspect = true; _tonearmSprite = CreateTonearmSprite(); _tonearmImage.sprite = _tonearmSprite; _trackHeader = CreateText(_trackRoot, "Now Playing Label", font, 15f, (TextAlignmentOptions)1025, new Vector2(70f, 62f), new Vector2(305f, 23f)); ((TMP_Text)_trackHeader).text = "NOW PLAYING"; _trackTitle = CreateText(_trackRoot, "Track Title", font, 23f, (TextAlignmentOptions)4097, new Vector2(70f, 31f), new Vector2(305f, 35f)); _trackAuthor = CreateText(_trackRoot, "Track Author", font, 15f, (TextAlignmentOptions)257, new Vector2(70f, 5f), new Vector2(305f, 26f)); } 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_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: 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_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: 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; _timerPositionInitialized = true; } float num = 1f - Mathf.Exp((0f - config.TimerTransitionSpeed) * Time.unscaledDeltaTime); _timerRoot.anchoredPosition = Vector2.Lerp(_timerRoot.anchoredPosition, val2, num); Vector2 anchoredPosition = ScreenToRootLocal(new Vector2(35f, 22f)) + new Vector2(config.DistanceOffsetX, config.DistanceOffsetY); SetAnchoredLayout(_distanceRoot, new Vector2(0.5f, 0.5f), Vector2.zero, anchoredPosition); Vector2 anchoredPosition2 = ScreenToRootLocal(new Vector2((float)Screen.width - 22f, (float)Screen.height * 0.5f)) + new Vector2(config.TrackOffsetX, config.TrackOffsetY); SetAnchoredLayout(_trackRoot, new Vector2(0.5f, 0.5f), new Vector2(1f, 0.5f), anchoredPosition2); } } private static Vector2 GetTopCenterTimerTarget(SyncedConfigSnapshot config, float scale) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_000d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_timerRoot == (Object)null) { return Vector2.zero; } return ScreenToRootLocal(new Vector2((float)Screen.width * 0.5f, (float)Screen.height - 24f)) + new Vector2(config.InsideTimerOffsetX, (0f - _timerRoot.sizeDelta.y) * scale * 0.5f + config.InsideTimerOffsetY); } private static Vector2 GetOutsideTimerTarget(SyncedConfigSnapshot config, float scale) { //IL_000f: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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) //IL_0075: 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_0081: 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_00b0: 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_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_timerRoot == (Object)null) { return GetTopCenterTimerTarget(config, scale); } HUDManager? hudManager = _hudManager; object obj; if (hudManager == null) { obj = null; } else { TextMeshProUGUI clockNumber = hudManager.clockNumber; obj = ((clockNumber != null) ? ((TMP_Text)clockNumber).rectTransform : null); } RectTransform val = (RectTransform)obj; if ((Object)(object)val == (Object)null) { return GetTopCenterTimerTarget(config, scale); } Rect rect = val.rect; float xMax = ((Rect)(ref rect)).xMax; rect = val.rect; Vector3 val2 = ((Transform)val).TransformPoint(new Vector3(xMax, ((Rect)(ref rect)).center.y, 0f)); return ScreenToRootLocal(RectTransformUtility.WorldToScreenPoint(GetHudCamera(), val2)) + new Vector2(50f + _timerRoot.sizeDelta.x * scale * 0.5f + config.OutsideTimerOffsetX, config.OutsideTimerOffsetY); } private static bool IsOutsideClockVisible() { TextMeshProUGUI val = _hudManager?.clockNumber; if ((Object)(object)val != (Object)null && ((Behaviour)val).enabled) { return ((Component)val).gameObject.activeInHierarchy; } return false; } private static Vector2 ScreenToRootLocal(Vector2 screenPosition) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) Vector2 result = default(Vector2); if ((Object)(object)_rootRect != (Object)null && RectTransformUtility.ScreenPointToLocalPointInRectangle(_rootRect, screenPosition, GetHudCamera(), ref result)) { return result; } return Vector2.zero; } private static Camera? GetHudCamera() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_hudCanvas == (Object)null || (int)_hudCanvas.renderMode == 0) { return null; } return _hudCanvas.worldCamera; } private static void UpdateTimer() { if (!((Object)(object)_timerSeconds == (Object)null) && !((Object)(object)_timerHundredths == (Object)null)) { int num = Mathf.FloorToInt((((Object)(object)_handler == (Object)null) ? 0f : Mathf.Max(0f, _handler.TimeLeftUntilMeltdown)) * 100f + 0.001f); int num2 = num / 100; int num3 = num % 100; ((TMP_Text)_timerSeconds).text = num2.ToString(CultureInfo.InvariantCulture); ((TMP_Text)_timerHundredths).text = num3.ToString("00", CultureInfo.InvariantCulture); } } private static void UpdateDistance(SyncedConfigSnapshot config) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_distanceRoot == (Object)null || !((Component)_distanceRoot).gameObject.activeSelf || (Object)(object)_distanceText == (Object)null || Time.unscaledTime < _nextDistanceUpdate) { return; } _nextDistanceUpdate = Time.unscaledTime + 0.1f; PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return; } Vector3 val2; string text; if (val.isInsideFactory) { if (!_hasEntrancePosition) { _entrancePosition = RoundManager.FindMainEntrancePosition(true, false); _hasEntrancePosition = _entrancePosition != Vector3.zero; } if (!_hasEntrancePosition) { ((TMP_Text)_distanceText).text = "ENTRANCE --"; return; } val2 = _entrancePosition; text = "ENTRANCE"; } else { Transform val3 = StartOfRound.Instance?.shipDoorNode; if ((Object)(object)val3 == (Object)null) { ((TMP_Text)_distanceText).text = "SHIP --"; return; } val2 = val3.position; text = "SHIP"; } float num = Vector3.Distance(((Component)val).transform.position, val2); string text2; switch (config.DistanceUnits) { case DistanceUnit.Feet: num *= 3.28084f; text2 = "FT"; break; case DistanceUnit.GameUnits: text2 = "U"; break; default: text2 = "M"; break; } int distanceDecimals = config.DistanceDecimals; string text3 = "F" + distanceDecimals.ToString(CultureInfo.InvariantCulture); ((TMP_Text)_distanceText).text = text + " " + num.ToString(text3, CultureInfo.InvariantCulture) + " " + text2; } private static void UpdateDisc(SyncedConfigSnapshot config) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_discRect == (Object)null) && ((Component)_discRect).gameObject.activeSelf) { _discAngle = Mathf.Repeat(_discAngle - config.DiscSpinSpeed * Time.unscaledDeltaTime, 360f); ((Transform)_discRect).localRotation = Quaternion.Euler(0f, 0f, _discAngle); } } private static Color CalculatePulseColor(SyncedConfigSnapshot config) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) Color val = ResolveConfiguredColor(config.BaseColor, ref _cachedBaseColorText, ref _cachedBaseColor, new Color(1f, 0.125f, 0.125f, 1f), "BaseColor"); Color val2 = ResolveConfiguredColor(config.FlashColor, ref _cachedFlashColorText, ref _cachedFlashColor, new Color(1f, 0.824f, 0.102f, 1f), "FlashColor"); if (!config.EnableFlashing) { return val; } float num2; float num3; double num4; if (config.UseTrackBpm && _currentTrack != null && _currentTrack.HasBpm) { int num = ((config.BeatCadence != HudBeatCadence.EveryFourBeats) ? 1 : 4); num2 = 60f / _currentTrack.Bpm * (float)num; num3 = Mathf.Max(0f, _currentTrack.BeatOffsetSeconds); num4 = _trackStartDsp; } else { num2 = Mathf.Clamp(config.FixedFlashIntervalSeconds, 0.25f, 30f); num3 = 0f; num4 = ((_trackStartDsp > 0.0) ? _trackStartDsp : _sessionStartDsp); } if (!Mathf.Approximately(num2, _lastPulseInterval) || !Mathf.Approximately(num3, _lastPulseOffset)) { _lastPulseInterval = num2; _lastPulseOffset = num3; _lastPulseIndex = long.MinValue; _lastPulseDsp = double.NegativeInfinity; } double dspTime = AudioSettings.dspTime; double num5 = dspTime - num4 - (double)num3; if (num5 >= 0.0) { long num6 = (long)Math.Floor(num5 / (double)num2); if (num6 != _lastPulseIndex) { _lastPulseIndex = num6; _lastPulseDsp = num4 + (double)num3 + (double)((float)num6 * num2); } } float num7 = Mathf.Min(config.FlashFadeSeconds, num2 * 0.75f); float num8 = (float)(dspTime - _lastPulseDsp); if (num8 < 0f || num8 >= num7) { return val; } return Color.Lerp(val2, val, Mathf.Clamp01(num8 / num7)); } private static Color ResolveConfiguredColor(string configuredValue, ref string? cachedText, ref Color cachedColor, Color fallback, string settingName) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0041: Unknown result type (might be due to invalid IL or missing references) if (string.Equals(cachedText, configuredValue, StringComparison.Ordinal)) { return cachedColor; } cachedText = configuredValue; Color val = default(Color); if (ColorUtility.TryParseHtmlString(configuredValue.StartsWith("#", StringComparison.Ordinal) ? configuredValue : ("#" + configuredValue), ref val)) { cachedColor = val; return val; } cachedColor = fallback; Plugin.ModLog.LogWarning((object)("Invalid HUD " + settingName + " '" + configuredValue + "'; using the default.")); return fallback; } private static void ApplySharedColor(Color color, SyncedConfigSnapshot config) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00ab: 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) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) ApplyTextColor(_timerHeader, color); ApplyTextColor(_timerSeconds, color); ApplyTextColor(_timerHundredths, color); ApplyTextColor(_distanceText, color); ApplyTextColor(_trackHeader, color); ApplyTextColor(_trackTitle, color); ApplyTextColor(_trackAuthor, color); if ((Object)(object)_discImage != (Object)null) { ((Graphic)_discImage).color = new Color(color.r, color.g, color.b, color.a * 0.78f); } if ((Object)(object)_tonearmImage != (Object)null) { ((Graphic)_tonearmImage).color = new Color(color.r, color.g, color.b, color.a * 0.88f); } if ((Object)(object)_timerPanel != (Object)null) { ((Graphic)_timerPanel).color = new Color(0f, 0f, 0f, config.TimerPanelOpacity); } if ((Object)(object)_timerHighlight != (Object)null) { ((Graphic)_timerHighlight).color = new Color(color.r, color.g, color.b, color.a * 0.9f); } } private static void ApplyTextColor(TextMeshProUGUI? text, Color color) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)text != (Object)null) { ((Graphic)text).color = color; } } private static void UpdateTrackText() { if (!((Object)(object)_trackTitle == (Object)null) && !((Object)(object)_trackAuthor == (Object)null)) { if (_currentTrack == null) { ((TMP_Text)_trackTitle).text = string.Empty; ((TMP_Text)_trackAuthor).text = string.Empty; } else { ((TMP_Text)_trackTitle).text = _currentTrack.Title; ((TMP_Text)_trackAuthor).text = (string.IsNullOrWhiteSpace(_currentTrack.Author) ? string.Empty : ("BY " + _currentTrack.Author)); } } } private static TextMeshProUGUI CreateText(RectTransform parent, string name, TMP_FontAsset font, float fontSize, TextAlignmentOptions alignment, Vector2 anchoredPosition, Vector2 size) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI obj = ((Component)CreateRect(parent, name, Vector2.zero, Vector2.zero, Vector2.zero, size, anchoredPosition)).gameObject.AddComponent(); ((TMP_Text)obj).font = font; ((TMP_Text)obj).fontSize = fontSize; ((TMP_Text)obj).fontStyle = (FontStyles)0; ((TMP_Text)obj).alignment = alignment; ((TMP_Text)obj).enableWordWrapping = false; ((TMP_Text)obj).overflowMode = (TextOverflowModes)1; ((Graphic)obj).raycastTarget = false; ((TMP_Text)obj).outlineWidth = 0.12f; ((TMP_Text)obj).outlineColor = new Color32((byte)20, (byte)0, (byte)0, (byte)210); ((TMP_Text)obj).margin = Vector4.zero; return obj; } private static RectTransform CreateRect(RectTransform parent, string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 size, Vector2 anchoredPosition) { //IL_0014: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform; ((Transform)val).SetParent((Transform)(object)parent, false); val.anchorMin = anchorMin; val.anchorMax = anchorMax; val.pivot = pivot; val.sizeDelta = size; val.anchoredPosition = anchoredPosition; return val; } private static void StretchToParent(RectTransform rect) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.pivot = new Vector2(0.5f, 0.5f); rect.offsetMin = Vector2.zero; rect.offsetMax = Vector2.zero; } private static void SetAnchoredLayout(RectTransform rect, Vector2 anchor, Vector2 pivot, Vector2 anchoredPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_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) rect.anchorMin = anchor; rect.anchorMax = anchor; rect.pivot = pivot; rect.anchoredPosition = anchoredPosition; } private static Sprite CreateDiscSprite() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_017b: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) _discTexture = new Texture2D(64, 64, (TextureFormat)4, false) { name = "Combined Meltdown Music Disc", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color[] array = (Color[])(object)new Color[4096]; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(31.5f, 31.5f); float num = 30.08f; float num2 = 7.68f; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { Vector2 val2 = new Vector2((float)j, (float)i) - val; float magnitude = ((Vector2)(ref val2)).magnitude; Color clear = Color.clear; if (magnitude <= num && magnitude >= num2) { float num3 = Mathf.SmoothStep(0f, 1f, (num - magnitude) / 1.5f); float num4 = 0.48f + 0.18f * Mathf.Sin(magnitude * 1.35f); float num5 = Mathf.Clamp01((val2.x - val2.y + 8f) / 18f) * 0.18f; ((Color)(ref clear))..ctor(1f, 1f, 1f, Mathf.Clamp01((num4 + num5) * num3)); } array[i * 64 + j] = clear; } } _discTexture.SetPixels(array); _discTexture.Apply(false, true); Sprite obj = Sprite.Create(_discTexture, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f); ((Object)obj).name = "Combined Meltdown Music Disc"; ((Object)obj).hideFlags = (HideFlags)61; return obj; } private static Sprite CreateTonearmSprite() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) _tonearmTexture = new Texture2D(64, 64, (TextureFormat)4, false) { name = "Combined Meltdown Record Player Tonearm", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color[] array = (Color[])(object)new Color[4096]; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(54f, 55f); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(45f, 43f); Vector2 end = default(Vector2); ((Vector2)(ref end))..ctor(39f, 37f); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { Vector2 val3 = new Vector2((float)j, (float)i); float num = Vector2.Distance(val3, val); float num2 = DistanceToSegment(val3, val, val2); float num3 = DistanceToSegment(val3, val2, end); float num4 = 0f; if (num <= 5.5f) { num4 = ((num >= 2.4f) ? 0.95f : 0.32f); } if (num2 <= 1.8f) { num4 = Mathf.Max(num4, 0.92f); } if (num3 <= 3.1f) { num4 = Mathf.Max(num4, 1f); } array[i * 64 + j] = new Color(1f, 1f, 1f, num4); } } _tonearmTexture.SetPixels(array); _tonearmTexture.Apply(false, true); Sprite obj = Sprite.Create(_tonearmTexture, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f); ((Object)obj).name = "Combined Meltdown Record Player Tonearm"; ((Object)obj).hideFlags = (HideFlags)61; return obj; } private static Sprite CreateTimerPanelSprite() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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) _timerPanelTexture = new Texture2D(202, 94, (TextureFormat)4, false) { name = "Combined Meltdown Rounded Reactor Panel", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color[] array = (Color[])(object)new Color[18988]; Vector2 center = default(Vector2); ((Vector2)(ref center))..ctor(100.5f, 46.5f); Vector2 halfSize = default(Vector2); ((Vector2)(ref halfSize))..ctor(100.5f, 46.5f); for (int i = 0; i < 94; i++) { for (int j = 0; j < 202; j++) { float num = ((RoundedRectangleDistance(j, i, center, halfSize, 11f) <= -1f) ? 0.95f : 0f); array[i * 202 + j] = new Color(1f, 1f, 1f, num); } } _timerPanelTexture.SetPixels(array); _timerPanelTexture.Apply(false, true); Sprite obj = Sprite.Create(_timerPanelTexture, new Rect(0f, 0f, 202f, 94f), new Vector2(0.5f, 0.5f), 100f); ((Object)obj).name = "Combined Meltdown Rounded Reactor Panel"; ((Object)obj).hideFlags = (HideFlags)61; return obj; } private static Sprite CreateTimerHighlightSprite() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_0076: 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_00f7: Unknown result type (might be due to invalid IL or missing references) _timerHighlightTexture = new Texture2D(202, 94, (TextureFormat)4, false) { name = "Combined Meltdown Reactor Highlight", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color[] array = (Color[])(object)new Color[18988]; Vector2 center = default(Vector2); ((Vector2)(ref center))..ctor(100.5f, 46.5f); Vector2 halfSize = default(Vector2); ((Vector2)(ref halfSize))..ctor(100.5f, 46.5f); for (int i = 0; i < 94; i++) { for (int j = 0; j < 202; j++) { float num = RoundedRectangleDistance(j, i, center, halfSize, 11f); bool num2 = num <= 0f && num >= -2f; bool flag = Mathf.Abs((float)i - 63f) <= 1f && j >= 9 && j < 193; float num3 = ((num2 || flag) ? 0.96f : 0f); array[i * 202 + j] = new Color(1f, 1f, 1f, num3); } } _timerHighlightTexture.SetPixels(array); _timerHighlightTexture.Apply(false, true); Sprite obj = Sprite.Create(_timerHighlightTexture, new Rect(0f, 0f, 202f, 94f), new Vector2(0.5f, 0.5f), 100f); ((Object)obj).name = "Combined Meltdown Reactor Highlight"; ((Object)obj).hideFlags = (HideFlags)61; return obj; } private static float RoundedRectangleDistance(float x, float y, Vector2 center, Vector2 halfSize, float cornerRadius) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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) Vector2 val = new Vector2(Mathf.Abs(x - center.x), Mathf.Abs(y - center.y)) - (halfSize - Vector2.one * cornerRadius); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(Mathf.Max(val.x, 0f), Mathf.Max(val.y, 0f)); return Mathf.Min(Mathf.Max(val.x, val.y), 0f) + ((Vector2)(ref val2)).magnitude - cornerRadius; } private static float DistanceToSegment(Vector2 point, Vector2 start, Vector2 end) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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) Vector2 val = end - start; float sqrMagnitude = ((Vector2)(ref val)).sqrMagnitude; if (sqrMagnitude <= Mathf.Epsilon) { return Vector2.Distance(point, start); } float num = Mathf.Clamp01(Vector2.Dot(point - start, val) / sqrMagnitude); return Vector2.Distance(point, start + val * num); } private static void Hide() { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } } } [BepInPlugin("combinedmeltdownplaylist.sync", "Combined Meltdown Playlist Sync", "1.4.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("Lethal Company.exe")] public sealed class Plugin : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__HandleSelectionMessage; public static HandleNamedMessageDelegate <1>__Receive; } public const string PluginGuid = "combinedmeltdownplaylist.sync"; public const string PluginName = "Combined Meltdown Playlist Sync"; public const string PluginVersion = "1.4.1"; internal const string PlaylistTag = "CombinedMeltdownPlaylist"; internal const string SelectionMessageName = "CombinedMeltdownPlaylist.Selection.v1"; internal const string ConfigMessageName = "CombinedMeltdownPlaylist.Config.v1"; private Harmony? _harmony; internal static Plugin Instance { get; private set; } internal static ManualLogSource ModLog { get; private set; } internal static NetworkManager? RegisteredNetworkManager { get; private set; } internal static ConfigEntry ExtraStaminaPercent { get; private set; } internal static ConfigEntry ExtraStaminaRegenPercent { get; private set; } private void Awake() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown Instance = this; ModLog = ((BaseUnityPlugin)this).Logger; AcceptableValueRange val = new AcceptableValueRange(0f, 1000f); ExtraStaminaPercent = ((BaseUnityPlugin)this).Config.Bind("Meltdown Stamina", "ExtraStaminaPercent", 20f, new ConfigDescription("Percentage of extra effective stamina capacity during a meltdown. For example, 20 means 20% more stamina. Applied to the final stamina drain so upgrades from other mods remain included.", (AcceptableValueBase)(object)val, Array.Empty())); ExtraStaminaRegenPercent = ((BaseUnityPlugin)this).Config.Bind("Meltdown Stamina", "ExtraStaminaRegenPercent", 50f, new ConfigDescription("Percentage of extra stamina regeneration during a meltdown. For example, 50 means regeneration is 50% faster. Applied to the final regeneration produced by the game and other mods.", (AcceptableValueBase)(object)val, Array.Empty())); HudConfig.Bind(((BaseUnityPlugin)this).Config); HostConfigSynchronizer.Reset(); _harmony = new Harmony("combinedmeltdownplaylist.sync"); _harmony.PatchAll(); ModLog.LogInfo((object)"Combined Meltdown Playlist Sync 1.4.1 loaded."); } private void Update() { EnsureNetworkRegistration(); HostConfigSynchronizer.Tick(); LazyMusicPlayer.Tick(); StaminaBoostController.Tick(); ForcedTakeoffFailsafe.Tick(); MeltdownHudController.Tick(); } private void OnDestroy() { StaminaBoostController.ForceDeactivate("plugin shutdown"); ForcedTakeoffFailsafe.Reset(); LazyMusicPlayer.Stop(); UnregisterMessageHandlers(); SelectionCoordinator.Reset(); HostConfigSynchronizer.Reset(); MeltdownHudController.Destroy(); Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static void EnsureNetworkRegistration() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (singleton == RegisteredNetworkManager && ((Object)(object)singleton == (Object)null || singleton.IsListening)) { return; } UnregisterMessageHandlers(); SelectionCoordinator.Reset(); HostConfigSynchronizer.Reset(); MeltdownHudController.ResetSession(); if ((Object)(object)singleton == (Object)null || !singleton.IsListening) { return; } try { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__HandleSelectionMessage; if (obj == null) { HandleNamedMessageDelegate val = HandleSelectionMessage; <>O.<0>__HandleSelectionMessage = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("CombinedMeltdownPlaylist.Selection.v1", (HandleNamedMessageDelegate)obj); CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager; object obj2 = <>O.<1>__Receive; if (obj2 == null) { HandleNamedMessageDelegate val2 = HostConfigSynchronizer.Receive; <>O.<1>__Receive = val2; obj2 = (object)val2; } customMessagingManager2.RegisterNamedMessageHandler("CombinedMeltdownPlaylist.Config.v1", (HandleNamedMessageDelegate)obj2); RegisteredNetworkManager = singleton; HostConfigSynchronizer.ForceBroadcast(); ModLog.LogDebug((object)"Registered the synchronized playlist and host-config message handlers."); } catch (Exception arg) { ModLog.LogError((object)$"Could not register the synchronization message handlers: {arg}"); } } private static void UnregisterMessageHandlers() { if ((Object)(object)RegisteredNetworkManager == (Object)null) { return; } try { RegisteredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("CombinedMeltdownPlaylist.Selection.v1"); RegisteredNetworkManager.CustomMessagingManager.UnregisterNamedMessageHandler("CombinedMeltdownPlaylist.Config.v1"); } catch (Exception ex) { ModLog.LogDebug((object)("Message handlers were already unavailable: " + ex.Message)); } finally { RegisteredNetworkManager = null; } } private static void HandleSelectionMessage(ulong senderClientId, FastBufferReader reader) { NetworkManager registeredNetworkManager = RegisteredNetworkManager; if ((Object)(object)registeredNetworkManager == (Object)null || registeredNetworkManager.IsServer) { return; } if (senderClientId != 0L) { ModLog.LogWarning((object)$"Ignored a playlist selection from non-host client {senderClientId}."); return; } try { string selectedTrack = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref selectedTrack, true); SelectionCoordinator.ReceiveHostSelection(selectedTrack); } catch (Exception arg) { ModLog.LogError((object)$"Could not read the host's playlist selection: {arg}"); } } internal unsafe static bool BroadcastSelection(string selectedTrack) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) NetworkManager registeredNetworkManager = RegisteredNetworkManager; if ((Object)(object)registeredNetworkManager == (Object)null || !registeredNetworkManager.IsListening || !registeredNetworkManager.IsServer) { return false; } try { HostConfigSynchronizer.ForceBroadcast(); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(512, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(selectedTrack, true); registeredNetworkManager.CustomMessagingManager.SendNamedMessageToAll("CombinedMeltdownPlaylist.Selection.v1", val, (NetworkDelivery)3); return true; } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } catch (Exception arg) { ModLog.LogError((object)$"Could not broadcast the playlist selection: {arg}"); return false; } } } [HarmonyPatch(typeof(MusicManager), "LoadMusicClip")] internal static class MusicManagerLoadMusicClipPatch { private static bool Prefix(string musicFileName, ref Task __result) { if (!TrackMetadata.Contains(musicFileName)) { return true; } __result = Task.FromResult(null); return false; } } [HarmonyPatch(typeof(MusicManager), "PlayMusic")] internal static class MusicManagerPlayMusicPatch { private static bool Prefix(MusicManager __instance, Script script, ScriptEvent_PlayMusic musicEvent) { if (!string.Equals(musicEvent.tag, "CombinedMeltdownPlaylist", StringComparison.Ordinal)) { return true; } SelectionCoordinator.Intercept(__instance, script, musicEvent); return false; } } [HarmonyPatch(typeof(MusicManager), "StopMusic")] internal static class MusicManagerStopMusicPatch { private static void Postfix(string? targetTag = null) { if (targetTag == null || string.Equals(targetTag, "CombinedMeltdownPlaylist", StringComparison.Ordinal)) { LazyMusicPlayer.Stop(); } } } [HarmonyPatch(typeof(MusicManager), "FadeStopMusic")] internal static class MusicManagerFadeStopMusicPatch { private static void Postfix(string? targetTag = null) { if (targetTag == null || string.Equals(targetTag, "CombinedMeltdownPlaylist", StringComparison.Ordinal)) { LazyMusicPlayer.Stop(); } } } internal static class SelectionCoordinator { private static MusicManager? _waitingManager; private static Script? _waitingScript; private static ScriptEvent_PlayMusic? _waitingEvent; private static string? _pendingSelection; internal static void Intercept(MusicManager manager, Script script, ScriptEvent_PlayMusic musicEvent) { string[] musicNames = musicEvent.musicNames; if (musicNames == null || musicNames.Length == 0) { Plugin.ModLog.LogError((object)"The combined meltdown playlist has no tracks."); return; } _waitingManager = manager; _waitingScript = script; _waitingEvent = musicEvent; NetworkManager registeredNetworkManager = Plugin.RegisteredNetworkManager; if ((Object)(object)registeredNetworkManager == (Object)null || !registeredNetworkManager.IsListening) { string selectedTrack = musicNames[Random.Range(0, musicNames.Length)]; Plugin.ModLog.LogWarning((object)"Networking was not ready; selecting the meltdown track locally."); StartSelectedTrack(manager, script, musicEvent, selectedTrack); Reset(); } else if (registeredNetworkManager.IsServer) { string text = musicNames[Random.Range(0, musicNames.Length)]; if (!Plugin.BroadcastSelection(text)) { Plugin.ModLog.LogWarning((object)"The host selection could not be broadcast; playing it locally."); } Plugin.ModLog.LogInfo((object)("Host selected meltdown track: " + text)); StartSelectedTrack(manager, script, musicEvent, text); Reset(); } else if (!registeredNetworkManager.IsClient) { Reset(); } else if (_pendingSelection == null) { Plugin.ModLog.LogDebug((object)"Waiting for the host's meltdown track selection."); } else { string pendingSelection = _pendingSelection; _pendingSelection = null; PlayReceivedSelection(manager, script, musicEvent, pendingSelection); } } internal static void ReceiveHostSelection(string selectedTrack) { if (string.IsNullOrWhiteSpace(selectedTrack)) { Plugin.ModLog.LogWarning((object)"Ignored an empty playlist selection from the host."); } else if ((Object)(object)_waitingManager == (Object)null || _waitingScript == null || _waitingEvent == null) { _pendingSelection = selectedTrack; Plugin.ModLog.LogDebug((object)("Stored the host's early playlist selection: " + selectedTrack)); } else { PlayReceivedSelection(_waitingManager, _waitingScript, _waitingEvent, selectedTrack); } } internal static void Reset() { _waitingManager = null; _waitingScript = null; _waitingEvent = null; _pendingSelection = null; } private static void PlayReceivedSelection(MusicManager manager, Script script, ScriptEvent_PlayMusic musicEvent, string selectedTrack) { if (!ContainsChoice(musicEvent.musicNames, selectedTrack)) { Plugin.ModLog.LogError((object)("The host selected '" + selectedTrack + "', but it is not in this client's playlist. All players must install the same package version.")); Reset(); } else { Plugin.ModLog.LogInfo((object)("Streaming host-selected meltdown track: " + selectedTrack)); StartSelectedTrack(manager, script, musicEvent, selectedTrack); Reset(); } } private static void StartSelectedTrack(MusicManager manager, Script script, ScriptEvent_PlayMusic musicEvent, string selectedTrack) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected I4, but got Unknown OverlapHandling overlapHandling = musicEvent.overlapHandling; switch (overlapHandling - 2) { case 0: manager.StopMusic((string)null); break; case 1: manager.StopMusic(musicEvent.tag); break; case 2: manager.FadeStopMusic((string)null); break; case 3: manager.FadeStopMusic(musicEvent.tag); break; } LazyMusicPlayer.Play(script, musicEvent, selectedTrack); } private static bool ContainsChoice(string[] choices, string selectedTrack) { for (int i = 0; i < choices.Length; i++) { if (string.Equals(choices[i], selectedTrack, StringComparison.Ordinal)) { return true; } } return false; } } internal static class LazyMusicPlayer { private static readonly FieldInfo? MasterVolumeField = AccessTools.Field(typeof(Configuration), "volumeMaster"); private static Coroutine? _loadCoroutine; private static AudioSource? _audioSource; private static AudioClip? _audioClip; private static float _scriptVolume = 1f; private static bool _silenceGameMusic; private static int _playGeneration; internal static void Play(Script script, ScriptEvent_PlayMusic musicEvent, string filename) { Stop(); _playGeneration++; int playGeneration = _playGeneration; _scriptVolume = script.TryGetVolumeGroupOrDefault(musicEvent.tag).GetVolume(script); _silenceGameMusic = musicEvent.silenceGameMusic; _loadCoroutine = ((MonoBehaviour)Plugin.Instance).StartCoroutine(LoadAndPlay(filename, musicEvent, playGeneration)); } internal static void Tick() { if ((Object)(object)_audioSource == (Object)null || !_audioSource.isPlaying) { return; } _audioSource.volume = _scriptVolume * GetMasterVolume(); if (_silenceGameMusic) { if ((Object)(object)SoundManager.Instance != (Object)null && SoundManager.Instance.playingOutsideMusic) { SoundManager.Instance.playingOutsideMusic = false; } if ((Object)(object)TimeOfDay.Instance != (Object)null && (Object)(object)TimeOfDay.Instance.TimeOfDayMusic != (Object)null && TimeOfDay.Instance.TimeOfDayMusic.isPlaying) { TimeOfDay.Instance.TimeOfDayMusic.Stop(); } } } internal static void Stop() { _playGeneration++; if (_loadCoroutine != null && (Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StopCoroutine(_loadCoroutine); _loadCoroutine = null; } if ((Object)(object)_audioSource != (Object)null) { _audioSource.Stop(); Object.Destroy((Object)(object)_audioSource); _audioSource = null; } if ((Object)(object)_audioClip != (Object)null) { _audioClip.UnloadAudioData(); Object.Destroy((Object)(object)_audioClip); _audioClip = null; } _silenceGameMusic = false; } private static IEnumerator LoadAndPlay(string filename, ScriptEvent_PlayMusic musicEvent, int generation) { string text = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location) ?? Paths.PluginPath, "BGN-PizzaTowerEscapeMusic", "Music", filename); if (!File.Exists(text)) { Plugin.ModLog.LogError((object)("Cannot stream meltdown music because the file is missing: " + text)); yield break; } string absoluteUri = new Uri(text).AbsoluteUri; UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)14); try { DownloadHandler downloadHandler = request.downloadHandler; DownloadHandlerAudioClip val = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null); if (val != null) { val.streamAudio = true; } request.SendWebRequest(); while (!request.isDone) { yield return null; } if (generation != _playGeneration) { yield break; } if ((int)request.result != 1) { Plugin.ModLog.LogError((object)("Could not stream meltdown track '" + filename + "': " + request.error)); yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { Plugin.ModLog.LogError((object)("Streaming returned no audio clip for '" + filename + "'.")); yield break; } ((Object)content).name = filename; _audioClip = content; _audioSource = ((Component)Plugin.Instance).gameObject.AddComponent(); _audioSource.clip = content; _audioSource.loop = musicEvent.loop; _audioSource.bypassEffects = musicEvent.bypassEffects; _audioSource.bypassListenerEffects = musicEvent.bypassEffects; _audioSource.bypassReverbZones = musicEvent.bypassEffects; _audioSource.spatialBlend = 0f; _audioSource.volume = _scriptVolume * GetMasterVolume(); _audioSource.Play(); _loadCoroutine = null; MeltdownHudController.OnTrackStarted(filename); Plugin.ModLog.LogInfo((object)("On-demand stream started for meltdown track: " + filename)); } finally { ((IDisposable)request)?.Dispose(); } } private static float GetMasterVolume() { try { Configuration configuration = PizzaTowerEscapeMusicManager.Configuration; if (configuration != null && MasterVolumeField?.GetValue(configuration) is ConfigEntry val) { return Mathf.Max(0f, val.Value); } } catch (Exception ex) { Plugin.ModLog.LogDebug((object)("Could not read PizzaTowerEscapeMusic master volume: " + ex.Message)); } return 0.5f; } } internal sealed class TrackInfo { internal string Filename { get; } internal string Title { get; } internal string? Author { get; } internal float Bpm { get; } internal float BeatOffsetSeconds { get; } internal bool HasBpm => Bpm > 0f; internal TrackInfo(string filename, string title, string? author, float bpm, float beatOffsetSeconds) { Filename = filename; Title = title; Author = author; Bpm = bpm; BeatOffsetSeconds = beatOffsetSeconds; } } internal static class TrackMetadata { private static readonly Dictionary Tracks = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["grace-meltdown-actions.ogg"] = Track("grace-meltdown-actions.ogg", "ACTION & CONSEQUENCES", "Sebastian Fennec", 123.047f, 0.163f), ["grace-meltdown-carnation.ogg"] = Track("grace-meltdown-carnation.ogg", "Carnation (CST)", "marshall4", 123.047f, 0.163f), ["grace-meltdown-clock.ogg"] = Track("grace-meltdown-clock.ogg", "Clocktower Mayhem", "Sebastian Fennec", 151.999f, 0.139f), ["grace-meltdown-clot.ogg"] = Track("grace-meltdown-clot.ogg", "Bloody Devastation", "Phill C.", 123.047f, 0.511f), ["grace-meltdown-goob.ogg"] = Track("grace-meltdown-goob.ogg", "For the Greater Goob (CST)", "mich", 123.047f, 0.139f), ["grace-meltdown-lst.ogg"] = Track("grace-meltdown-lst.ogg", "Mayhem Last Soul Standing", null, 99.384f, 0.163f), ["grace-meltdown-nede.ogg"] = Track("grace-meltdown-nede.ogg", "SPEAK NO EVIL", "Sebastian Fennec", 107.666f, 0.163f), ["grace-meltdown.ogg"] = Track("grace-meltdown.ogg", "ULTRASONIC FAITH", "Phill C.", 129.199f, 0.163f), ["labirhin-apa-makna-nya.ogg"] = Track("labirhin-apa-makna-nya.ogg", "ApaMaknaNya", "Labirhin", 151.999f, 0.07f), ["labirhin-breakdown.ogg"] = Track("labirhin-breakdown.ogg", "BREAKDOWN", "Labirhin", 151.999f, 0.882f), ["labirhin-deleted-message.ogg"] = Track("labirhin-deleted-message.ogg", "DeletedMessage", "Labirhin", 151.999f, 0.07f), ["labirhin-here-for-nothing.ogg"] = Track("labirhin-here-for-nothing.ogg", "HereForNothing", "Labirhin", 151.999f, 0.116f), ["labirhin-hurt-overlay.ogg"] = Track("labirhin-hurt-overlay.ogg", "HurtOverlay", "Labirhin", 151.999f, 0.07f), ["labirhin-kesuniya.ogg"] = Track("labirhin-kesuniya.ogg", "KESUNIYA", "Labirhin", 151.999f, 0.07f), ["labirhin-need-someone-like-u.ogg"] = Track("labirhin-need-someone-like-u.ogg", "NeedSomeoneLikeU", "Labirhin", 151.999f, 0.325f), ["labirhin-pulang.ogg"] = Track("labirhin-pulang.ogg", "PULANG", "Labirhin", 151.999f, 0.07f), ["labirhin-tsaf.ogg"] = Track("labirhin-tsaf.ogg", "TSAF", "Labirhin", 151.999f, 0.07f), ["meltdown-072-attack-of-the-killer-queen.ogg"] = Track("meltdown-072-attack-of-the-killer-queen.ogg", "Attack of the Killer Queen", "Toby Fox, Lena Raine & Marcy Nabors", 143.555f, 0.441f), ["meltdown-cool-silly-idea.ogg"] = Track("meltdown-cool-silly-idea.ogg", "just a cool silly little idea that I'm gonna keep", null, 112.347f, 3.901f), ["meltdown-crime-with-master.ogg"] = Track("meltdown-crime-with-master.ogg", "crime with master", null, 112.347f, 1.3f), ["meltdown-is.ogg"] = Track("meltdown-is.ogg", "IS", null, 129.199f, 9.288f), ["meltdown-scp-foundation.ogg"] = Track("meltdown-scp-foundation.ogg", "SCP Foundation", null, 161.499f, 0.07f), ["meltdown-sg-vocal-mix.ogg"] = Track("meltdown-sg-vocal-mix.ogg", "SG - vocal mix", null, 123.047f, 4.899f), ["meltdown-sh4dy-gr3y-1one.ogg"] = Track("meltdown-sh4dy-gr3y-1one.ogg", "SH4DY-GR3Y - 1One", null, 123.047f, 0.697f), ["meltdown-shady-grey-3three.ogg"] = Track("meltdown-shady-grey-3three.ogg", "Shady Grey - 3Three", null, 161.499f, 8.29f), ["meltdown-wwii-moment.ogg"] = Track("meltdown-wwii-moment.ogg", "wwii moment i think", null, 107.666f, 0.232f), ["run-for-it.ogg"] = Track("run-for-it.ogg", "RUN FOR IT", "insOmic", 117.454f, 0.07f), ["workspace-079-big-shot.ogg"] = Track("workspace-079-big-shot.ogg", "BIG SHOT", "Toby Fox", 143.555f, 14.838f), ["workspace-114-its-tv-time.ogg"] = Track("workspace-114-its-tv-time.ogg", "It's TV Time!", "Toby Fox", 99.384f, 0.209f), ["workspace-117-black-knife.ogg"] = Track("workspace-117-black-knife.ogg", "Black Knife", "Toby Fox", 117.454f, 0.232f), ["workspace-155-guardian.ogg"] = Track("workspace-155-guardian.ogg", "GUARDIAN", "Toby Fox", 143.555f, 0.07f), ["workspace-199-flower-man.ogg"] = Track("workspace-199-flower-man.ogg", "Flower Man", "Toby Fox", 107.666f, 0.511f), ["workspace-hotel-chase.ogg"] = Track("workspace-hotel-chase.ogg", "Hotel Chase", null, 129.199f, 3.158f), ["workspace-level-soundtrack-remastered.ogg"] = Track("workspace-level-soundtrack-remastered.ogg", "Level ! But It's Actually a Soundtrack REMASTERED", "Dapper Husky", 151.999f, 0.882f), ["workspace-off-with-ya-head.ogg"] = Track("workspace-off-with-ya-head.ogg", "OFF WITH YA HEAD!", "googifloop", 123.047f, 0.07f), ["workspace-restore-point-interceptor.ogg"] = Track("workspace-restore-point-interceptor.ogg", "Restore Point Interceptor", null, 117.454f, 0.093f) }; internal static int Count => Tracks.Count; internal static bool Contains(string filename) { return Tracks.ContainsKey(filename); } internal static TrackInfo Resolve(string filename) { if (Tracks.TryGetValue(filename, out TrackInfo value)) { return value; } string text = Path.GetFileNameWithoutExtension(filename); string[] array = new string[4] { "workspace-", "meltdown-", "labirhin-", "grace-" }; foreach (string text2 in array) { if (text.StartsWith(text2, StringComparison.OrdinalIgnoreCase)) { text = text.Substring(text2.Length); break; } } text = text.Replace('-', ' ').Replace('_', ' ').Trim(); text = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(text); return Track(filename, text, null, 0f, 0f); } private static TrackInfo Track(string filename, string title, string? author, float bpm, float beatOffsetSeconds) { return new TrackInfo(filename, title, author, bpm, beatOffsetSeconds); } } internal static class VcrFontFactory { private const string ResourceName = "CombinedMeltdownPlaylistSync.Assets.VCR_OSD_MONO_1.001.ttf"; private const int PointSize = 90; private const int AtlasSize = 1024; private const int Padding = 8; private const string IncludedCharacters = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; private static TMP_FontAsset? _fontAsset; private static Texture2D? _atlasTexture; private static Material? _material; private static bool _ownsFontAsset; internal static TMP_FontAsset GetOrCreate() { if ((Object)(object)_fontAsset != (Object)null) { return _fontAsset; } try { _fontAsset = BuildFontAsset(); _ownsFontAsset = true; return _fontAsset; } catch (Exception arg) { Plugin.ModLog.LogError((object)$"Could not create the embedded VCR OSD Mono HUD font: {arg}"); HUDManager instance = HUDManager.Instance; object obj; if (instance == null) { obj = null; } else { TextMeshProUGUI clockNumber = instance.clockNumber; obj = ((clockNumber != null) ? ((TMP_Text)clockNumber).font : null); } if ((Object)obj == (Object)null) { throw; } Plugin.ModLog.LogWarning((object)"Using the vanilla clock font as a HUD fallback."); _fontAsset = (TMP_FontAsset?)obj; _ownsFontAsset = false; return (TMP_FontAsset)obj; } } internal static void Destroy() { if ((Object)(object)_fontAsset != (Object)null && _ownsFontAsset) { Object.Destroy((Object)(object)_fontAsset); } if ((Object)(object)_material != (Object)null) { Object.Destroy((Object)(object)_material); } if ((Object)(object)_atlasTexture != (Object)null) { Object.Destroy((Object)(object)_atlasTexture); } _fontAsset = null; _material = null; _atlasTexture = null; _ownsFontAsset = false; } private static TMP_FontAsset BuildFontAsset() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Expected O, but got Unknown byte[] array = ReadEmbeddedFont(); FontEngineError val = FontEngine.InitializeFontEngine(); if ((int)val != 0) { throw new InvalidOperationException($"FontEngine initialization failed: {val}"); } FontEngineError val2 = FontEngine.LoadFontFace(array, 90, 0); if ((int)val2 != 0) { throw new InvalidOperationException($"VCR OSD Mono could not be loaded from embedded bytes: {val2}"); } try { List list = new List(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".Length); List list2 = new List(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".Length); Dictionary dictionary = new Dictionary(); HashSet hashSet = new HashSet(); string text = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; Glyph val3 = default(Glyph); foreach (uint num in text) { if (FontEngine.TryGetGlyphWithUnicodeValue(num, (GlyphLoadFlags)0, ref val3) && val3.index != 0) { uint index = val3.index; list.Add(num); dictionary[num] = index; if (hashSet.Add(index)) { list2.Add(index); } } } _atlasTexture = new Texture2D(1024, 1024, (TextureFormat)1, false) { name = "VCR OSD Mono Atlas", hideFlags = (HideFlags)61 }; InvokeInternalFontEngineMethod("ResetAtlasTexture", new object[1] { _atlasTexture }); List list3 = new List { new GlyphRect(0, 0, 1023, 1023) }; List list4 = new List(); object[] array2 = new object[8] { list2, 8, (object)(GlyphPackingMode)0, list3, list4, (object)(GlyphRenderMode)4165, _atlasTexture, null }; bool num2 = (bool)InvokeInternalFontEngineMethod("TryAddGlyphsToTexture", array2, 8, typeof(List)); Glyph[] array3 = ((Glyph[])array2[7]) ?? Array.Empty(); if (!num2) { throw new InvalidOperationException("VCR OSD Mono glyphs did not fit in the runtime atlas."); } _atlasTexture.Apply(false, false); List list5 = new List(array3.Length); Dictionary dictionary2 = new Dictionary(array3.Length); Glyph[] array4 = array3; foreach (Glyph val4 in array4) { if (val4 != null) { list5.Add(val4); dictionary2[val4.index] = val4; } } List list6 = new List(list.Count); foreach (uint item in list) { if (dictionary2.TryGetValue(dictionary[item], out var value)) { list6.Add(new TMP_Character(item, value)); } } TMP_FontAsset val5 = ScriptableObject.CreateInstance(); ((Object)val5).name = "VCR OSD Mono"; ((Object)val5).hideFlags = (HideFlags)61; val5.faceInfo = FontEngine.GetFaceInfo(); val5.atlasTextures = (Texture2D[])(object)new Texture2D[1] { _atlasTexture }; val5.atlasPopulationMode = (AtlasPopulationMode)0; val5.isMultiAtlasTexturesEnabled = false; SetPrivateField(val5, "m_Version", "1.1.0"); SetPrivateField(val5, "m_GlyphTable", list5); SetPrivateField(val5, "m_CharacterTable", list6); SetPrivateField(val5, "m_AtlasWidth", 1024); SetPrivateField(val5, "m_AtlasHeight", 1024); SetPrivateField(val5, "m_AtlasPadding", 8); SetPrivateField(val5, "m_AtlasRenderMode", (GlyphRenderMode)4165); SetPrivateField(val5, "m_UsedGlyphRects", list4); SetPrivateField(val5, "m_FreeGlyphRects", list3); HUDManager instance = HUDManager.Instance; object obj; if (instance == null) { obj = null; } else { TextMeshProUGUI clockNumber = instance.clockNumber; if (clockNumber == null) { obj = null; } else { Material fontMaterial = ((TMP_Text)clockNumber).fontMaterial; obj = ((fontMaterial != null) ? fontMaterial.shader : null); } } if (obj == null) { obj = Shader.Find("TextMeshPro/Distance Field"); } if ((Object)obj == (Object)null) { throw new InvalidOperationException("The TextMeshPro distance-field shader was not available."); } _material = new Material((Shader)obj) { name = "VCR OSD Mono Material", hideFlags = (HideFlags)61 }; _material.SetTexture("_MainTex", (Texture)(object)_atlasTexture); _material.SetFloat("_TextureWidth", 1024f); _material.SetFloat("_TextureHeight", 1024f); _material.SetFloat("_GradientScale", 9f); _material.SetFloat("_WeightNormal", 0f); _material.SetFloat("_WeightBold", 0.5f); ((TMP_Asset)val5).material = _material; val5.ReadFontAssetDefinition(); Plugin.ModLog.LogInfo((object)"Loaded embedded VCR OSD Mono HUD font."); return val5; } finally { FontEngine.UnloadFontFace(); } } private static byte[] ReadEmbeddedFont() { using Stream stream = typeof(VcrFontFactory).Assembly.GetManifestResourceStream("CombinedMeltdownPlaylistSync.Assets.VCR_OSD_MONO_1.001.ttf"); if (stream == null) { throw new FileNotFoundException("Embedded font resource 'CombinedMeltdownPlaylistSync.Assets.VCR_OSD_MONO_1.001.ttf' was not found."); } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } private static object InvokeInternalFontEngineMethod(string name, object?[] arguments, int? parameterCount = null, Type? firstParameterType = null) { MethodInfo methodInfo = null; MethodInfo[] methods = typeof(FontEngine).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { ParameterInfo[] parameters = methodInfo2.GetParameters(); if (string.Equals(methodInfo2.Name, name, StringComparison.Ordinal) && (!parameterCount.HasValue || parameters.Length == parameterCount.Value) && (!(firstParameterType != null) || (parameters.Length != 0 && !(parameters[0].ParameterType != firstParameterType)))) { methodInfo = methodInfo2; break; } } if (methodInfo == null) { throw new MissingMethodException(typeof(FontEngine).FullName, name); } object obj = methodInfo.Invoke(null, arguments); if (methodInfo.ReturnType == typeof(void)) { return true; } return obj ?? throw new InvalidOperationException("Internal FontEngine method '" + name + "' returned null."); } private static void SetPrivateField(TMP_FontAsset fontAsset, string fieldName, T value) { FieldInfo fieldInfo = AccessTools.Field(typeof(TMP_FontAsset), fieldName); if (fieldInfo == null) { throw new MissingFieldException(typeof(TMP_FontAsset).FullName, fieldName); } fieldInfo.SetValue(fontAsset, value); } } }