Please disclose if your mod was created primarily 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 CancerCompanySFX Pack v0.8.0
BepInEx/plugins/CustomSounds/DEM_EverlongEscape/EverlongEscapeMusic.dll
Decompiled a year agousing System; 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.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PizzaTowerEscapeMusic.Scripting; using PizzaTowerEscapeMusic.Scripting.Conditions; using PizzaTowerEscapeMusic.Scripting.ScriptEvents; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PizzaTowerEscapeMusic")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Plays music from Pizza Tower when the early ship leave alert appears")] [assembly: AssemblyFileVersion("2.0.2.0")] [assembly: AssemblyInformationalVersion("2.0.2")] [assembly: AssemblyProduct("PizzaTowerEscapeMusic")] [assembly: AssemblyTitle("PizzaTowerEscapeMusic")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } 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 P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [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 P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PizzaTowerEscapeMusic { public class Configuration { private readonly ConfigFile config; internal ConfigEntry<float> volumeMaster; internal ConfigEntry<string> scriptingScript; public Configuration(ConfigFile config) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown this.config = config; RemoveObsoleteEntries(); scriptingScript = config.Bind<string>("Scripting", "Script", "Default", new ConfigDescription("The name of the JSON script file that will be loaded", (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>())); } 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 RemoveObsoleteEntries() { RemoveObsoleteEntry("Volume", "InsideFacility"); RemoveObsoleteEntry("Volume", "OutsideFacility"); RemoveObsoleteEntry("Volume", "InsideShip"); RemoveObsoleteEntry("Volume", "CrouchingScale"); RemoveObsoleteEntry("Music", "InsideFacility"); RemoveObsoleteEntry("Music", "OutsideFacility"); RemoveObsoleteEntry("Music", "HeavyWeather"); } } public class GameEventListener : MonoBehaviour { private ManualLogSource logger; public Action OnSoundManagerCreated = delegate { }; public Action OnSoundManagerDestroyed = delegate { }; public Action OnDungeonDoneGenerating = delegate { }; public Action OnShipLanded = delegate { }; public Action OnShipTakeOff = delegate { }; public Action OnShipReturnToOrbit = 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<SelectableLevel?> OnCurrentMoonChanged = delegate { }; private readonly Dictionary<string, object?> previousValues = new Dictionary<string, object>(); private LungProp? dockedApparatus; private void Awake() { logger = Logger.CreateLogSource("PizzaTowerEscapeMusic GameEventListener"); OnShipLanded = (Action)Delegate.Combine(OnShipLanded, new Action(FindDockedApparatus)); } 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"); } private void Update() { CheckSoundManager(); CheckDungeonDoneGenerating(); CheckShipLanded(); CheckShipReturnToOrbit(); CheckShipLeavingAlertCalled(); CheckPlayerDamaged(); CheckPlayerDeath(); CheckPlayerInsideFacility(); CheckPlayerInsideShip(); CheckApparatusTaken(); CheckCurrentMoonChanged(); } private T? UpdateCached<T>(string key, T? currentValue, T? defaultValue) { if (!previousValues.TryGetValue(key, out object 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 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 has landed"); OnShipLanded(); } else { logger.LogDebug((object)"Ship has taken off"); OnShipTakeOff(); } } } 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 returned to orbit"); OnShipReturnToOrbit(); } } 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 facility"); OnPlayerEnteredFacility(); } else { logger.LogDebug((object)"Player exited 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 ship"); OnPlayerEnteredShip(); } else { logger.LogDebug((object)"Player exited ship"); OnPlayerExitedShip(); } } } private void CheckApparatusTaken() { 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"); OnApparatusTaken(); } } private void CheckCurrentMoonChanged() { SelectableLevel val = TimeOfDay.Instance?.currentLevel; SelectableLevel val2 = UpdateCached<SelectableLevel>("CurrentMoon", val, null); if (!((Object)(object)val == (Object)(object)val2)) { logger.LogDebug((object)("Level has changed to " + val?.PlanetName)); OnCurrentMoonChanged(val); } } } public class MusicManager : MonoBehaviour { private class MusicInstance { public ScriptEvent_PlayMusic musicEvent; public AudioSource audioSource; public Script.VolumeGroup volumeGroup; private bool isStopping; private float volume; public float FadeSpeed { get; private set; } public MusicInstance(ScriptEvent_PlayMusic musicEvent, AudioSource audioSource, AudioClip? musicClip) { this.musicEvent = musicEvent; this.audioSource = audioSource; audioSource.clip = musicClip; audioSource.loop = musicEvent.loop; audioSource.Play(); musicInstances.Add(this); if (musicEvent.tag != null) { if (!musicInstancesByTag.TryGetValue(musicEvent.tag, out List<MusicInstance> value)) { value = new List<MusicInstance>(1); musicInstancesByTag.Add(musicEvent.tag, value); Debug.Log((object)("musicInstancesByTag didn't have a list for tag " + musicEvent.tag + ", creating one now")); } Debug.Log((object)"Added music instance to musicInstancesByTag"); value.Add(this); } volumeGroup = Plugin.ScriptManager.TryGetVolumeGroup(musicEvent.tag); volume = volumeGroup.GetVolume(); } public void Update(float deltaTime) { float num = (isStopping ? 0f : volumeGroup.GetVolume()); float num2 = (isStopping ? volumeGroup.stoppingVolumeLerpSpeed : volumeGroup.volumeLerpSpeed); volume = Mathf.Lerp(volume, num, num2 * deltaTime); audioSource.volume = volume * Plugin.Configuration.volumeMaster.Value; if (!audioSource.isPlaying || (isStopping && audioSource.volume < 0.005f)) { StopCompletely(); } } public void FadeStop() { if (!isStopping) { isStopping = true; FadeSpeed = volumeGroup.stoppingVolumeLerpSpeed; } } public void StopCompletely() { audioSource.Stop(); audioSourcePool.Push(audioSource); musicInstances.Remove(this); if (musicEvent.tag != null && musicInstancesByTag.TryGetValue(musicEvent.tag, out List<MusicInstance> value)) { value.Remove(this); } } } 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>(); 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 List<MusicInstance> value)) { logger.LogDebug((object)$"GetIsMusicPlaying says there's {value.Count} music instance(s) with the tag \"{tag}\""); return value.Count > 0; } logger.LogDebug((object)("GetIsMusicPlaying says there was no music instance list for tag \"" + tag + "\"")); return false; } public void PlayMusic(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)}")); 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; } string text = musicEvent.musicNames[Random.Range(0, musicEvent.musicNames.Length)]; loadedMusic.TryGetValue(text, out AudioClip value); if ((Object)(object)value != (Object)null) { new MusicInstance(musicEvent, GetAudioSource(), value); logger.LogInfo((object)("Playing music (" + text + ")")); } 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.TryPop(out AudioSource result)) { return ((Component)this).gameObject.AddComponent<AudioSource>(); } return result; } public async void LoadNecessaryMusicClips() { if (Plugin.ScriptManager.loadedScript == null) { logger.LogError((object)"Script has not loaded, cannot load its music!"); return; } UnloadMusicClips(); ScriptEvent[] scriptEvents = Plugin.ScriptManager.loadedScript.scriptEvents; for (int i = 0; i < scriptEvents.Length; i++) { if (!(scriptEvents[i] is ScriptEvent_PlayMusic scriptEvent_PlayMusic)) { continue; } string[] musicNames = scriptEvent_PlayMusic.musicNames; foreach (string musicName in musicNames) { if (!loadedMusic.ContainsKey(musicName)) { AudioClip val = await LoadMusicClip(musicName); if (!((Object)(object)val == (Object)null)) { loadedMusic.Add(musicName, val); } } } } logger.LogInfo((object)"Music clips done loading"); } public void UnloadMusicClips() { foreach (AudioClip value in loadedMusic.Values) { value.UnloadAudioData(); } loadedMusic.Clear(); logger.LogInfo((object)"All music clips unloaded"); } private async Task<AudioClip?> LoadMusicClip(string musicFileName) { string path = "file:///" + GetMusicPath(musicFileName); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(path, (AudioType)20); try { request.SendWebRequest(); while (!request.isDone) { await Task.Delay(50); } if ((int)request.result == 1) { logger.LogInfo((object)("Loaded music (" + musicFileName + ") from file")); AudioClip content = DownloadHandlerAudioClip.GetContent(request); ((Object)content).name = musicFileName; return content; } logger.LogError((object)("Failed to load music (" + musicFileName + ") from file:\n- Path: " + path + "\n- Error: " + request.error)); return null; } finally { ((IDisposable)request)?.Dispose(); } } private string GetMusicPath(string musicFileName) { string text = Paths.PluginPath + "/BGN-PizzaTowerEscapeMusic_Custom/Music/" + musicFileName + ".wav"; if (File.Exists(text)) { return text; } return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/DefaultMusic/" + musicFileName + ".wav"; } } [BepInPlugin("bgn.pizzatowerescapemusic", "PizzaTowerEscapeMusic", "2.0.2")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { private const string GUID = "bgn.pizzatowerescapemusic"; private GameEventListener gameEventListener; public static Configuration Configuration { get; private set; } public static ScriptManager ScriptManager { get; private set; } public static MusicManager MusicManager { get; private set; } private void Awake() { Configuration = new Configuration(((BaseUnityPlugin)this).Config); MusicManager = ((Component)this).gameObject.AddComponent<MusicManager>(); gameEventListener = ((Component)this).gameObject.AddComponent<GameEventListener>(); GameEventListener obj = gameEventListener; obj.OnSoundManagerCreated = (Action)Delegate.Combine(obj.OnSoundManagerCreated, new Action(MusicManager.LoadNecessaryMusicClips)); GameEventListener obj2 = gameEventListener; obj2.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj2.OnSoundManagerDestroyed, (Action)delegate { MusicManager.StopMusic(); }); GameEventListener obj3 = gameEventListener; obj3.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj3.OnSoundManagerDestroyed, new Action(MusicManager.UnloadMusicClips)); ScriptManager = new ScriptManager(Configuration.scriptingScript.Value, gameEventListener); ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin bgn.pizzatowerescapemusic is loaded!"); } private void Update() { } } public static class PluginInfo { public const string PLUGIN_GUID = "PizzaTowerEscapeMusic"; public const string PLUGIN_NAME = "PizzaTowerEscapeMusic"; public const string PLUGIN_VERSION = "2.0.2"; } } 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 Condition? condition; } public class VolumeGroup { public string comment = string.Empty; public string tag = string.Empty; public float volumeLerpSpeed = 1f; public float stoppingVolumeLerpSpeed = 1f; [JsonRequired] public VolumeRule[] volumeRules = Array.Empty<VolumeRule>(); public VolumeModifier[] volumeModifiers = Array.Empty<VolumeModifier>(); public float GetVolume() { float num = 1f; VolumeRule[] array = volumeRules; foreach (VolumeRule volumeRule in array) { if (volumeRule.condition == null || volumeRule.condition.Check()) { num = volumeRule.volume; break; } } VolumeModifier[] array2 = volumeModifiers; foreach (VolumeModifier volumeModifier in array2) { if (volumeModifier.condition == null || volumeModifier.condition.Check()) { num *= volumeModifier.volumeScale; } } return num; } } public string comment = string.Empty; public VolumeGroup[] volumeGroups = Array.Empty<VolumeGroup>(); [JsonRequired] public ScriptEvent[] scriptEvents = Array.Empty<ScriptEvent>(); } public class ScriptManager { private readonly ManualLogSource logger; public readonly Script? loadedScript; private readonly Dictionary<ScriptEvent.GameEventType, List<ScriptEvent>> loadedScriptEvents = new Dictionary<ScriptEvent.GameEventType, List<ScriptEvent>>(); private readonly Dictionary<string, Script.VolumeGroup> loadedScriptVolumeGroups = new Dictionary<string, Script.VolumeGroup>(); private static readonly Script.VolumeGroup defaultVolumeGroup = new Script.VolumeGroup(); public ScriptManager(string scriptName, GameEventListener gameEventListener) { logger = Logger.CreateLogSource("PizzaTowerEscapeMusic ScriptManager"); loadedScript = DeserializeScript(scriptName); if (loadedScript == null) { return; } ScriptEvent[] scriptEvents = loadedScript.scriptEvents; foreach (ScriptEvent scriptEvent in scriptEvents) { if (!loadedScriptEvents.TryGetValue(scriptEvent.gameEventType, out List<ScriptEvent> value)) { value = new List<ScriptEvent>(1); loadedScriptEvents.Add(scriptEvent.gameEventType, value); } value.Add(scriptEvent); } Script.VolumeGroup[] volumeGroups = loadedScript.volumeGroups; foreach (Script.VolumeGroup volumeGroup in volumeGroups) { if (!loadedScriptVolumeGroups.TryAdd(volumeGroup.tag, volumeGroup)) { logger.LogError((object)("Volume group tag " + volumeGroup.tag + " was already declaired, you cannot have two volume groups with the same tag")); } } 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.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.OnCurrentMoonChanged = (Action<SelectableLevel>)Delegate.Combine(gameEventListener.OnCurrentMoonChanged, (Action<SelectableLevel>)delegate { CheckScriptEvents(ScriptEvent.GameEventType.CurrentMoonChanged); }); logger.LogInfo((object)("Script (" + scriptName + ") loaded")); } public Script.VolumeGroup TryGetVolumeGroup(string? tag) { if (tag == null || !loadedScriptVolumeGroups.ContainsKey(tag)) { return defaultVolumeGroup; } return loadedScriptVolumeGroups[tag]; } private void CheckScriptEvents(ScriptEvent.GameEventType eventType) { if (!loadedScriptEvents.TryGetValue(eventType, out List<ScriptEvent> value)) { return; } foreach (ScriptEvent item in value) { if (item.CheckConditions()) { 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(); } } } private Script? DeserializeScript(string name) { string scriptPath = GetScriptPath(name); if (!File.Exists(scriptPath)) { logger.LogError((object)("Script \"" + name + "\" does not exist! Make sure you spelt it right the config, and make sure its file extention is \".json\"")); return null; } string text = File.ReadAllText(scriptPath); try { return JsonConvert.DeserializeObject<Script>(text); } catch (Exception ex) { logger.LogError((object)("Failed to deserialize script \"" + name + "\":\n" + ex.Message)); return null; } } private string GetScriptPath(string fileName) { string text = Paths.PluginPath + "/BGN-PizzaTowerEscapeMusic_Custom/Scripts/" + fileName + ".json"; if (File.Exists(text)) { return text; } return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/DefaultScripts/" + fileName + ".json"; } } } namespace PizzaTowerEscapeMusic.Scripting.ScriptEvents { 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!"); } string text = Extensions.Value<string>((IEnumerable<JToken>)val2); ScriptEvent scriptEvent; if (!(text == "PlayMusic")) { if (!(text == "StopMusic")) { throw new Exception($"Condition type \"{val2}\" does not exist"); } scriptEvent = new ScriptEvent_StopMusic(); } else { scriptEvent = new ScriptEvent_PlayMusic(); } ScriptEvent scriptEvent2 = scriptEvent; serializer.Populate(((JToken)val).CreateReader(), (object)scriptEvent2); return scriptEvent2; } public override void WriteJson(JsonWriter writer, ScriptEvent? value, JsonSerializer serializer) { throw new NotImplementedException(); } } [JsonConverter(typeof(ScriptEventConverter))] public abstract class ScriptEvent { public enum GameEventType { ShipLanded, ShipTakeOff, ShipLeavingAlertCalled, PlayerDamaged, PlayerDied, PlayerEnteredFacility, PlayerExitedFacility, PlayerEnteredShip, PlayerExitedShip, ApparatusTaken, CurrentMoonChanged } public string comment = string.Empty; [JsonRequired] public string scriptEventType = string.Empty; [JsonRequired] public GameEventType gameEventType; public Condition[] conditions = Array.Empty<Condition>(); public bool CheckConditions() { return !conditions.Any((Condition c) => !c.Check()); } public abstract void Run(); } 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 override void Run() { if (musicNames.Length != 0) { Plugin.MusicManager.PlayMusic(this); } } } public class ScriptEvent_StopMusic : ScriptEvent { public string[]? targetTags; public bool instant; public override void Run() { if (targetTags != null) { string[] array = targetTags; foreach (string targetTag in array) { if (instant) { Plugin.MusicManager.StopMusic(targetTag); } else { Plugin.MusicManager.FadeStopMusic(targetTag); } } } else if (instant) { Plugin.MusicManager.StopMusic(); } else { Plugin.MusicManager.FadeStopMusic(); } } } } namespace PizzaTowerEscapeMusic.Scripting.Conditions { 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(), "PlayerHealth" => new Condition_PlayerHealth(), "PlayerCrouching" => new Condition_PlayerCrouching(), "ShipLanded" => new Condition_ShipLanded(), "ShipLeavingAlertCalled" => new Condition_ShipLeavingAlertCalled(), "MusicWithTagPlaying" => new Condition_MusicWithTagPlaying(), "CurrentMoon" => new Condition_CurrentMoon(), _ => 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(); } } [JsonConverter(typeof(ConditionConverter))] public abstract class Condition { [JsonRequired] public string conditionType = string.Empty; public abstract bool Check(); } public class Condition_And : Condition { [JsonRequired] public Condition[] conditions = Array.Empty<Condition>(); public override bool Check() { return !conditions.Any((Condition c) => !c.Check()); } } public class Condition_Or : Condition { [JsonRequired] public Condition[] conditions = Array.Empty<Condition>(); public override bool Check() { return conditions.Any((Condition c) => c.Check()); } } public class Condition_Not : Condition { [JsonRequired] public Condition? condition; public override bool Check() { if (condition == null) { return true; } return !condition.Check(); } } public class Condition_Weather : Condition { [JsonRequired] public LevelWeatherType weather; public override bool Check() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } return TimeOfDay.Instance.currentLevelWeather == weather; } } public class Condition_PlayerLocation : Condition { public enum Location { Ship, Facility } [JsonRequired] public Location location; public override bool Check() { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } return location switch { Location.Ship => GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom, Location.Facility => GameNetworkManager.Instance.localPlayerController.isInsideFactory, _ => false, }; } } public class Condition_PlayerAlive : Condition { public override bool Check() { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } return !GameNetworkManager.Instance.localPlayerController.isPlayerDead; } } public class Condition_PlayerHealth : Condition { public enum ComparisonType { Equals, NotEquals, GreaterThan, LessThan, GreaterThanOrEquals, LessThanOrEquals } [JsonRequired] public ComparisonType comparisonType; [JsonRequired] public int value; public override bool Check() { 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_PlayerCrouching : Condition { public override bool Check() { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } return GameNetworkManager.Instance.localPlayerController.isCrouching; } } public class Condition_ShipLanded : Condition { public override bool Check() { if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } return StartOfRound.Instance.shipHasLanded; } } public class Condition_ShipLeavingAlertCalled : Condition { public override bool Check() { if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } return TimeOfDay.Instance.shipLeavingAlertCalled; } } public class Condition_MusicWithTagPlaying : Condition { [JsonRequired] public string tag = string.Empty; public override bool Check() { return Plugin.MusicManager.GetIsMusicPlaying(tag); } } public class Condition_CurrentMoon : Condition { public enum Moons { Gordion = 3, Experimentation = 0, Assurance = 1, Vow = 2, Offense = 7, March = 4, Rend = 5, Dine = 6, Titan = 8 } [JsonRequired] public Moons moon; public override bool Check() { if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } return TimeOfDay.Instance.currentLevel.levelID == (int)moon; } } }