using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PizzaTowerEscapeMusic.Networking; using PizzaTowerEscapeMusic.Scripting; using PizzaTowerEscapeMusic.Scripting.Conditions; using PizzaTowerEscapeMusic.Scripting.ScriptEvents; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("PizzaTowerEscapeMusic")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Plays music from Pizza Tower when the early ship leave alert appears")] [assembly: AssemblyFileVersion("2.5.7.0")] [assembly: AssemblyInformationalVersion("2.5.7")] [assembly: AssemblyProduct("PizzaTowerEscapeMusic")] [assembly: AssemblyTitle("PizzaTowerEscapeMusic")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.5.7.0")] [module: UnverifiableCode] public class ConditionConverter : JsonConverter { public override bool CanWrite => false; public override Condition ReadJson(JsonReader reader, Type objectType, Condition existingValue, bool hasExistingValue, JsonSerializer serializer) { JObject val = JObject.Load(reader); JToken val2 = default(JToken); if (!val.TryGetValue("conditionType", ref val2)) { throw new Exception("Condition type is null!"); } Condition condition = Extensions.Value((IEnumerable)val2) switch { "And" => new Condition_And(), "Or" => new Condition_Or(), "Not" => new Condition_Not(), "Weather" => new Condition_Weather(), "PlayerLocation" => new Condition_PlayerLocation(), "PlayerAlive" => new Condition_PlayerAlive(), "AllPlayersDead" => new Condition_AllPlayersDead(), "PlayerHealth" => new Condition_PlayerHealth(), "PlayerCrouching" => new Condition_PlayerCrouching(), "PlayerInsanity" => new Condition_PlayerInsanity(), "PlayerFearLevel" => new Condition_PlayerFearLevel(), "PlayerAlone" => new Condition_PlayerAlone(), "FiringPlayers" => new Condition_FiringPlayers(), "ShipLanded" => new Condition_ShipLanded(), "ShipInOrbit" => new Condition_ShipInOrbit(), "ShipLeavingAlertCalled" => new Condition_ShipLeavingAlertCalled(), "ShipIsLeaving" => new Condition_ShipIsLeaving(), "MusicWithTagPlaying" => new Condition_MusicWithTagPlaying(), "CurrentMoon" => new Condition_CurrentMoon(), "Timer" => new Condition_Timer(), "Counter" => new Condition_Counter(), "Random" => new Condition_Random(), "ApparatusDocked" => new Condition_ApparatusDocked(), "ApparatusTaked" => new Condition_ApparatusTaked(), "TimeOfDay" => new Condition_TimeOfDay(), "SelectedLabel" => new Condition_SelectedLabel(), _ => throw new Exception($"Condition type \"{val2}\" does not exist"), }; serializer.Populate(((JToken)val).CreateReader(), (object)condition); return condition; } public override void WriteJson(JsonWriter writer, Condition value, JsonSerializer serializer) { throw new NotImplementedException(); } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 A_1) { NullableFlags = new byte[1] { A_1 }; } public NullableAttribute(byte[] A_1) { NullableFlags = A_1; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 A_1) { Flag = A_1; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int A_1) { Version = A_1; } } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace PizzaTowerEscapeMusic { public class Configuration { private readonly ConfigFile config; internal ConfigEntry useRandomMapSeed; internal ConfigEntry dontQueue; internal ConfigEntry scriptingScripts; internal ConfigEntry volumeMaster; internal ConfigEntry selectLabelManually; public Configuration(ConfigFile config) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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 this.config = config; useRandomMapSeed = config.Bind("General", "UseRandomMapSeed", false, new ConfigDescription("Whether to use the game's random map seed for randomization", (AcceptableValueBase)null, Array.Empty())); dontQueue = config.Bind("General", "DontQueue", true, new ConfigDescription("Whether to not queue randomization events even RandomMapSeed not fully ready, UseRandomMapSeed required", (AcceptableValueBase)null, Array.Empty())); scriptingScripts = config.Bind("Scripting", "Scripts", "Default", new ConfigDescription("The names of the JSON script files that will be loaded (Separated by commas, do not put a space after the commas)", (AcceptableValueBase)null, Array.Empty())); volumeMaster = config.Bind("Volume", "Master", 0.5f, new ConfigDescription("The volume of the music as a whole, all volumes are scaled by this value", (AcceptableValueBase)null, Array.Empty())); selectLabelManually = config.Bind("LabelRandom", "SelectLabelManually", "", new ConfigDescription("Manually select label for groups. Format: Group1:Label1,Group2:Label2 (empty to skip)", (AcceptableValueBase)null, Array.Empty())); volumeMaster.SettingChanged += delegate { }; selectLabelManually.SettingChanged += delegate { PizzaTowerEscapeMusicManager.ScriptManager?.ApplySelectedLabels(); }; RemoveObsoleteEntries(); } private void RemoveObsoleteEntry(string section, string key) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition(section, key); config.Bind(val, "", (ConfigDescription)null); config.Remove(val); } private void ReplaceObsoleteEntry(string section, string key, ConfigEntry replacement) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition(section, key); ConfigEntry val2 = config.Bind(val, (T)((ConfigEntryBase)replacement).DefaultValue, (ConfigDescription)null); if (!EqualityComparer.Default.Equals(val2.Value, (T)((ConfigEntryBase)replacement).DefaultValue)) { replacement.Value = val2.Value; } config.Remove(val); } private void RemoveObsoleteEntries() { RemoveObsoleteEntry("Volume", "InsideFacility"); RemoveObsoleteEntry("Volume", "OutsideFacility"); RemoveObsoleteEntry("Volume", "InsideShip"); RemoveObsoleteEntry("Volume", "CrouchingScale"); RemoveObsoleteEntry("Music", "InsideFacility"); RemoveObsoleteEntry("Music", "OutsideFacility"); RemoveObsoleteEntry("Music", "HeavyWeather"); ReplaceObsoleteEntry("Scripting", "Script", scriptingScripts); config.Save(); } } internal static class CustomManager { public static string GetFilePath(string path, string fallbackPath) { string[] directories = Directory.GetDirectories(Paths.PluginPath); for (int i = 0; i < directories.Length; i++) { string text = directories[i] + "/BGN-PizzaTowerEscapeMusic/" + path; if (File.Exists(text)) { return text; } } string text2 = Paths.PluginPath + "/BGN-PizzaTowerEscapeMusic_Custom/" + path; if (File.Exists(text2)) { return text2; } return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/" + fallbackPath; } } public class FacilityMeltdownIntegration : MonoBehaviour { private ManualLogSource logger; private GameEventListener gameEventListener; private Action registeredCallback; public void Initialize(ManualLogSource logger, GameEventListener gameEventListener) { this.logger = logger; this.gameEventListener = gameEventListener; TryHookIntoFacilityMeltdown(); } private void TryHookIntoFacilityMeltdown() { try { if (Type.GetType("FacilityMeltdown.MeltdownPlugin, FacilityMeltdown") == null) { logger.LogInfo((object)"Could not find FacilityMeltdown mod, skipping"); return; } logger.LogInfo((object)"FacilityMeltdown detected, hooking into meltdown events..."); Type type = Type.GetType("FacilityMeltdown.API.MeltdownAPI, FacilityMeltdown"); if (type == null) { logger.LogWarning((object)"Could not find MeltdownAPI type"); return; } MethodInfo method = type.GetMethod("RegisterMeltdownListener", BindingFlags.Static | BindingFlags.Public); if (method == null) { logger.LogWarning((object)"Could not find RegisterMeltdownListener method in MeltdownAPI"); return; } logger.LogInfo((object)"Found RegisterMeltdownListener method in MeltdownAPI"); Action action = OnFacilityMeltdownStarted; method.Invoke(null, new object[1] { action }); registeredCallback = action; logger.LogInfo((object)"Successfully registered as a meltdown listener!"); } catch (Exception ex) { logger.LogError((object)("Failed to hook into FacilityMeltdown: " + ex.Message)); logger.LogDebug((object)("Exception details: " + ex.ToString())); } } private void OnFacilityMeltdownStarted() { logger.LogInfo((object)"FacilityMeltdown meltdown event detected! Triggering music..."); if ((Object)(object)gameEventListener != (Object)null) { gameEventListener.OnMeltdownStarted?.Invoke(); } } private void OnDestroy() { logger.LogDebug((object)"FacilityMeltdown integration being destroyed"); } } public class GameEventListener : MonoBehaviour { private ManualLogSource logger; public Action OnFrameUpdate = delegate { }; public Action OnSoundManagerCreated = delegate { }; public Action OnSoundManagerDestroyed = delegate { }; public Action OnDungeonDoneGenerating = delegate { }; public Action OnLevelLoaded = delegate { }; public Action OnEndOfGame = delegate { }; public Action OnShipLanded = delegate { }; public Action OnShipTakeOff = delegate { }; public Action OnShipInOrbit = delegate { }; public Action OnShipLeavingAlertCalled = delegate { }; public Action OnPlayerDamaged = delegate { }; public Action OnPlayerDeath = delegate { }; public Action OnPlayerEnteredFacility = delegate { }; public Action OnPlayerExitedFacility = delegate { }; public Action OnPlayerEnteredShip = delegate { }; public Action OnPlayerExitedShip = delegate { }; public Action OnApparatusTaken = delegate { }; public Action OnMeltdownStarted = delegate { }; public Action OnShipNotInOrbit = delegate { }; public Action OnFiringPlayers = delegate { }; public Action OnGameOver = delegate { }; public Action OnCurrentMoonChanged = delegate { }; private int localSeed; private bool syncedrandomMapSeed; private readonly Dictionary previousValues = new Dictionary(); private static LungProp dockedApparatus; public static GameEventListener Instance { get; private set; } public static bool SyncedrandomMapSeed { get { if ((Object)(object)Instance != (Object)null) { return Instance.syncedrandomMapSeed; } return false; } } public static bool EndOfGameCalled { get; set; } public static bool ApparatusTaked { get; set; } private void Awake() { logger = Logger.CreateLogSource("PizzaTowerEscapeMusic GameEventListener"); Instance = this; OnShipLanded = (Action)Delegate.Combine(OnShipLanded, new Action(FindDockedApparatus)); } private void OnDestroy() { Instance = null; } private void FindDockedApparatus() { logger.LogDebug((object)"Checking for docked Apparatus..."); LungProp[] array = Object.FindObjectsOfType(); foreach (LungProp val in array) { if (val.isLungDocked) { logger.LogDebug((object)"Found docked Apparatus"); dockedApparatus = val; return; } } logger.LogDebug((object)"Could not find docked Apparatus"); } public static bool IsApparatusDocked() { return (Object)(object)dockedApparatus != (Object)null; } private void StartSyncedrandomMapSeed() { if (!((Object)(object)StartOfRound.Instance != (Object)null) || !SeedSyncService.SeedReceived || syncedrandomMapSeed) { return; } int randomMapSeed = StartOfRound.Instance.randomMapSeed; if (randomMapSeed != localSeed) { localSeed = randomMapSeed; logger.LogDebug((object)$"StartOfRound randomMapSeed updated: {randomMapSeed}"); int capturedSeed = SeedSyncService.CapturedSeed; if (capturedSeed != -1 && randomMapSeed == capturedSeed) { logger.LogDebug((object)$"Seed match: RPC seed {capturedSeed} equals StartOfRound seed {randomMapSeed}"); syncedrandomMapSeed = true; } } } private void ResetSyncedrandomMapSeed() { if (syncedrandomMapSeed) { localSeed = 0; syncedrandomMapSeed = false; logger.LogDebug((object)"SyncedrandomMapSeed flag reset"); } } private void Update() { if ((Object)(object)SoundManager.Instance != (Object)null) { OnFrameUpdate(); } CheckSoundManager(); CheckDungeonDoneGenerating(); CheckLevelLoaded(); CheckEndOfGame(); CheckShipLanded(); CheckShipIsLeaving(); CheckShipReturnToOrbit(); CheckShipInOrbit(); CheckShipNotInOrbit(); CheckFiringPlayers(); CheckGameOver(); CheckShipLeavingAlertCalled(); CheckPlayerDamaged(); CheckPlayerDeath(); CheckPlayerInsideFacility(); CheckPlayerInsideShip(); CheckApparatusTaken(); CheckCurrentMoonChanged(); CheckStartOfRoundNull(); StartSyncedrandomMapSeed(); } private T UpdateCached(string key, T currentValue, T defaultValue) { if (!previousValues.TryGetValue(key, out var value)) { value = defaultValue; } previousValues[key] = currentValue; return (T)value; } private void CheckSoundManager() { bool flag = (Object)(object)SoundManager.Instance != (Object)null; if (UpdateCached("SoundManager", flag, defaultValue: false) != flag) { if (flag) { logger.LogDebug((object)"Sound Manager created"); OnSoundManagerCreated(); } else { logger.LogDebug((object)"Sound Manager destroyed"); OnSoundManagerDestroyed(); } } } private void CheckDungeonDoneGenerating() { bool flag = (Object)(object)RoundManager.Instance != (Object)null && RoundManager.Instance.dungeonCompletedGenerating; bool flag2 = UpdateCached("DungeonDoneGenerating", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Dungeon done generating"); OnDungeonDoneGenerating(); } } private void CheckLevelLoaded() { bool flag = (Object)(object)RoundManager.Instance != (Object)null && RoundManager.Instance.dungeonFinishedGeneratingForAllPlayers; bool flag2 = UpdateCached("LevelLoaded", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Level loaded"); OnLevelLoaded(); } } private void CheckEndOfGame() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && EndOfGameCalled; bool flag2 = UpdateCached("EndOfGame", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"End of game"); OnEndOfGame(); EndOfGameCalled = false; } } private void CheckShipLanded() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipHasLanded; bool flag2 = UpdateCached("ShipLanded", flag, defaultValue: true); if (flag != flag2 && !((Object)(object)StartOfRound.Instance == (Object)null)) { if (flag) { logger.LogDebug((object)"Ship landed"); OnShipLanded(); } else { logger.LogDebug((object)"Ship takeoff"); OnShipTakeOff(); } } } private void CheckShipIsLeaving() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving; bool flag2 = UpdateCached("ShipIsLeaving", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship is leaving"); } } private void CheckShipReturnToOrbit() { bool flag = (Object)(object)StartOfRound.Instance == (Object)null || (!StartOfRound.Instance.shipHasLanded && !StartOfRound.Instance.shipIsLeaving); bool flag2 = UpdateCached("ShipReturnToOrbit", flag, defaultValue: true); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship returning to orbit"); } } private void CheckShipInOrbit() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.inShipPhase; bool flag2 = UpdateCached("ShipInOrbit", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship is in orbit"); OnShipInOrbit(); EndOfGameCalled = false; ApparatusTaked = false; } } private void CheckShipNotInOrbit() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && !StartOfRound.Instance.inShipPhase; bool flag2 = UpdateCached("ShipNotInOrbit", flag, defaultValue: true); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship not in orbit"); OnShipNotInOrbit(); } } private void CheckShipLeavingAlertCalled() { bool flag = (Object)(object)TimeOfDay.Instance != (Object)null && TimeOfDay.Instance.shipLeavingAlertCalled; bool flag2 = UpdateCached("ShipLeavingAlertCalled", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship leaving alert called"); OnShipLeavingAlertCalled(); } } private void CheckPlayerDamaged() { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { int health = GameNetworkManager.Instance.localPlayerController.health; int num = UpdateCached("PlayerDamaged", health, 100); if (health < num) { logger.LogDebug((object)$"Player took damage (Health: {GameNetworkManager.Instance.localPlayerController.health})"); OnPlayerDamaged(); } } } private void CheckPlayerDeath() { bool flag = (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null && GameNetworkManager.Instance.localPlayerController.isPlayerDead; bool flag2 = UpdateCached("PlayerDeath", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Player has died"); OnPlayerDeath(); } } private void CheckPlayerInsideFacility() { bool flag = (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null && GameNetworkManager.Instance.localPlayerController.isInsideFactory; bool flag2 = UpdateCached("PlayerInsideFacility", flag, defaultValue: false); if (flag != flag2) { if (flag) { logger.LogDebug((object)"Player entered the facility"); OnPlayerEnteredFacility(); } else { logger.LogDebug((object)"Player exited the facility"); OnPlayerExitedFacility(); } } } private void CheckPlayerInsideShip() { bool flag = (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null && GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom; bool flag2 = UpdateCached("PlayerInsideShip", flag, defaultValue: false); if (flag != flag2) { if (flag) { logger.LogDebug((object)"Player entered the ship"); OnPlayerEnteredShip(); } else { logger.LogDebug((object)"Player exited the ship"); OnPlayerExitedShip(); } } } private void CheckApparatusTaken() { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { bool flag = (Object)(object)dockedApparatus != (Object)null && !dockedApparatus.isLungDocked; bool flag2 = UpdateCached("ApparatusTaken", flag, defaultValue: false); if (flag != flag2 && flag) { dockedApparatus = null; logger.LogDebug((object)"Apparatus was taken"); ApparatusTaked = true; OnApparatusTaken(); } } } private void CheckCurrentMoonChanged() { if (!((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)TimeOfDay.Instance == (Object)null)) { SelectableLevel currentLevel = TimeOfDay.Instance.currentLevel; SelectableLevel val = UpdateCached("CurrentMoon", currentLevel, null); if (!((Object)(object)currentLevel == (Object)(object)val) && !((Object)(object)currentLevel == (Object)null) && !((Object)(object)val == (Object)null)) { logger.LogDebug((object)("Level has changed to " + (((Object)(object)currentLevel != (Object)null) ? currentLevel.PlanetName : null))); OnCurrentMoonChanged(currentLevel); } } } private void CheckFiringPlayers() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.firingPlayersCutsceneRunning; bool flag2 = UpdateCached("FiringPlayers", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Firing players cutscene running"); OnFiringPlayers(); } } private void CheckGameOver() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.suckingPlayersOutOfShip; bool flag2 = UpdateCached("GameOver", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Game over"); OnGameOver(); } } private void CheckStartOfRoundNull() { bool flag = (Object)(object)StartOfRound.Instance == (Object)null; bool flag2 = UpdateCached("StartOfRoundNull", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"StartOfRound instance became null"); ResetSyncedrandomMapSeed(); SeedSyncService.ResetSeedReceived(); ScriptEvent_LabelRandom.ClearQueueAndFlags(); previousValues.Remove("CurrentMoon"); } } } public class MusicManager : MonoBehaviour { private class MusicInstance { private readonly MusicManager manager; public Script script; public ScriptEvent_PlayMusic musicEvent; public AudioSource introAudioSource; public AudioSource mainAudioSource; public Script.VolumeGroup volumeGroup; private bool isStopping; private AudioClip introClip; private AudioClip mainClip; private bool isIntroPlaying; private bool mainScheduled; private bool introSwitchToMain; private float volume; public float FadeSpeed { get; private set; } public MusicInstance(MusicManager manager, Script script, ScriptEvent_PlayMusic musicEvent, AudioSource audioSource, AudioClip musicClip, AudioClip introClip = null) { this.manager = manager; this.script = script; this.musicEvent = musicEvent; introAudioSource = audioSource; this.introClip = introClip; mainClip = musicClip; isIntroPlaying = (Object)(object)introClip != (Object)null; if (isIntroPlaying) { audioSource.clip = introClip; audioSource.loop = false; mainAudioSource = manager.GetAudioSource(); mainAudioSource.clip = mainClip; mainAudioSource.loop = musicEvent.loop; mainScheduled = false; audioSource.Play(); } else { introAudioSource = null; mainAudioSource = audioSource; mainAudioSource.clip = mainClip; mainAudioSource.loop = musicEvent.loop; mainAudioSource.Play(); } musicInstances.Add(this); if (musicEvent.tag != null) { if (!musicInstancesByTag.TryGetValue(musicEvent.tag, out var value)) { value = new List(1); musicInstancesByTag.Add(musicEvent.tag, value); } value.Add(this); } volumeGroup = script.TryGetVolumeGroupOrDefault(musicEvent.tag); volume = volumeGroup.GetVolume(script); if (!isIntroPlaying) { manager.OnMainMusicStarted?.Invoke(musicEvent.tag); } } public void Update(float deltaTime) { bool flag = introSwitchToMain; introSwitchToMain = false; if (isIntroPlaying) { if ((Object)(object)introAudioSource != (Object)null && (Object)(object)mainAudioSource != (Object)null && !mainScheduled) { int num = introClip.samples - introAudioSource.timeSamples; int num2 = (int)(0.5f * (float)introClip.frequency); if (num <= num2) { double num3 = (double)num / (double)introClip.frequency; double num4 = AudioSettings.dspTime + num3; mainAudioSource.PlayScheduled(num4); mainScheduled = true; } } if ((Object)(object)introAudioSource != (Object)null && !introAudioSource.isPlaying) { isIntroPlaying = false; introSwitchToMain = true; manager.OnMainMusicStarted?.Invoke(musicEvent.tag); } } float num5 = (isStopping ? 0f : volumeGroup.GetVolume(script)); float num6 = (isStopping ? volumeGroup.stoppingVolumeLerpSpeed : volumeGroup.volumeLerpSpeed); float num7 = (isStopping ? volumeGroup.GetStoppingVolumeLerpSpeedScale(script) : volumeGroup.GetVolumeLerpSpeedScale(script)); float num8 = num6 * num7; volume = Mathf.Lerp(volume, num5, num8 * deltaTime); float value = PizzaTowerEscapeMusicManager.Configuration.volumeMaster.Value; if ((Object)(object)introAudioSource != (Object)null) { introAudioSource.volume = volume * value; } if ((Object)(object)mainAudioSource != (Object)null) { mainAudioSource.volume = volume * value; } AudioSource val = (isIntroPlaying ? introAudioSource : (mainAudioSource ?? introAudioSource)); if (((!((Object)(object)val != (Object)null) || !val.isPlaying) && !introSwitchToMain && !flag) || (isStopping && (Object)(object)val != (Object)null && val.volume < 0.005f)) { StopCompletely(); } } public void FadeStop() { if (!isStopping) { isStopping = true; float stoppingVolumeLerpSpeedScale = volumeGroup.GetStoppingVolumeLerpSpeedScale(script); FadeSpeed = volumeGroup.stoppingVolumeLerpSpeed * stoppingVolumeLerpSpeedScale; } } public void StopCompletely() { if ((Object)(object)introAudioSource != (Object)null) { introAudioSource.Stop(); audioSourcePool.Push(introAudioSource); } if ((Object)(object)mainAudioSource != (Object)null) { mainAudioSource.Stop(); audioSourcePool.Push(mainAudioSource); } musicInstances.Remove(this); if (musicEvent.tag != null && musicInstancesByTag.TryGetValue(musicEvent.tag, out var value)) { value.Remove(this); } mainScheduled = false; } } private Dictionary lastGetIsMusicPlayingLogTimeByTag = new Dictionary(); private bool enablelogCooldown = true; private static readonly SemaphoreSlim _loadConcurrencySemaphore = new SemaphoreSlim(16, 16); private ManualLogSource logger; private static readonly List musicInstances = new List(); private static readonly Dictionary> musicInstancesByTag = new Dictionary>(); private static readonly Stack audioSourcePool = new Stack(); private readonly Dictionary loadedMusic = new Dictionary(); public Action OnMainMusicStarted = delegate { }; private void Awake() { logger = Logger.CreateLogSource("PizzaTowerEscapeMusic MusicManager"); } private void Update() { if ((Object)(object)StartOfRound.Instance == (Object)null) { return; } for (int num = musicInstances.Count - 1; num >= 0; num--) { musicInstances[num].Update(Time.deltaTime); } bool flag = false; foreach (MusicInstance musicInstance in musicInstances) { if (musicInstance.musicEvent.silenceGameMusic) { flag = true; break; } } if (flag) { if (SoundManager.Instance.playingOutsideMusic && GetIsMusicPlaying()) { SoundManager.Instance.playingOutsideMusic = false; logger.LogInfo((object)"Silenced the outside music because alternate music is playing"); } if (TimeOfDay.Instance.TimeOfDayMusic.isPlaying && GetIsMusicPlaying()) { TimeOfDay.Instance.TimeOfDayMusic.Stop(); logger.LogInfo((object)"Silenced the time of day music because alternate music is playing"); } } } public bool GetIsMusicPlaying(string tag = null) { if (tag == null) { return musicInstances.Count > 0; } if (musicInstancesByTag.TryGetValue(tag, out var value)) { bool flag = true; if (enablelogCooldown) { if (!lastGetIsMusicPlayingLogTimeByTag.TryGetValue(tag, out var value2)) { value2 = -30f; } if (Time.time - value2 >= 30f) { lastGetIsMusicPlayingLogTimeByTag[tag] = Time.time; } else { flag = false; } } if (flag) { logger.LogDebug((object)$"GetIsMusicPlaying says there's {value.Count} music instance(s) with the tag \"{tag}\""); } return value.Count > 0; } bool flag2 = true; if (enablelogCooldown) { if (!lastGetIsMusicPlayingLogTimeByTag.TryGetValue(tag, out var value3)) { value3 = -30f; } if (Time.time - value3 >= 30f) { lastGetIsMusicPlayingLogTimeByTag[tag] = Time.time; } else { flag2 = false; } } if (flag2) { logger.LogDebug((object)("GetIsMusicPlaying says there was no music instance list for tag \"" + tag + "\"")); } return false; } public void PlayMusic(Script script, ScriptEvent_PlayMusic musicEvent) { logger.LogDebug((object)("PlayMusic called\nTag: " + musicEvent.tag + $"\nOverlap handling: {musicEvent.overlapHandling}" + $"\nAny music playing?: {GetIsMusicPlaying()}" + $"\nAny music playing with tag?: {GetIsMusicPlaying(musicEvent.tag)}")); string text = musicEvent.musicNames[Random.Range(0, musicEvent.musicNames.Length)]; string text2 = null; if (musicEvent.introMusicNames != null && musicEvent.introMusicNames.Length != 0) { text2 = musicEvent.introMusicNames[Random.Range(0, musicEvent.introMusicNames.Length)]; } if (musicEvent.overlapHandling == ScriptEvent_PlayMusic.OverlapHandling.IgnoreAll && GetIsMusicPlaying()) { logger.LogDebug((object)"PlayMusic canceled because other music was playing"); return; } if (musicEvent.overlapHandling == ScriptEvent_PlayMusic.OverlapHandling.IgnoreTag && GetIsMusicPlaying(musicEvent.tag)) { logger.LogDebug((object)("PlayMusic canceled because other music with the tag \"" + musicEvent.tag + "\" was playing")); return; } switch (musicEvent.overlapHandling) { case ScriptEvent_PlayMusic.OverlapHandling.OverrideAll: StopMusic(); break; case ScriptEvent_PlayMusic.OverlapHandling.OverrideTag: StopMusic(musicEvent.tag); break; case ScriptEvent_PlayMusic.OverlapHandling.OverrideFadeAll: FadeStopMusic(); break; case ScriptEvent_PlayMusic.OverlapHandling.OverrideFadeTag: FadeStopMusic(musicEvent.tag); break; } loadedMusic.TryGetValue(text, out var value); AudioClip value2 = null; if (text2 != null) { loadedMusic.TryGetValue(text2, out value2); } if ((Object)(object)value != (Object)null) { new MusicInstance(this, script, musicEvent, GetAudioSource(), value, value2); logger.LogInfo((object)("Playing music (" + text + ")" + ((text2 != null) ? (" with intro (" + text2 + ")") : ""))); } else { logger.LogWarning((object)("Music (" + text + ") is null, cannot play. Maybe it wasn't loaded correctly?")); } } public void StopMusic(string targetTag = null) { foreach (MusicInstance item in new List(musicInstances)) { if (targetTag == null || !(item.musicEvent.tag != targetTag)) { item.StopCompletely(); } } } public void FadeStopMusic(string targetTag = null) { foreach (MusicInstance item in new List(musicInstances)) { if (targetTag == null || !(item.musicEvent.tag != targetTag)) { item.FadeStop(); } } } private AudioSource GetAudioSource() { if (audioSourcePool.Count > 0) { return audioSourcePool.Pop(); } return ((Component)this).gameObject.AddComponent(); } public async void LoadNecessaryMusicClips() { if (PizzaTowerEscapeMusicManager.ScriptManager.loadedScripts.Count == 0) { logger.LogError((object)"No scripts are loaded, addon scripts may not work, please report this issue"); return; } if (string.IsNullOrWhiteSpace(PizzaTowerEscapeMusicManager.Configuration?.scriptingScripts?.Value)) { logger.LogInfo((object)"No scripts configured, skipping music loading"); return; } HashSet musicToLoad = new HashSet(); foreach (Script loadedScript in PizzaTowerEscapeMusicManager.ScriptManager.loadedScripts) { ScriptEvent[] scriptEvents = loadedScript.scriptEvents; for (int i = 0; i < scriptEvents.Length; i++) { if (!(scriptEvents[i] is ScriptEvent_PlayMusic scriptEvent_PlayMusic)) { continue; } string[] musicNames; if (scriptEvent_PlayMusic.musicNames != null) { musicNames = scriptEvent_PlayMusic.musicNames; foreach (string text in musicNames) { if (!loadedMusic.ContainsKey(text)) { musicToLoad.Add(text); } } } if (scriptEvent_PlayMusic.introMusicNames == null) { continue; } musicNames = scriptEvent_PlayMusic.introMusicNames; foreach (string text2 in musicNames) { if (!loadedMusic.ContainsKey(text2)) { musicToLoad.Add(text2); } } } } if (musicToLoad.Count == 0) { logger.LogInfo((object)"All music clips already loaded"); return; } logger.LogInfo((object)$"Loading {musicToLoad.Count} music clips..."); List> list = new List>(); foreach (string item in musicToLoad) { list.Add(LoadMusicClip(item)); } AudioClip[] array = await Task.WhenAll(list); int num = 0; int num2 = 0; foreach (string item2 in musicToLoad) { AudioClip val = array[num2++]; if ((Object)(object)val != (Object)null) { loadedMusic[item2] = val; num++; } } num2 = 0; foreach (string item3 in musicToLoad) { AudioClip val2 = array[num2++]; if ((Object)(object)val2 != (Object)null) { try { val2.LoadAudioData(); } catch (Exception arg) { logger.LogError((object)$"Failed to load audio data for {item3}: {arg}"); } } } logger.LogInfo((object)$"Music clips done loading. Successfully loaded {num} out of {musicToLoad.Count}"); } private Task LoadMusicClip(string musicFileName) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) InterpretMusicFileName(musicFileName, out var audioType, out var finalFileName); string path = "file:///" + CustomManager.GetFilePath("Music/" + finalFileName, "DefaultMusic/" + finalFileName); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(path, audioType); UnityWebRequestAsyncOperation obj = request.SendWebRequest(); TaskCompletionSource tcs = new TaskCompletionSource(); ((AsyncOperation)obj).completed += delegate { Task.Run(async delegate { await _loadConcurrencySemaphore.WaitAsync(); try { if ((int)request.result == 1) { AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content != (Object)null) { ((Object)content).name = musicFileName; logger.LogInfo((object)("Loaded music (" + musicFileName + ") from file")); tcs.SetResult(content); } else { logger.LogError((object)("DownloadHandlerAudioClip.GetContent returned null for " + musicFileName)); tcs.SetResult(null); } } else { logger.LogError((object)($"Failed to load music ({musicFileName}) from file as audio type {audioType}, if the file extension and the audio type do not match the file extension may not be supported" + "\n- Path: " + path + "\n- Error: " + request.error)); tcs.SetResult(null); } } finally { request.Dispose(); _loadConcurrencySemaphore.Release(); } }); }; return tcs.Task; } private void InterpretMusicFileName(string musicFileName, out AudioType audioType, out string finalFileName) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected I4, but got Unknown //IL_0059: 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) if (!Enumerable.Contains(musicFileName, '.')) { audioType = (AudioType)20; finalFileName = musicFileName + ".wav"; return; } string text = musicFileName.Split(new char[1] { '.' }).Last().ToLower(); AudioType val = ((text == "ogg") ? ((AudioType)14) : ((text == "mp3") ? ((AudioType)13) : ((AudioType)20))); audioType = (AudioType)(int)val; finalFileName = musicFileName; } } public class PizzaTowerEscapeMusicManager : MonoBehaviour { private GameEventListener gameEventListener; private ManualLogSource logger; public static Configuration Configuration { get; private set; } public static ScriptManager ScriptManager { get; private set; } public static MusicManager MusicManager { get; private set; } public void Initialise(ManualLogSource logger, ConfigFile config) { this.logger = logger; Configuration = new Configuration(config); MusicManager = ((Component)this).gameObject.AddComponent(); gameEventListener = ((Component)this).gameObject.AddComponent(); GameEventListener obj = gameEventListener; obj.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj.OnSoundManagerDestroyed, (Action)delegate { MusicManager.StopMusic(); }); ScriptManager = new ScriptManager(Configuration.scriptingScripts.Value.Split(new char[1] { ',' }), gameEventListener); GameEventListener obj2 = gameEventListener; obj2.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj2.OnSoundManagerDestroyed, new Action(ScriptManager.ClearAllScriptTimers)); GameEventListener obj3 = gameEventListener; obj3.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj3.OnSoundManagerDestroyed, new Action(ScriptManager.ClearAllScriptCounters)); try { ((Component)this).gameObject.AddComponent().Initialize(logger, gameEventListener); } catch (Exception) { logger.LogInfo((object)"Could not initialize FacilityMeltdown integration, skipping"); } try { LethalConfigIntegration.Initialize(); } catch (Exception) { logger.LogInfo((object)"Could not initialize LethalConfig integration, skipping"); } ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; logger.LogInfo((object)"Plugin pizzatowerescapemusic is loaded!"); } private void Update() { ScriptManager.UpdateAllScriptTimers(Time.deltaTime); } public static void OnChainloaderStartupComplete() { if ((Object)(object)MusicManager != (Object)null) { MusicManager.LoadNecessaryMusicClips(); } } } [BepInPlugin("bgn.pizzatowerescapemusic", "PizzaTowerEscapeMusic", "2.5.7")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { private void Awake() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) SeedSyncPatches.ApplyPatches(); EndOfGamePatches.ApplyPatches(); ChainloaderStartupPatch.ApplyPatches(); GameObject val = new GameObject("PizzaTowerEscapeMusic Manager"); val.AddComponent().Initialise(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); ((Object)val).hideFlags = (HideFlags)61; } } public static class PluginInfo { public const string PLUGIN_GUID = "bgn.pizzatowerescapemusic"; public const string PLUGIN_NAME = "PizzaTowerEscapeMusic"; public const string PLUGIN_VERSION = "2.5.7"; public const string PLUGIN_VERSION_FULL = "2.5.7.0"; } [HarmonyPatch] internal static class EndOfGamePatches { private static ManualLogSource logger = Logger.CreateLogSource("PizzaTowerEscapeMusic EndOfGamePatches"); [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] private static void EndOfGame_Postfix(int bodiesInsured, int connectedPlayersOnServer, int scrapCollected) { logger.LogDebug((object)$"EndOfGame called with bodiesInsured={bodiesInsured}, connectedPlayersOnServer={connectedPlayersOnServer}, scrapCollected={scrapCollected}"); GameEventListener.EndOfGameCalled = true; } internal static void ApplyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.endofgame").PatchAll(Assembly.GetExecutingAssembly()); logger.LogInfo((object)"EndOfGame Harmony patches applied successfully"); } catch (Exception arg) { logger.LogError((object)$"Failed to apply EndOfGame Harmony patches: {arg}"); } } internal static void RemovePatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.endofgame").UnpatchSelf(); logger.LogInfo((object)"EndOfGame Harmony patches removed"); } catch (Exception arg) { logger.LogError((object)$"Failed to remove EndOfGame Harmony patches: {arg}"); } } } [HarmonyPatch] internal static class ChainloaderStartupPatch { private static ManualLogSource logger = Logger.CreateLogSource("PizzaTowerEscapeMusic ChainloaderStartupPatch"); private static bool chainloaderStartupCompleted = false; [HarmonyPrefix] [HarmonyPatch(typeof(Logger), "LogMessage")] private static void LogMessagePrefix(object data) { if (data is string text && text == "Chainloader startup complete" && !chainloaderStartupCompleted) { chainloaderStartupCompleted = true; logger.LogDebug((object)"Chainloader startup complete detected"); PizzaTowerEscapeMusicManager.OnChainloaderStartupComplete(); } } internal static void ApplyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.chainloaderstartup").PatchAll(Assembly.GetExecutingAssembly()); logger.LogInfo((object)"Chainloader startup patch applied successfully"); } catch (Exception arg) { logger.LogError((object)$"Failed to apply Chainloader startup patch: {arg}"); } } } internal static class LethalConfigIntegration { internal static void Initialize() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0065: 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_0075: 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_008c: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown LethalConfigManager.SkipAutoGen(); LethalConfigManager.SetModDescription("PizzaTowerEscapeMusic"); ConfigEntry volumeMaster = PizzaTowerEscapeMusicManager.Configuration.volumeMaster; FloatStepSliderOptions val = new FloatStepSliderOptions { Name = "Master Volume", RequiresRestart = false }; ((BaseRangeOptions)val).Min = 0f; ((BaseRangeOptions)val).Max = 1f; val.Step = 0.01f; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(volumeMaster, (FloatSliderOptions)val)); LethalConfigManager.AddConfigItem((BaseConfigItem)new TextInputFieldConfigItem(PizzaTowerEscapeMusicManager.Configuration.selectLabelManually, new TextInputFieldOptions { Name = "Select Label Manually", RequiresRestart = false, CharacterLimit = 200 })); } } } namespace PizzaTowerEscapeMusic.Networking { public static class SeedSyncService { private static ManualLogSource logger = Logger.CreateLogSource("PizzaTowerEscapeMusic SeedSyncService"); private static bool seedReceived = false; private static int capturedSeed = -1; public static bool SeedReceived => seedReceived; public static int CapturedSeed => capturedSeed; public static event Action OnSeedReceived; public static void SetSeedReceived(int seed = -1) { if (!seedReceived) { seedReceived = true; capturedSeed = seed; logger.LogDebug((object)$"SeedReceived flag set with seed: {seed}"); SeedSyncService.OnSeedReceived?.Invoke(); } } public static void ResetSeedReceived() { if (seedReceived) { capturedSeed = -1; seedReceived = false; logger.LogDebug((object)"SeedReceived flag reset"); } } public static void LogStatus() { logger.LogDebug((object)$"SeedReceived = {SeedReceived}"); } } [HarmonyPatch] internal static class SeedSyncPatches { private static ManualLogSource logger = Logger.CreateLogSource("PizzaTowerEscapeMusic SeedSyncPatches"); [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "OnPlayerConnectedClientRpc", new Type[] { typeof(ulong), typeof(int), typeof(ulong[]), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(bool) })] private static void OnPlayerConnectedClientRpc_Postfix(ulong clientId, int connectedPlayers, ulong[] connectedPlayerIdsOrdered, int assignedPlayerObjectId, int serverMoneyAmount, int levelID, int profitQuota, int timeUntilDeadline, int quotaFulfilled, int randomSeed, bool isChallenge) { logger.LogDebug((object)$"OnPlayerConnectedClientRpc captured randomSeed: {randomSeed}"); SeedSyncService.SetSeedReceived(randomSeed); } internal static void ApplyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.seedsync").PatchAll(Assembly.GetExecutingAssembly()); logger.LogInfo((object)"SeedSync Harmony patches applied successfully"); } catch (Exception arg) { logger.LogError((object)$"Failed to apply SeedSync Harmony patches: {arg}"); } } internal static void RemovePatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.seedsync").UnpatchSelf(); logger.LogInfo((object)"SeedSync Harmony patches removed"); } catch (Exception arg) { logger.LogError((object)$"Failed to remove SeedSync Harmony patches: {arg}"); } } } } namespace PizzaTowerEscapeMusic.Scripting { public class Script { public class VolumeRule { public string comment = string.Empty; [JsonRequired] public float volume; public Condition condition; } public class VolumeModifier { public string comment = string.Empty; [JsonRequired] public float volumeScale; public float volumeLerpSpeedScale = 1f; public float stoppingVolumeLerpSpeedScale = 1f; public Condition condition; } public class VolumeGroup { public string comment = string.Empty; public string tag = string.Empty; public float volumeLerpSpeed = 1f; public float stoppingVolumeLerpSpeed = 1f; public float masterVolume = 1f; public VolumeRule[] volumeRules = Array.Empty(); public VolumeModifier[] volumeModifiers = Array.Empty(); public float GetVolume(Script script) { float num = 1f; VolumeRule[] array = volumeRules; foreach (VolumeRule volumeRule in array) { if (volumeRule.condition == null || volumeRule.condition.Check(script)) { num = volumeRule.volume; break; } } VolumeModifier[] array2 = volumeModifiers; foreach (VolumeModifier volumeModifier in array2) { if (volumeModifier.condition == null || volumeModifier.condition.Check(script)) { num *= volumeModifier.volumeScale; } } return num * masterVolume; } public float GetVolumeLerpSpeedScale(Script script) { float num = 1f; VolumeModifier[] array = volumeModifiers; foreach (VolumeModifier volumeModifier in array) { if (volumeModifier.condition == null || volumeModifier.condition.Check(script)) { num *= volumeModifier.volumeLerpSpeedScale; } } return num; } public float GetStoppingVolumeLerpSpeedScale(Script script) { float num = 1f; VolumeModifier[] array = volumeModifiers; foreach (VolumeModifier volumeModifier in array) { if (volumeModifier.condition == null || volumeModifier.condition.Check(script)) { num *= volumeModifier.stoppingVolumeLerpSpeedScale; } } return num; } } public class Timer { public string name; public float time; public Timer(string name) { this.name = name; } } public class Counter { public string name; public int count; public Counter(string name) { this.name = name; } } public string comment = string.Empty; public bool isAddon; public VolumeGroup[] volumeGroups = Array.Empty(); [JsonRequired] public ScriptEvent[] scriptEvents = Array.Empty(); [JsonIgnore] public readonly Dictionary> loadedScriptEvents = new Dictionary>(); [JsonIgnore] public readonly Dictionary loadedScriptVolumeGroups = new Dictionary(); [JsonIgnore] public readonly Dictionary activeTimers = new Dictionary(); [JsonIgnore] public readonly Dictionary activeCounters = new Dictionary(); [JsonIgnore] public readonly Dictionary selectedLabelsByGroup = new Dictionary(); [JsonIgnore] public static VolumeGroup DefaultVolumeGroup { get; private set; } = new VolumeGroup(); [JsonIgnore] public string selectedLabel { get { if (selectedLabelsByGroup.TryGetValue("", out var value)) { return value; } return string.Empty; } set { selectedLabelsByGroup[""] = value; } } public void Initialise(ManualLogSource logger) { ScriptEvent[] array = scriptEvents; foreach (ScriptEvent scriptEvent in array) { if (!loadedScriptEvents.TryGetValue(scriptEvent.gameEventType, out var value)) { value = new List(1); loadedScriptEvents.Add(scriptEvent.gameEventType, value); } value.Add(scriptEvent); } VolumeGroup[] array2 = volumeGroups; foreach (VolumeGroup volumeGroup in array2) { if (!loadedScriptVolumeGroups.ContainsKey(volumeGroup.tag)) { loadedScriptVolumeGroups.Add(volumeGroup.tag, volumeGroup); } else { logger.LogError((object)("Volume group tag \"" + volumeGroup.tag + "\" was already declared, you cannot have two volume groups with the same tag")); } } } public VolumeGroup TryGetVolumeGroupOrDefault(string tag) { if (tag == null || !loadedScriptVolumeGroups.ContainsKey(tag)) { return DefaultVolumeGroup; } return loadedScriptVolumeGroups[tag]; } public bool TryGetVolumeGroup(string tag, out VolumeGroup volumeGroup) { if (tag == null || !loadedScriptVolumeGroups.ContainsKey(tag)) { volumeGroup = null; return false; } volumeGroup = loadedScriptVolumeGroups[tag]; return true; } public void UpdateTimers(float deltaTime) { foreach (Timer value in activeTimers.Values) { value.time += deltaTime; } } public void ClearTimers() { activeTimers.Clear(); } internal void ClearTimer(string timerName) { activeTimers.Remove(timerName); } public void ClearCounters() { activeCounters.Clear(); } internal void ClearCounter(string counterName) { activeCounters.Remove(counterName); } } public class ScriptManager { private GameEventListener gameEventListener; private bool pendingManualLabelSelection; private bool selectLabelManuallyValid = true; private Dictionary lastLogTimeByEvent = new Dictionary(); private bool enablelogCooldown = true; public readonly List