Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PizzaTowerEscapeMusic ForkForMe v2.5.7
BepInEx/plugins/PizzaTowerEscapeMusic.dll
Decompiled 2 months agousing 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<Condition> { 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<string>((IEnumerable<JToken>)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<bool> useRandomMapSeed; internal ConfigEntry<bool> dontQueue; internal ConfigEntry<string> scriptingScripts; internal ConfigEntry<float> volumeMaster; internal ConfigEntry<string> 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<bool>("General", "UseRandomMapSeed", false, new ConfigDescription("Whether to use the game's random map seed for randomization", (AcceptableValueBase)null, Array.Empty<object>())); dontQueue = config.Bind<bool>("General", "DontQueue", true, new ConfigDescription("Whether to not queue randomization events even RandomMapSeed not fully ready, UseRandomMapSeed required", (AcceptableValueBase)null, Array.Empty<object>())); scriptingScripts = config.Bind<string>("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<object>())); volumeMaster = config.Bind<float>("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<object>())); selectLabelManually = config.Bind<string>("LabelRandom", "SelectLabelManually", "", new ConfigDescription("Manually select label for groups. Format: Group1:Label1,Group2:Label2 (empty to skip)", (AcceptableValueBase)null, Array.Empty<object>())); 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<string>(val, "", (ConfigDescription)null); config.Remove(val); } private void ReplaceObsoleteEntry<T>(string section, string key, ConfigEntry<T> 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<T> val2 = config.Bind<T>(val, (T)((ConfigEntryBase)replacement).DefaultValue, (ConfigDescription)null); if (!EqualityComparer<T>.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<string>("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<SelectableLevel> OnCurrentMoonChanged = delegate { }; private int localSeed; private bool syncedrandomMapSeed; private readonly Dictionary<string, object> previousValues = new Dictionary<string, object>(); 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<LungProp>(); 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<T>(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<SelectableLevel>("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<MusicInstance>(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<string, float> lastGetIsMusicPlayingLogTimeByTag = new Dictionary<string, float>(); private bool enablelogCooldown = true; private static readonly SemaphoreSlim _loadConcurrencySemaphore = new SemaphoreSlim(16, 16); private ManualLogSource logger; private static readonly List<MusicInstance> musicInstances = new List<MusicInstance>(); private static readonly Dictionary<string, List<MusicInstance>> musicInstancesByTag = new Dictionary<string, List<MusicInstance>>(); private static readonly Stack<AudioSource> audioSourcePool = new Stack<AudioSource>(); private readonly Dictionary<string, AudioClip> loadedMusic = new Dictionary<string, AudioClip>(); public Action<string> 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<MusicInstance>(musicInstances)) { if (targetTag == null || !(item.musicEvent.tag != targetTag)) { item.StopCompletely(); } } } public void FadeStopMusic(string targetTag = null) { foreach (MusicInstance item in new List<MusicInstance>(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<AudioSource>(); } 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<string> musicToLoad = new HashSet<string>(); 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<Task<AudioClip>> list = new List<Task<AudioClip>>(); 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<AudioClip> 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<AudioClip> tcs = new TaskCompletionSource<AudioClip>(); ((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<MusicManager>(); gameEventListener = ((Component)this).gameObject.AddComponent<GameEventListener>(); 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<FacilityMeltdownIntegration>().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<PizzaTowerEscapeMusicManager>().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<float> volumeMaster = PizzaTowerEscapeMusicManager.Configuration.volumeMaster; FloatStepSliderOptions val = new FloatStepSliderOptions { Name = "Master Volume", RequiresRestart = false }; ((BaseRangeOptions<float>)val).Min = 0f; ((BaseRangeOptions<float>)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<VolumeRule>(); public VolumeModifier[] volumeModifiers = Array.Empty<VolumeModifier>(); 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<VolumeGroup>(); [JsonRequired] public ScriptEvent[] scriptEvents = Array.Empty<ScriptEvent>(); [JsonIgnore] public readonly Dictionary<ScriptEvent.GameEventType, List<ScriptEvent>> loadedScriptEvents = new Dictionary<ScriptEvent.GameEventType, List<ScriptEvent>>(); [JsonIgnore] public readonly Dictionary<string, VolumeGroup> loadedScriptVolumeGroups = new Dictionary<string, VolumeGroup>(); [JsonIgnore] public readonly Dictionary<string, Timer> activeTimers = new Dictionary<string, Timer>(); [JsonIgnore] public readonly Dictionary<string, Counter> activeCounters = new Dictionary<string, Counter>(); [JsonIgnore] public readonly Dictionary<string, string> selectedLabelsByGroup = new Dictionary<string, string>(); [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<ScriptEvent>(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<ScriptEvent.GameEventType, float> lastLogTimeByEvent = new Dictionary<ScriptEvent.GameEventType, float>(); private bool enablelogCooldown = true; public readonly List<Script> loadedScripts = new List<Script>(); public bool SelectLabelManuallyValid => selectLabelManuallyValid; public ManualLogSource Logger { get; private set; } public ScriptManager(string[] scriptNames, GameEventListener gameEventListener) { Logger = Logger.CreateLogSource("PizzaTowerEscapeMusic ScriptManager"); this.gameEventListener = gameEventListener; Script script = new Script(); loadedScripts.Add(script); foreach (string text in scriptNames) { if (string.IsNullOrWhiteSpace(text)) { Logger.LogDebug((object)"Skipping empty script name"); continue; } Script script2 = DeserializeScript(text); if (script2 != null) { script2.Initialise(Logger); if (script2.isAddon) { List<Script.VolumeGroup> list = script.volumeGroups.ToList(); list.AddRange(script2.volumeGroups); script.volumeGroups = list.ToArray(); List<ScriptEvent> list2 = script.scriptEvents.ToList(); list2.AddRange(script2.scriptEvents); script.scriptEvents = list2.ToArray(); } else { loadedScripts.Add(script2); } if (script2.isAddon) { Logger.LogInfo((object)("Script (" + text + ") loaded as addon")); } else { Logger.LogInfo((object)("Script (" + text + ") loaded")); } } } script.Initialise(Logger); gameEventListener.OnFrameUpdate = (Action)Delegate.Combine(gameEventListener.OnFrameUpdate, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.FrameUpdated); }); gameEventListener.OnShipLanded = (Action)Delegate.Combine(gameEventListener.OnShipLanded, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipLanded); }); gameEventListener.OnShipTakeOff = (Action)Delegate.Combine(gameEventListener.OnShipTakeOff, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipTakeOff); }); gameEventListener.OnShipInOrbit = (Action)Delegate.Combine(gameEventListener.OnShipInOrbit, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipInOrbit); }); gameEventListener.OnShipInOrbit = (Action)Delegate.Combine(gameEventListener.OnShipInOrbit, (Action)delegate { if (pendingManualLabelSelection) { pendingManualLabelSelection = false; ApplySelectedLabels(); } }); gameEventListener.OnShipLeavingAlertCalled = (Action)Delegate.Combine(gameEventListener.OnShipLeavingAlertCalled, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipLeavingAlertCalled); }); gameEventListener.OnPlayerDamaged = (Action)Delegate.Combine(gameEventListener.OnPlayerDamaged, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerDamaged); }); gameEventListener.OnPlayerDeath = (Action)Delegate.Combine(gameEventListener.OnPlayerDeath, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerDied); }); gameEventListener.OnPlayerEnteredFacility = (Action)Delegate.Combine(gameEventListener.OnPlayerEnteredFacility, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerEnteredFacility); }); gameEventListener.OnPlayerExitedFacility = (Action)Delegate.Combine(gameEventListener.OnPlayerExitedFacility, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerExitedFacility); }); gameEventListener.OnPlayerEnteredShip = (Action)Delegate.Combine(gameEventListener.OnPlayerEnteredShip, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerEnteredShip); }); gameEventListener.OnPlayerExitedShip = (Action)Delegate.Combine(gameEventListener.OnPlayerExitedShip, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerExitedShip); }); gameEventListener.OnApparatusTaken = (Action)Delegate.Combine(gameEventListener.OnApparatusTaken, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ApparatusTaken); }); gameEventListener.OnMeltdownStarted = (Action)Delegate.Combine(gameEventListener.OnMeltdownStarted, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.MeltdownStarted); }); gameEventListener.OnLevelLoaded = (Action)Delegate.Combine(gameEventListener.OnLevelLoaded, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.LevelLoaded); }); gameEventListener.OnEndOfGame = (Action)Delegate.Combine(gameEventListener.OnEndOfGame, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.EndOfGame); }); gameEventListener.OnFiringPlayers = (Action)Delegate.Combine(gameEventListener.OnFiringPlayers, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.FiringPlayers); }); gameEventListener.OnGameOver = (Action)Delegate.Combine(gameEventListener.OnGameOver, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.GameOver); }); gameEventListener.OnShipNotInOrbit = (Action)Delegate.Combine(gameEventListener.OnShipNotInOrbit, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipNotInOrbit); }); gameEventListener.OnCurrentMoonChanged = (Action<SelectableLevel>)Delegate.Combine(gameEventListener.OnCurrentMoonChanged, (Action<SelectableLevel>)delegate { CheckScriptEvents(ScriptEvent.GameEventType.CurrentMoonChanged); }); Logger.LogInfo((object)"Done loading scripts"); ApplySelectedLabels(); } private void CheckScriptEvents(ScriptEvent.GameEventType eventType) { foreach (Script loadedScript in loadedScripts) { if (!loadedScript.loadedScriptEvents.TryGetValue(eventType, out var value)) { continue; } foreach (ScriptEvent item in value) { if (!item.CheckConditions(loadedScript)) { continue; } bool flag = true; if (enablelogCooldown) { if (!lastLogTimeByEvent.TryGetValue(eventType, out var value2)) { value2 = -15f; } if (Time.time - value2 >= 15f) { lastLogTimeByEvent[eventType] = Time.time; } else { flag = false; } } if (flag) { Logger.LogDebug((object)("Conditions for a script event have been met!\n Script Event Type: " + item.scriptEventType + $"\n Game Event Type: {item.gameEventType}" + "\n Comment: " + item.comment)); } item.Run(loadedScript); } } } private Script DeserializeScript(string name) { string filePath = CustomManager.GetFilePath("Scripts/" + name + ".json", "DefaultScripts/" + name + ".json"); if (!File.Exists(filePath)) { Logger.LogError((object)("Script \"" + name + "\" does not exist! Make sure you spelt it right the config, and make sure its file extension is \".json\"")); return null; } string text = File.ReadAllText(filePath); try { return JsonConvert.DeserializeObject<Script>(text); } catch (Exception ex) { Logger.LogError((object)("Failed to deserialize script \"" + name + "\":\n" + ex.Message)); return null; } } public void UpdateAllScriptTimers(float deltaTime) { foreach (Script loadedScript in loadedScripts) { loadedScript.UpdateTimers(deltaTime); } } public void ClearAllScriptTimers() { foreach (Script loadedScript in loadedScripts) { loadedScript.ClearTimers(); } } public void ClearAllScriptCounters() { foreach (Script loadedScript in loadedScripts) { loadedScript.ClearCounters(); } } public void ApplySelectedLabels() { if ((Object)(object)StartOfRound.Instance != (Object)null && !StartOfRound.Instance.inShipPhase) { pendingManualLabelSelection = true; Logger.LogInfo((object)"Cannot apply manual label selection when not in ship phase, Changes pending"); return; } pendingManualLabelSelection = false; string text = PizzaTowerEscapeMusicManager.Configuration?.selectLabelManually?.Value; if (string.IsNullOrWhiteSpace(text)) { selectLabelManuallyValid = true; return; } string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); Dictionary<string, string> dictionary = new Dictionary<string, string>(); bool flag = true; string[] array2 = array; foreach (string text2 in array2) { string[] array3 = text2.Split(new char[1] { ':' }, 2); if (array3.Length != 2) { Logger.LogWarning((object)("Invalid selectLabelManually entry: '" + text2 + "', expected Group:Label")); flag = false; continue; } string text3 = array3[0].Trim(); string text4 = array3[1].Trim(); if (string.IsNullOrEmpty(text3) || string.IsNullOrEmpty(text4)) { Logger.LogWarning((object)("Empty group or label in entry: '" + text2 + "'")); flag = false; continue; } if (dictionary.ContainsKey(text3)) { Logger.LogWarning((object)("Duplicate group '" + text3 + "' in selectLabelManually configuration, will use label '" + text4 + "' (previous label '" + dictionary[text3] + "')")); } dictionary[text3] = text4; } selectLabelManuallyValid = flag; foreach (KeyValuePair<string, string> item in dictionary) { string key = item.Key; string value = item.Value; foreach (Script loadedScript in loadedScripts) { loadedScript.selectedLabelsByGroup[key] = value; } Logger.LogDebug((object)("Applied manual label selection: group='" + key + "', label='" + value + "'")); } } } } namespace PizzaTowerEscapeMusic.Scripting.ScriptEvents { [JsonConverter(typeof(ScriptEventConverter))] public abstract class ScriptEvent { public enum GameEventType { FrameUpdated, ShipLanded, ShipTakeOff, ShipLeavingAlertCalled, PlayerDamaged, PlayerDied, PlayerEnteredFacility, PlayerExitedFacility, PlayerEnteredShip, PlayerExitedShip, ApparatusTaken, CurrentMoonChanged, MeltdownStarted, ShipInOrbit, ShipNotInOrbit, LevelLoaded, EndOfGame, FiringPlayers, GameOver } public string comment = string.Empty; [JsonRequired] public string scriptEventType = string.Empty; [JsonRequired] public GameEventType gameEventType; public Condition[] conditions = Array.Empty<Condition>(); public bool CheckConditions(Script script) { return !conditions.Any((Condition c) => !c.Check(script)); } public abstract void Run(Script script); } public class ScriptEventConverter : JsonConverter<ScriptEvent> { public override bool CanWrite => false; public override ScriptEvent ReadJson(JsonReader reader, Type objectType, ScriptEvent existingValue, bool hasExistingValue, JsonSerializer serializer) { JObject val = JObject.Load(reader); JToken val2 = default(JToken); if (!val.TryGetValue("scriptEventType", ref val2)) { throw new Exception("scriptEventType type is null!"); } ScriptEvent scriptEvent = Extensions.Value<string>((IEnumerable<JToken>)val2) switch { "SetVolumeGroupMasterVolume" => new ScriptEvent_SetVolumeGroupMasterVolume(), "LabelRandom" => new ScriptEvent_LabelRandom(), "ResetCounters" => new ScriptEvent_ResetCounters(), "ResetTimers" => new ScriptEvent_ResetTimers(), "StopMusic" => new ScriptEvent_StopMusic(), "PlayMusic" => new ScriptEvent_PlayMusic(), _ => throw new Exception($"Condition type \"{val2}\" does not exist"), }; serializer.Populate(((JToken)val).CreateReader(), (object)scriptEvent); return scriptEvent; } public override void WriteJson(JsonWriter writer, ScriptEvent value, JsonSerializer serializer) { throw new NotImplementedException(); } } public class ScriptEvent_PlayMusic : ScriptEvent { public enum OverlapHandling { IgnoreAll, IgnoreTag, OverrideAll, OverrideTag, OverrideFadeAll, OverrideFadeTag, Overlap } public bool loop; public bool silenceGameMusic = true; [JsonRequired] public OverlapHandling overlapHandling; public string tag; [JsonRequired] public string[] musicNames = Array.Empty<string>(); public string[] introMusicNames = Array.Empty<string>(); public override void Run(Script script) { if (musicNames.Length != 0) { PizzaTowerEscapeMusicManager.MusicManager.PlayMusic(script, this); } } } public class ScriptEvent_ResetTimers : ScriptEvent { public string[] targetTimerNames; public override void Run(Script script) { if (targetTimerNames != null) { string[] array = targetTimerNames; foreach (string timerName in array) { script.ClearTimer(timerName); } } } } public class ScriptEvent_ResetCounters : ScriptEvent { public string[] targetCounterNames; public override void Run(Script script) { if (targetCounterNames != null) { string[] array = targetCounterNames; foreach (string counterName in array) { script.ClearCounter(counterName); } } } } public class ScriptEvent_SetVolumeGroupMasterVolume : ScriptEvent { public string[] targetTags = Array.Empty<string>(); [JsonRequired] public float masterVolume; public override void Run(Script script) { if (targetTags.Length == 0) { Script.DefaultVolumeGroup.masterVolume = masterVolume; return; } string[] array = targetTags; foreach (string text in array) { if (!script.loadedScriptVolumeGroups.TryGetValue(text, out var value)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("Script Event SetVolumeGroupMasterVolume was called for volume group with tag \"" + text + "\", but there is no volume group of that tag")); } else { value.masterVolume = masterVolume; } } } } public class ScriptEvent_StopMusic : ScriptEvent { public string[] targetTags; public bool instant; public override void Run(Script script) { if (targetTags != null) { string[] array = targetTags; foreach (string targetTag in array) { if (instant) { PizzaTowerEscapeMusicManager.MusicManager.StopMusic(targetTag); } else { PizzaTowerEscapeMusicManager.MusicManager.FadeStopMusic(targetTag); } } } else if (instant) { PizzaTowerEscapeMusicManager.MusicManager.StopMusic(); } else { PizzaTowerEscapeMusicManager.MusicManager.FadeStopMusic(); } } } public class ScriptEvent_LabelRandom : ScriptEvent { private struct QueuedLabelRandom { public Script script; public string group; public string[] labels; public List<(string label, float weight)> entries; public float totalWeight; } [CompilerGenerated] private sealed class <DelayedSelection>d__11 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Script script; public string group; public string[] labels; public List<(string label, float weight)> entries; public float totalWeight; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedSelection>d__11(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; case 1: <>1__state = -1; SelectLabelWithSeed(script, group, labels, entries, totalWeight); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ProcessQueueWithDelay>d__9 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ProcessQueueWithDelay>d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; queueProcessing = true; <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; case 1: <>1__state = -1; while (pendingEvents.Count > 0) { QueuedLabelRandom queuedLabelRandom = pendingEvents.Dequeue(); ExecuteWithDelay(queuedLabelRandom.script, queuedLabelRandom.group, queuedLabelRandom.labels, queuedLabelRandom.entries, queuedLabelRandom.totalWeight); } queueProcessing = false; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: queue processed"); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForSyncedThenProcess>d__7 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForSyncedThenProcess>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (!GameEventListener.SyncedrandomMapSeed) { <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; } PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: SyncedrandomMapSeed"); ProcessQueue(); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static Queue<QueuedLabelRandom> pendingEvents = new Queue<QueuedLabelRandom>(); private static bool queueProcessing = false; private static bool subscribedToSeedReceived = false; [JsonRequired] public string group = string.Empty; [JsonRequired] public string[] labels = Array.Empty<string>(); public override void Run(Script script) { if (string.IsNullOrEmpty(group)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: group must be specified and non-empty"); } else { if (labels.Length == 0) { return; } List<(string, float)> list = new List<(string, float)>(); float num = 0f; string[] array = labels; foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length != 2) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: malformed entry '" + text + "', expected 'label:weight'")); continue; } string text2 = array2[0].Trim(); if (string.IsNullOrEmpty(text2)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: label is empty '" + text + "'")); continue; } if (!float.TryParse(array2[1], out var result)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: weight is not a number '" + text + "'")); continue; } if (result <= 0f) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: weight must be positive '" + text + "'")); continue; } list.Add((text2, result)); num += result; } if (list.Count == 0) { return; } if (PizzaTowerEscapeMusicManager.Configuration != null && PizzaTowerEscapeMusicManager.Configuration.useRandomMapSeed != null && PizzaTowerEscapeMusicManager.Configuration.useRandomMapSeed.Value) { if ((Object)(object)StartOfRound.Instance == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: StartOfRound instance is null, skipping"); } else if ((((NetworkBehaviour)StartOfRound.Instance).IsHost && ((NetworkBehaviour)StartOfRound.Instance).IsServer) || (SeedSyncService.SeedReceived && GameEventListener.SyncedrandomMapSeed) || (PizzaTowerEscapeMusicManager.Configuration.dontQueue != null && PizzaTowerEscapeMusicManager.Configuration.dontQueue.Value)) { ExecuteWithDelay(script, group, labels, list, num); } else { EnqueueEvent(script, group, labels, list, num); } } else { float randomValue = Random.Range(0f, num); SelectLabel(script, group, list, num, randomValue); } } } private static void EnqueueEvent(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { QueuedLabelRandom queuedLabelRandom = default(QueuedLabelRandom); queuedLabelRandom.script = script; queuedLabelRandom.group = group; queuedLabelRandom.labels = labels; queuedLabelRandom.entries = entries; queuedLabelRandom.totalWeight = totalWeight; QueuedLabelRandom item = queuedLabelRandom; pendingEvents.Enqueue(item); PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)$"LabelRandom: event queued (waiting for seed). Queue size: {pendingEvents.Count}"); if (!subscribedToSeedReceived) { SeedSyncService.OnSeedReceived += OnSeedReceived; subscribedToSeedReceived = true; } } private static void OnSeedReceived() { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: OnSeedReceived"); if (GameEventListener.SyncedrandomMapSeed) { ProcessQueue(); return; } GameEventListener gameEventListener = GameEventListener.Instance ?? Object.FindObjectOfType<GameEventListener>(); if ((Object)(object)gameEventListener == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: cannot find GameEventListener instance, cannot wait for sync"); } else { ((MonoBehaviour)gameEventListener).StartCoroutine(WaitForSyncedThenProcess()); } } [IteratorStateMachine(typeof(<WaitForSyncedThenProcess>d__7))] private static IEnumerator WaitForSyncedThenProcess() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForSyncedThenProcess>d__7(0); } private static void ProcessQueue() { if (!queueProcessing) { GameEventListener gameEventListener = GameEventListener.Instance ?? Object.FindObjectOfType<GameEventListener>(); if ((Object)(object)gameEventListener == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: cannot find GameEventListener instance, cannot start delay coroutine"); } else { ((MonoBehaviour)gameEventListener).StartCoroutine(ProcessQueueWithDelay()); } } } [IteratorStateMachine(typeof(<ProcessQueueWithDelay>d__9))] private static IEnumerator ProcessQueueWithDelay() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ProcessQueueWithDelay>d__9(0); } private static void ExecuteWithDelay(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { GameEventListener gameEventListener = GameEventListener.Instance ?? Object.FindObjectOfType<GameEventListener>(); if ((Object)(object)gameEventListener == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: cannot find GameEventListener to start coroutine, falling back to immediate selection"); SelectLabelWithSeed(script, group, labels, entries, totalWeight); } else { ((MonoBehaviour)gameEventListener).StartCoroutine(DelayedSelection(script, group, labels, entries, totalWeight)); } } [IteratorStateMachine(typeof(<DelayedSelection>d__11))] private static IEnumerator DelayedSelection(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedSelection>d__11(0) { script = script, group = group, labels = labels, entries = entries, totalWeight = totalWeight }; } private static void SelectLabelWithSeed(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { int randomMapSeed = StartOfRound.Instance.randomMapSeed; int num = group.GetHashCode(); foreach (string text in labels) { num ^= text.GetHashCode(); } float randomValue = (float)(new Random(randomMapSeed ^ num).NextDouble() * (double)totalWeight); SelectLabel(script, group, entries, totalWeight, randomValue); } private static void SelectLabel(Script script, string group, List<(string label, float weight)> entries, float totalWeight, float randomValue) { string text = PizzaTowerEscapeMusicManager.Configuration?.selectLabelManually?.Value; if (!string.IsNullOrWhiteSpace(text)) { ScriptManager scriptManager = PizzaTowerEscapeMusicManager.ScriptManager; if (scriptManager != null && scriptManager.SelectLabelManuallyValid) { string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }, 2); if (array2.Length == 2) { string text2 = array2[0].Trim(); string text3 = array2[1].Trim(); if (text2.Equals(group)) { string text4 = (string.IsNullOrEmpty(group) ? "" : group); script.selectedLabelsByGroup[text4] = text3; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)("LabelRandom: using manually selected label '" + text3 + "' for group '" + text4 + "'")); return; } } } } } float num = 0f; string text5 = null; foreach (var entry in entries) { string item = entry.label; float item2 = entry.weight; num += item2; if (randomValue <= num) { text5 = item; break; } } if (text5 != null) { string text6 = (string.IsNullOrEmpty(group) ? "" : group); script.selectedLabelsByGroup[text6] = text5; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)("LabelRandom: selected label '" + text5 + "' for group '" + text6 + "'")); } } public static void ClearQueueAndFlags() { pendingEvents.Clear(); queueProcessing = false; subscribedToSeedReceived = false; SeedSyncService.OnSeedReceived -= OnSeedReceived; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: queue and flags cleared"); } } } namespace PizzaTowerEscapeMusic.Scripting.Conditions { [JsonConverter(typeof(ConditionConverter))] public abstract class Condition { [JsonRequired] public string conditionType = string.Empty; public abstract bool Check(Script script); } public abstract class ConditionComparableNumber : Condition { public enum ComparisonType { Equals, NotEquals, GreaterThan, LessThan, GreaterThanOrEquals, LessThanOrEquals } [JsonRequired] public ComparisonType comparisonType; } public class Condition_And : Condition { [JsonRequired] public Condition[] conditions = Array.Empty<Condition>(); public override bool Check(Script script) { return !conditions.Any((Condition c) => !c.Check(script)); } } public class Condition_ApparatusDocked : Condition { public override bool Check(Script script) { return GameEventListener.IsApparatusDocked(); } } public class Condition_ApparatusTaked : Condition { public override bool Check(Script script) { return GameEventListener.ApparatusTaked; } } public class Condition_CurrentMoon : Condition { private static readonly Dictionary<string, int> moonNameToId = new Dictionary<string, int>(); [JsonRequired] public string moonName = string.Empty; private bool isDisabled; public override bool Check(Script script) { if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } if (isDisabled) { return false; } if (!moonNameToId.TryGetValue(moonName, out var value)) { SelectableLevel[] levels = StartOfRound.Instance.levels; foreach (SelectableLevel val in levels) { if (!moonNameToId.ContainsKey(val.PlanetName)) { moonNameToId.Add(val.PlanetName, val.levelID); } } if (!moonNameToId.TryGetValue(moonName, out value)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("From CurrentMoon condition: Found no existing level with the name \"" + moonName + "\"")); isDisabled = true; return false; } } return TimeOfDay.Instance.currentLevel.levelID == value; } } public class Condition_MusicWithTagPlaying : Condition { [JsonRequired] public string tag = string.Empty; public override bool Check(Script script) { return PizzaTowerEscapeMusicManager.MusicManager.GetIsMusicPlaying(tag); } } public class Condition_Not : Condition { [JsonRequired] public Condition condition; public override bool Check(Script script) { if (condition != null) { return !condition.Check(script); } return true; } } public class Condition_Or : Condition { [JsonRequired] public Condition[] conditions = Array.Empty<Condition>(); public override bool Check(Script script) { return conditions.Any((Condition c) => c.Check(script)); } } public class Condition_PlayerAlive : Condition { public override bool Check(Script script) { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { return !GameNetworkManager.Instance.localPlayerController.isPlayerDead; } return false; } } public class Condition_AllPlayersDead : Condition { public override bool Check(Script script) { if ((Object)(object)StartOfRound.Instance != (Object)null) { return StartOfRound.Instance.allPlayersDead; } return false; } } public class Condition_PlayerCrouching : Condition { public override bool Check(Script script) { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { return GameNetworkManager.Instance.localPlayerController.isCrouching; } return false; } } public class Condition_PlayerHealth : ConditionComparableNumber { [JsonRequired] public int value; public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } int health = GameNetworkManager.Instance.localPlayerController.health; return comparisonType switch { ComparisonType.Equals => health == value, ComparisonType.NotEquals => health != value, ComparisonType.GreaterThan => health > value, ComparisonType.LessThan => health < value, ComparisonType.GreaterThanOrEquals => health >= value, ComparisonType.LessThanOrEquals => health <= value, _ => false, }; } } public class Condition_PlayerInsanity : ConditionComparableNumber { [JsonRequired] public float level; public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } float num = GameNetworkManager.Instance.localPlayerController.insanityLevel / GameNetworkManager.Instance.localPlayerController.maxInsanityLevel; return comparisonType switch { ComparisonType.Equals => level == num, ComparisonType.NotEquals => level != num, ComparisonType.GreaterThan => level > num, ComparisonType.LessThan => level < num, ComparisonType.GreaterThanOrEquals => level >= num, ComparisonType.LessThanOrEquals => level <= num, _ => false, }; } } public class Condition_PlayerFearLevel : ConditionComparableNumber { [JsonRequired] public float level; public override bool Check(Script script) { if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } float fearLevel = StartOfRound.Instance.fearLevel; return comparisonType switch { ComparisonType.Equals => level == fearLevel, ComparisonType.NotEquals => level != fearLevel, ComparisonType.GreaterThan => level > fearLevel, ComparisonType.LessThan => level < fearLevel, ComparisonType.GreaterThanOrEquals => level >= fearLevel, ComparisonType.LessThanOrEquals => level <= fearLevel, _ => false, }; } } public class Condition_PlayerLocation : Condition { public enum Location { Ship, Facility } [JsonRequired] public Location location; public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } Location location = this.location; if (location != 0) { return location == Location.Facility && GameNetworkManager.Instance.localPlayerController.isInsideFactory; } return GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom; } } public class Condition_PlayerAlone : Condition { public override bool Check(Script script) { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { return GameNetworkManager.Instance.localPlayerController.isPlayerAlone; } return false; } } public class Condition_FiringPlayers : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.firingPlayersCutsceneRunning; } return false; } } public class Condition_Random : Condition { [JsonRequired] public float chance; public override bool Check(Script script) { return Random.Range(0f, 1f) <= chance; } } public class Condition_ShipLanded : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.shipHasLanded; } return false; } } public class Condition_ShipInOrbit : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.inShipPhase; } return false; } } public class Condition_ShipLeavingAlertCalled : Condition { public override bool Check(Script script) { if (!((Object)(object)TimeOfDay.Instance == (Object)null)) { return TimeOfDay.Instance.shipLeavingAlertCalled; } return false; } } public class Condition_ShipIsLeaving : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.shipIsLeaving; } return false; } } public class Condition_TimeOfDay : ConditionComparableNumber { [JsonRequired] public float time; public override bool Check(Script script) { if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } float num = TimeOfDay.Instance.currentDayTime / TimeOfDay.Instance.totalTime; return comparisonType switch { ComparisonType.Equals => num == time, ComparisonType.NotEquals => num != time, ComparisonType.GreaterThan => num > time, ComparisonType.LessThan => num < time, ComparisonType.GreaterThanOrEquals => num >= time, ComparisonType.LessThanOrEquals => num <= time, _ => false, }; } } public class Condition_Timer : Condition { [JsonRequired] public string timerName = string.Empty; [JsonRequired] public float timeGoal; public ConditionComparableNumber.ComparisonType? timerComparisonType; public override bool Check(Script script) { if (!script.activeTimers.TryGetValue(timerName, out var value)) { value = new Script.Timer(timerName); script.activeTimers.Add(timerName, value); } ConditionComparableNumber.ComparisonType valueOrDefault = timerComparisonType.GetValueOrDefault(ConditionComparableNumber.ComparisonType.GreaterThanOrEquals); bool result = false; switch (valueOrDefault) { case ConditionComparableNumber.ComparisonType.Equals: result = value.time == timeGoal; break; case ConditionComparableNumber.ComparisonType.NotEquals: result = value.time != timeGoal; break; case ConditionComparableNumber.ComparisonType.GreaterThan: result = value.time > timeGoal; break; case ConditionComparableNumber.ComparisonType.LessThan: result = value.time < timeGoal; break; case ConditionComparableNumber.ComparisonType.GreaterThanOrEquals: result = value.time >= timeGoal; break; case ConditionComparableNumber.ComparisonType.LessThanOrEquals: result = value.time <= timeGoal; break; } return result; } } public class Condition_Counter : Condition { [JsonRequired] public string counterName = string.Empty; [JsonRequired] public int counterGoal; public ConditionComparableNumber.ComparisonType? counterComparisonType; public override bool Check(Script script) { if (!script.activeCounters.TryGetValue(counterName, out var value)) { value = new Script.Counter(counterName); script.activeCounters.Add(counterName, value); } value.count++; ConditionComparableNumber.ComparisonType valueOrDefault = counterComparisonType.GetValueOrDefault(ConditionComparableNumber.ComparisonType.GreaterThanOrEquals); bool result = false; switch (valueOrDefault) { case ConditionComparableNumber.ComparisonType.Equals: result = value.count == counterGoal; break; case ConditionComparableNumber.ComparisonType.NotEquals: result = value.count != counterGoal; break; case ConditionComparableNumber.ComparisonType.GreaterThan: result = value.count > counterGoal; break; case ConditionComparableNumber.ComparisonType.LessThan: result = value.count < counterGoal; break; case ConditionComparableNumber.ComparisonType.GreaterThanOrEquals: result = value.count >= counterGoal; break; case ConditionComparableNumber.ComparisonType.LessThanOrEquals: result = value.count <= counterGoal; break; } return result; } } public class Condition_Weather : Condition { [JsonRequired] public object weather; private static Type _weatherConfigHelperType; private static MethodInfo _resolveWeatherMethod; private static PropertyInfo _vanillaWeatherTypeProp; public override bool Check(Script script) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } LevelWeatherType currentLevelWeather = TimeOfDay.Instance.currentLevelWeather; if (weather is LevelWeatherType val) { return currentLevelWeather == val; } if (!(weather is string text) || _weatherConfigHelperType == null || _resolveWeatherMethod == null || _vanillaWeatherTypeProp == null) { return false; } try { object obj = _resolveWeatherMethod.Invoke(null, new object[1] { text }); if (obj == null) { return false; } LevelWeatherType val2 = (LevelWeatherType)_vanillaWeatherTypeProp.GetValue(obj); return currentLevelWeather == val2; } catch (Exception) { return false; } } static Condition_Weather() { try { _weatherConfigHelperType = Type.GetType("WeatherRegistry.ConfigHelper, WeatherRegistry"); if (_weatherConfigHelperType != null) { _resolveWeatherMethod = _weatherConfigHelperType.GetMethod("ResolveStringToWeather", new Type[1] { typeof(string) }); Type type = Type.GetType("WeatherRegistry.Weather, WeatherRegistry"); if (type != null) { _vanillaWeatherTypeProp = type.GetProperty("VanillaWeatherType"); } } } catch (Exception) { _weatherConfigHelperType = null; _resolveWeatherMethod = null; _vanillaWeatherTypeProp = null; } } } public class Condition_SelectedLabel : Condition { [JsonRequired] public string label = string.Empty; [JsonRequired] public string group = string.Empty; public override bool Check(Script script) { if (string.IsNullOrEmpty(group)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"Condition_SelectedLabel: group must be specified and non-empty"); return false; } if (script.selectedLabelsByGroup.TryGetValue(group, out var value)) { return value == label; } return false; } } }