Decompiled source of SCPEscapeMusicfix v1.0.1

PizzaTowerEscapeMusic.dll

Decompiled a year ago
using 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;
		}
	}
}