Decompiled source of MusicManager v1.0.0

plugins/MusicSwapper.dll

Decompiled 11 hours 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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates.SolusWing2;
using HG;
using HG.Reflection;
using IL.RoR2;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On.EntityStates.SolusWing2;
using On.RoR2;
using RoR2;
using RoR2.EntitlementManagement;
using RoR2.ExpansionManagement;
using RoR2BepInExPack.GameAssetPathsBetter;
using SimpleJSON;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MusicSwapper")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+57d1654b71976cb5cfc3381312ad6009a9ad915f")]
[assembly: AssemblyProduct("MusicSwapper")]
[assembly: AssemblyTitle("MusicSwapper")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 MusicSwapper
{
	public class ConsistentLanguageInstance : IDisposable
	{
		private List<KeyValuePair<string, string>> consistentTokenStringPairs;

		public ConsistentLanguageInstance()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			Language.LoadAllTokensFromFolders += new hook_LoadAllTokensFromFolders(Language_LoadAllTokensFromFolders);
		}

		private void Language_LoadAllTokensFromFolders(orig_LoadAllTokensFromFolders orig, IEnumerable<string> folders, List<KeyValuePair<string, string>> output)
		{
			orig.Invoke(folders, output);
			Language val = Language.FindLanguageByName("en");
			if (val != null && folders == val.folders)
			{
				consistentTokenStringPairs = output;
			}
		}

		public Dictionary<string, string> BuildConsistentLanguageDictionary()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (consistentTokenStringPairs == null)
			{
				MusicSwapperPlugin.Logger.LogWarning((object)"Failed to cache consistentTokenStringPairs - generating them from the language folders!");
				if (Language.english == null)
				{
					return dictionary;
				}
				consistentTokenStringPairs = new List<KeyValuePair<string, string>>();
				Language.LoadAllTokensFromFolders((IEnumerable<string>)Language.english.folders, consistentTokenStringPairs);
			}
			foreach (KeyValuePair<string, string> consistentTokenStringPair in consistentTokenStringPairs)
			{
				dictionary.TryAdd(consistentTokenStringPair.Key, consistentTokenStringPair.Value);
			}
			return dictionary;
		}

		public void Dispose()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			Language.LoadAllTokensFromFolders -= new hook_LoadAllTokensFromFolders(Language_LoadAllTokensFromFolders);
		}
	}
	public static class Constants
	{
		public const string VALUE_DEFAULT = "default";

		public const string VALUE_INHERIT = "inherit";

		public const string TRACK_NAME_NONE = "None";

		public const string MAIN_TRACK = "Main Track";

		public const string BOSS_TRACK = "Teleporter Track";
	}
	public class HiddenAcceptableValueList<T> : AcceptableValueList<T> where T : IEquatable<T>
	{
		public virtual HashSet<T> HiddenAcceptableValues { get; }

		public HiddenAcceptableValueList(T[] acceptableValues, HashSet<T> hiddenAcceptableValues)
		{
			HiddenAcceptableValues = hiddenAcceptableValues;
			base..ctor(acceptableValues);
		}

		public override bool IsValid(object value)
		{
			if (value is T item && HiddenAcceptableValues.Contains(item))
			{
				return true;
			}
			return base.IsValid(value);
		}
	}
	[BepInPlugin("groovesalad.MusicManager", "MusicManager", "1.0.0")]
	public class MusicSwapperPlugin : BaseUnityPlugin
	{
		public const string GUID = "groovesalad.MusicManager";

		public const string NAME = "MusicManager";

		public const string VERSION = "1.0.0";

		public static ManualLogSource Logger { get; private set; }

		public static string RuntimeDirectory { get; private set; }

		public static string ConfigDirectory { get; private set; }

		public static string DefaultConfigDirectory { get; private set; }

		public static ConfigFile TracksConfig { get; private set; }

		public static ConfigFile ExtrasConfig { get; private set; }

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			RuntimeDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			ConfigDirectory = Path.Combine(Paths.ConfigPath, "MusicManager");
			DefaultConfigDirectory = Path.Combine(RuntimeDirectory, "defaultconfig");
			TracksConfig = GetConfigFile("groovesalad.MusicManager.Tracks.cfg");
			ExtrasConfig = GetConfigFile("groovesalad.MusicManager.Extras.cfg");
			MusicSwapperSystem.Init();
			TeleporterAudioAdjuster.Init();
			SolutionalHauntMusic.Init();
		}

		private ConfigFile GetConfigFile(string relativePath)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			string text = Path.Combine(ConfigDirectory, relativePath);
			if (!File.Exists(text))
			{
				string text2 = Path.Combine(DefaultConfigDirectory, relativePath);
				if (File.Exists(text2))
				{
					Logger.LogMessage((object)("Regenerating the config file " + relativePath + " from the default config file"));
					Directory.CreateDirectory(Path.GetDirectoryName(text));
					File.Copy(text2, text);
				}
			}
			return new ConfigFile(text, true, ((BaseUnityPlugin)this).Info.Metadata);
		}
	}
	public static class MusicSwapperSystem
	{
		private struct SceneMusicConfigurationResult
		{
			public struct TrackResult
			{
				public ConfigEntry<TrackTitle> configEntry;

				public ConfigEntry<TrackTitle> postLoopConfigEntry;
			}

			public TrackResult mainTrack;

			public TrackResult bossTrack;
		}

		private static TrackTitlesInstance trackTitles;

		private static ConsistentLanguageInstance consistentLanguage;

		public static void Init()
		{
			trackTitles = new TrackTitlesInstance("TrackTitles.json");
			consistentLanguage = new ConsistentLanguageInstance();
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnLoad));
		}

		private static void OnLoad()
		{
			DoConfiguration();
			PostLoopMusicManager.Init();
			trackTitles = null;
			consistentLanguage.Dispose();
			consistentLanguage = null;
		}

		private static void DoConfiguration()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			ExpansionDef dlc1 = Addressables.LoadAssetAsync<ExpansionDef>((object)RoR2_DLC1_Common.DLC1_asset).WaitForCompletion();
			HashSet<UnityObjectWrapperKey<SceneDef>> infiniteTowerStages = new HashSet<UnityObjectWrapperKey<SceneDef>>();
			AsyncOperationHandle<SceneCollection> val2 = Addressables.LoadAssetAsync<SceneCollection>((object)RoR2_DLC1_GameModes_InfiniteTowerRun_SceneGroups.sgInfiniteTowerStageX_asset);
			SceneCollection val3 = val2.WaitForCompletion();
			if (Object.op_Implicit((Object)(object)val3))
			{
				Enumerator<SceneEntry> enumerator = val3.sceneEntries.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						SceneEntry current = enumerator.Current;
						infiniteTowerStages.Add(UnityObjectWrapperKey<SceneDef>.op_Implicit(current.sceneDef));
					}
				}
				finally
				{
					((IDisposable)enumerator).Dispose();
				}
			}
			else
			{
				MusicSwapperPlugin.Logger.LogError((object)"Failed to load sgInfiniteTowerStageX!");
			}
			SceneDef[] array = ((IEnumerable<SceneDef>)(object)SceneCatalog.allSceneDefs).Where(SceneValidForConfig).ToArray();
			HashSet<UnityObjectWrapperKey<MusicTrackDef>> allMusicTracks = new HashSet<UnityObjectWrapperKey<MusicTrackDef>>();
			HashSet<UnityObjectWrapperKey<MusicTrackDef>> alwaysAvailableMusicTracks = new HashSet<UnityObjectWrapperKey<MusicTrackDef>>();
			Dictionary<UnityObjectWrapperKey<MusicTrackDef>, HashSet<UnityObjectWrapperKey<EntitlementDef>>> entitlementLockedMusicTracks = new Dictionary<UnityObjectWrapperKey<MusicTrackDef>, HashSet<UnityObjectWrapperKey<EntitlementDef>>>();
			SceneDef[] array2 = array;
			foreach (SceneDef val4 in array2)
			{
				EntitlementDef requiredEntitlement2 = GetRequiredEntitlementFromScene(val4);
				if (SceneValidForMainTrack(val4))
				{
					RegisterMusicTrack(val4.mainTrack, requiredEntitlement2);
				}
				if (SceneValidForBossTrack(val4))
				{
					RegisterMusicTrack(val4.bossTrack, requiredEntitlement2);
				}
			}
			MusicTrackDef val5 = Addressables.LoadAssetAsync<MusicTrackDef>((object)RoR2_Base_Common_MusicTrackDefs.muNone_asset).WaitForCompletion();
			if (Object.op_Implicit((Object)(object)val5))
			{
				RegisterMusicTrack(val5, null);
			}
			else
			{
				MusicSwapperPlugin.Logger.LogError((object)"Failed to load muNone!");
			}
			trackTitles.SetAllTracks(allMusicTracks);
			Dictionary<string, string> consistentLanguageDictionary2 = consistentLanguage.BuildConsistentLanguageDictionary();
			HashSet<char> invalidConfigChars = new HashSet<char> { '=', '\n', '\t', '\\', '"', '\'', '[', ']' };
			foreach (IGrouping<string, SceneDef> baseNameSceneGroup in from x in array
				group x by x.baseSceneName)
			{
				SceneMusicConfigurationResult sceneMusicConfigurationResult = default(SceneMusicConfigurationResult);
				MusicTrackDef val6 = null;
				MusicTrackDef val7 = null;
				List<SceneDef> list = baseNameSceneGroup.ToList();
				if (list.Count > 1)
				{
					int num = list.FindIndex((SceneDef x) => x.cachedName == baseNameSceneGroup.Key);
					if (num >= 0)
					{
						SceneDef val8 = list[num];
						if (Object.op_Implicit((Object)(object)val8))
						{
							val6 = val8.mainTrack;
							val7 = val8.bossTrack;
							sceneMusicConfigurationResult = ConfigureSceneMusic(val8, default(SceneMusicConfigurationResult.TrackResult), default(SceneMusicConfigurationResult.TrackResult));
						}
						list.RemoveAt(num);
					}
				}
				foreach (SceneDef item in list)
				{
					ConfigureSceneMusic(item, ((Object)(object)item.mainTrack == (Object)(object)val6) ? sceneMusicConfigurationResult.mainTrack : default(SceneMusicConfigurationResult.TrackResult), ((Object)(object)item.bossTrack == (Object)(object)val7) ? sceneMusicConfigurationResult.bossTrack : default(SceneMusicConfigurationResult.TrackResult));
				}
			}
			val2.Release();
			invalidConfigChars = null;
			ConfigEntry<TrackTitle> ConfigureMusicTrack(ref MusicTrackDef musicTrack, SceneDef scene, string section, string key, string description, [CanBeNull] ConfigEntry<TrackTitle> parentConfigEntry)
			{
				if (!trackTitles.InternalNameToAlbumName.TryGetValue(musicTrack.cachedName, out var value2))
				{
					value2 = musicTrack.cachedName;
				}
				ConfigEntry<TrackTitle> val10 = CreateMusicTrackConfigEntry(section, key, description, string.Empty, value2, parentConfigEntry);
				if (ShouldApplyMusicTrackConfig(val10, scene, parentConfigEntry, out var chosenMusicTrack3))
				{
					MusicSwapperPlugin.Logger.LogMessage((object)("Setting the " + scene.cachedName + " " + key + " to " + chosenMusicTrack3.cachedName + " (formerly " + musicTrack.cachedName + ")"));
					musicTrack = chosenMusicTrack3;
				}
				return val10;
			}
			ConfigEntry<TrackTitle> ConfigureMusicTrackPostLoop(PostLoopMusicManager.IPostLoopTrackData postLoopTrackData, SceneDef scene, string section, string key, [CanBeNull] ConfigEntry<TrackTitle> parentConfigEntry)
			{
				ConfigEntry<TrackTitle> val9 = CreateMusicTrackConfigEntry(section, "Post-Loop " + key, "Choose a track to override the " + key + " after looping once.", "\nChoose \"default\" to disable this feature.", "default", parentConfigEntry);
				if (ShouldApplyMusicTrackConfig(val9, scene, parentConfigEntry, out var chosenMusicTrack2))
				{
					MusicSwapperPlugin.Logger.LogMessage((object)("Setting the " + scene.cachedName + " " + ((ConfigEntryBase)val9).Definition.Key + " to " + chosenMusicTrack2.cachedName));
					postLoopTrackData.RegisterTrack(scene, chosenMusicTrack2);
				}
				return val9;
			}
			SceneMusicConfigurationResult ConfigureSceneMusic(SceneDef scene, SceneMusicConfigurationResult.TrackResult mainTrackParent, SceneMusicConfigurationResult.TrackResult bossTrackParent)
			{
				SceneMusicConfigurationResult result = default(SceneMusicConfigurationResult);
				string configSectionForScene = GetConfigSectionForScene(scene, consistentLanguageDictionary2);
				bool flag = SceneValidForMainTrack(scene);
				bool flag2 = SceneValidForBossTrack(scene);
				if (flag)
				{
					result.mainTrack.configEntry = ConfigureMusicTrack(ref scene.mainTrack, scene, configSectionForScene, "Main Track", "Choose a track for the stage.", mainTrackParent.configEntry);
				}
				if (flag2)
				{
					result.bossTrack.configEntry = ConfigureMusicTrack(ref scene.bossTrack, scene, configSectionForScene, "Teleporter Track", "Choose a track for the Teleporter event.", bossTrackParent.configEntry);
				}
				if (flag)
				{
					result.mainTrack.postLoopConfigEntry = ConfigureMusicTrackPostLoop(PostLoopMusicManager.mainTrackData, scene, configSectionForScene, "Main Track", mainTrackParent.postLoopConfigEntry);
				}
				if (flag2)
				{
					result.bossTrack.postLoopConfigEntry = ConfigureMusicTrackPostLoop(PostLoopMusicManager.bossTrackData, scene, configSectionForScene, "Teleporter Track", bossTrackParent.postLoopConfigEntry);
				}
				return result;
			}
			static ConfigEntry<TrackTitle> CreateMusicTrackConfigEntry(string section, string key, string desc, string specialValuesDesc, string defaultValue, [CanBeNull] ConfigEntry<TrackTitle> parentConfigEntry)
			{
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Expected O, but got Unknown
				List<TrackTitle> list2 = trackTitles.PrimaryTrackTitles.ToList();
				if (parentConfigEntry != null)
				{
					if (!list2.Contains(defaultValue))
					{
						list2.Insert(0, defaultValue);
					}
					defaultValue = "inherit";
					specialValuesDesc = "\nChoose \"inherit\" to use the same " + key + " as " + ((ConfigEntryBase)parentConfigEntry).Definition.Section + "." + specialValuesDesc;
				}
				list2.Remove(defaultValue);
				list2.Insert(0, defaultValue);
				desc += " Some tracks require DLC.";
				if (!string.IsNullOrEmpty(specialValuesDesc))
				{
					desc = desc + "\nSpecial Values:" + specialValuesDesc;
				}
				return MusicSwapperPlugin.TracksConfig.Bind<TrackTitle>(section, key, (TrackTitle)defaultValue, new ConfigDescription(desc, (AcceptableValueBase)(object)new HiddenAcceptableValueList<TrackTitle>(list2.ToArray(), trackTitles.AllTrackTitles), Array.Empty<object>()));
			}
			string GetConfigSafeString(string val)
			{
				val = val.Replace('\'', 'ꞌ');
				for (int num2 = val.Length - 1; num2 >= 0; num2--)
				{
					if (invalidConfigChars.Contains(val[num2]))
					{
						val = val.Remove(num2, 1);
					}
				}
				return val;
			}
			string GetConfigSectionForScene(SceneDef scene, Dictionary<string, string> consistentLanguageDictionary)
			{
				string value3;
				string val11 = ((string.IsNullOrEmpty(scene.nameToken) || !consistentLanguageDictionary.TryGetValue(scene.nameToken, out value3) || string.IsNullOrWhiteSpace(value3)) ? scene.cachedName : (value3 + " (" + scene.cachedName + ")"));
				return GetConfigSafeString(val11);
			}
			EntitlementDef GetRequiredEntitlementFromScene(SceneDef scene)
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				EntitlementDef val12 = (Object.op_Implicit((Object)(object)scene.requiredExpansion) ? scene.requiredExpansion.requiredEntitlement : null);
				if (!Object.op_Implicit((Object)(object)val12) && infiniteTowerStages.Contains(UnityObjectWrapperKey<SceneDef>.op_Implicit(scene)) && Object.op_Implicit((Object)(object)dlc1))
				{
					val12 = dlc1.requiredEntitlement;
				}
				return val12;
			}
			void RegisterMusicTrack(MusicTrackDef musicTrack, [CanBeNull] EntitlementDef requiredEntitlement)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				allMusicTracks.Add(UnityObjectWrapperKey<MusicTrackDef>.op_Implicit(musicTrack));
				if (!alwaysAvailableMusicTracks.Contains(UnityObjectWrapperKey<MusicTrackDef>.op_Implicit(musicTrack)))
				{
					HashSet<UnityObjectWrapperKey<EntitlementDef>> value4;
					if (!Object.op_Implicit((Object)(object)requiredEntitlement) || ((BaseUserEntitlementTracker<LocalUser>)(object)EntitlementManager.localUserEntitlementTracker).AnyUserHasEntitlement(requiredEntitlement))
					{
						alwaysAvailableMusicTracks.Add(UnityObjectWrapperKey<MusicTrackDef>.op_Implicit(musicTrack));
						entitlementLockedMusicTracks.Remove(UnityObjectWrapperKey<MusicTrackDef>.op_Implicit(musicTrack));
					}
					else if (entitlementLockedMusicTracks.TryGetValue(UnityObjectWrapperKey<MusicTrackDef>.op_Implicit(musicTrack), out value4))
					{
						value4.Add(UnityObjectWrapperKey<EntitlementDef>.op_Implicit(requiredEntitlement));
					}
					else
					{
						entitlementLockedMusicTracks.Add(UnityObjectWrapperKey<MusicTrackDef>.op_Implicit(musicTrack), new HashSet<UnityObjectWrapperKey<EntitlementDef>> { UnityObjectWrapperKey<EntitlementDef>.op_Implicit(requiredEntitlement) });
					}
				}
			}
			bool SceneValidForBossTrack(SceneDef scene)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				return Object.op_Implicit((Object)(object)scene.bossTrack) && scene.hasAnyDestinations && !infiniteTowerStages.Contains(UnityObjectWrapperKey<SceneDef>.op_Implicit(scene));
			}
			static bool SceneValidForConfig(SceneDef scene)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Invalid comparison between Unknown and I4
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Invalid comparison between Unknown and I4
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Invalid comparison between Unknown and I4
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Invalid comparison between Unknown and I4
				if (scene.isOfflineScene)
				{
					return false;
				}
				SceneType sceneType = scene.sceneType;
				if ((int)sceneType != 1 && (int)sceneType != 2 && (int)sceneType != 4 && (int)sceneType != 5)
				{
					return false;
				}
				return true;
			}
			static bool SceneValidForMainTrack(SceneDef scene)
			{
				return Object.op_Implicit((Object)(object)scene.mainTrack);
			}
			bool ShouldApplyMusicTrackConfig(ConfigEntry<TrackTitle> configEntry, SceneDef scene, [CanBeNull] ConfigEntry<TrackTitle> parentConfigEntry, out MusicTrackDef chosenMusicTrack)
			{
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				chosenMusicTrack = null;
				if (string.Equals(configEntry.Value, "inherit"))
				{
					if (parentConfigEntry != null)
					{
						return ShouldApplyMusicTrackConfig(parentConfigEntry, scene, null, out chosenMusicTrack);
					}
					return false;
				}
				if (string.Equals(configEntry.Value, (TrackTitle)((ConfigEntryBase)configEntry).DefaultValue))
				{
					return false;
				}
				if (string.Equals(configEntry.Value, "default"))
				{
					return false;
				}
				if (!trackTitles.TrackNameToMusicTrackDef.TryGetValue(configEntry.Value, out chosenMusicTrack))
				{
					return false;
				}
				if (entitlementLockedMusicTracks.TryGetValue(UnityObjectWrapperKey<MusicTrackDef>.op_Implicit(chosenMusicTrack), out var value))
				{
					EntitlementDef requiredEntitlementFromScene = GetRequiredEntitlementFromScene(scene);
					if (!Object.op_Implicit((Object)(object)requiredEntitlementFromScene) || !value.Contains(UnityObjectWrapperKey<EntitlementDef>.op_Implicit(requiredEntitlementFromScene)))
					{
						MusicSwapperPlugin.Logger.LogWarning((object)("The " + scene.cachedName + " " + ((ConfigEntryBase)configEntry).Definition.Key + " cannot be set to " + chosenMusicTrack.cachedName + " because the track's entitlement requirements are not met"));
						return false;
					}
				}
				return true;
			}
		}
	}
	public static class PostLoopMusicManager
	{
		public interface IPostLoopTrackData
		{
			void RegisterTrack(SceneDef scene, MusicTrackDef postLoopTrack);
		}

		public class PostLoopTrackData : IPostLoopTrackData
		{
			private readonly string trackName;

			public Dictionary<UnityObjectWrapperKey<SceneDef>, MusicTrackDef> tracks;

			public MusicTrackDef mostRecentTrack;

			public bool setHook;

			public bool HasTracks => tracks != null && tracks.Count > 0;

			public PostLoopTrackData(string trackName)
			{
				this.trackName = trackName;
				base..ctor();
			}

			public void RegisterTrack(SceneDef scene, MusicTrackDef postLoopTrack)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				(tracks ?? (tracks = new Dictionary<UnityObjectWrapperKey<SceneDef>, MusicTrackDef>()))[UnityObjectWrapperKey<SceneDef>.op_Implicit(scene)] = postLoopTrack;
			}

			public void Init()
			{
				if (HasTracks)
				{
					SceneCatalog.onMostRecentSceneDefChanged += OnMostRecentSceneDefChanged;
				}
			}

			private void OnMostRecentSceneDefChanged(SceneDef mostRecentSceneDef)
			{
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Expected O, but got Unknown
				mostRecentTrack = null;
				if (Object.op_Implicit((Object)(object)Run.instance) && Run.instance.loopClearCount > 0 && tracks.TryGetValue(UnityObjectWrapperKey<SceneDef>.op_Implicit(mostRecentSceneDef), out mostRecentTrack) && !setHook)
				{
					MusicSwapperPlugin.Logger.LogMessage((object)("Setting a hook to override " + trackName + " post loop"));
					setHook = true;
					MusicController.PickCurrentTrack += new Manipulator(OverrideTrackPostLoop);
				}
			}

			private void OverrideTrackPostLoop(ILContext il)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Expected O, but got Unknown
				ILCursor val = new ILCursor(il);
				while (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
				{
					(Instruction x) => ILPatternMatchingExt.MatchLdfld<SceneDef>(x, trackName)
				}))
				{
					val.EmitDelegate<Func<MusicTrackDef, MusicTrackDef>>((Func<MusicTrackDef, MusicTrackDef>)((MusicTrackDef track) => Object.op_Implicit((Object)(object)mostRecentTrack) ? mostRecentTrack : track));
				}
			}
		}

		public static readonly PostLoopTrackData mainTrackData = new PostLoopTrackData("mainTrack");

		public static readonly PostLoopTrackData bossTrackData = new PostLoopTrackData("bossTrack");

		public static void Init()
		{
			mainTrackData.Init();
			bossTrackData.Init();
		}
	}
	public static class SolutionalHauntMusic
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_OnEnter <0>__Mission5Death_OnEnter;
		}

		public static void Init()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			ConfigEntry<bool> val = MusicSwapperPlugin.ExtrasConfig.Bind<bool>("Solutional Haunt", "Restart Music After Fight", false, "After the Solus Wing fight, resume playing the main track of Solutional Haunt.");
			if (val.Value)
			{
				MusicSwapperPlugin.Logger.LogMessage((object)"SolutionalHauntMusic extra is active");
				object obj = <>O.<0>__Mission5Death_OnEnter;
				if (obj == null)
				{
					hook_OnEnter val2 = Mission5Death_OnEnter;
					<>O.<0>__Mission5Death_OnEnter = val2;
					obj = (object)val2;
				}
				Mission5Death.OnEnter += (hook_OnEnter)obj;
			}
		}

		private static void Mission5Death_OnEnter(orig_OnEnter orig, Mission5Death self)
		{
			orig.Invoke(self);
			if (Object.op_Implicit((Object)(object)((SolusWing2BaseMissionState)self).solutionalHauntReferences) && Object.op_Implicit((Object)(object)((SolusWing2BaseMissionState)self).solutionalHauntReferences.PostFightMusic))
			{
				((SolusWing2BaseMissionState)self).solutionalHauntReferences.PostFightMusic.AddComponent<DestroyOnTimer>().duration = 10f;
			}
		}
	}
	public static class TeleporterAudioAdjuster
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_UpdateTeleporterParameters <0>__MusicController_UpdateTeleporterParameters;
		}

		private static float proximityScalar;

		public static void Init()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			ConfigEntry<float> val = MusicSwapperPlugin.ExtrasConfig.Bind<float>("Teleporter Hum", "Volume Multiplier", 1f, new ConfigDescription("Reduce this value to dampen the volume of Teleporter hum (the Teleporter hum emits from the Teleporter and plays along with a stage's main track).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			if (val.Value != 1f)
			{
				MusicSwapperPlugin.Logger.LogMessage((object)"TeleporterAudioAdjuster extra is active");
				proximityScalar = Mathf.Clamp01(val.Value);
				object obj = <>O.<0>__MusicController_UpdateTeleporterParameters;
				if (obj == null)
				{
					hook_UpdateTeleporterParameters val2 = MusicController_UpdateTeleporterParameters;
					<>O.<0>__MusicController_UpdateTeleporterParameters = val2;
					obj = (object)val2;
				}
				MusicController.UpdateTeleporterParameters += (hook_UpdateTeleporterParameters)obj;
			}
		}

		private static void MusicController_UpdateTeleporterParameters(orig_UpdateTeleporterParameters orig, MusicController self, TeleporterInteraction teleporter, Transform cameraTransform, CharacterBody targetBody)
		{
			orig.Invoke(self, teleporter, cameraTransform, targetBody);
			float value = self.rtpcTeleporterProximityValue.value;
			self.rtpcTeleporterProximityValue.value = Util.Remap(value, 0f, 10000f, 10000f - 10000f * proximityScalar, 10000f);
		}
	}
	public readonly struct TrackTitle : IEquatable<TrackTitle>
	{
		public string Value { get; }

		public TrackTitle(string value)
		{
			Value = value;
		}

		static TrackTitle()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			TomlTypeConverter.AddConverter(typeof(TrackTitle), new TypeConverter
			{
				ConvertToString = (object obj, Type type) => obj.ToString(),
				ConvertToObject = (string str, Type type) => new TrackTitle(str)
			});
		}

		public override string ToString()
		{
			return Value;
		}

		public static implicit operator TrackTitle(string value)
		{
			return new TrackTitle(value);
		}

		public static implicit operator string(TrackTitle trackTitle)
		{
			return trackTitle.Value;
		}

		public override int GetHashCode()
		{
			return Value?.GetHashCode() ?? 0;
		}

		public bool Equals(string other)
		{
			return string.Equals(Value, other);
		}

		public bool Equals(TrackTitle other)
		{
			return Equals(other.Value);
		}

		public override bool Equals(object other)
		{
			if (1 == 0)
			{
			}
			bool result = ((other is TrackTitle other2) ? Equals(other2) : (other is string other3 && Equals(other3)));
			if (1 == 0)
			{
			}
			return result;
		}
	}
	public class TrackTitlesInstance
	{
		public Dictionary<string, string> InternalNameToAlbumName { get; private set; }

		public List<TrackTitle> PrimaryTrackTitles { get; private set; }

		public HashSet<TrackTitle> AllTrackTitles { get; private set; }

		public Dictionary<string, MusicTrackDef> TrackNameToMusicTrackDef { get; private set; }

		public TrackTitlesInstance(string fileName)
		{
			InternalNameToAlbumName = new Dictionary<string, string>();
			string path = Path.Combine(MusicSwapperPlugin.RuntimeDirectory, fileName);
			if (!File.Exists(path))
			{
				MusicSwapperPlugin.Logger.LogWarning((object)("Could not find " + fileName + "!"));
				return;
			}
			JSONNode val = JSON.Parse(File.ReadAllText(path));
			foreach (string key in val.Keys)
			{
				string value = val[key].Value;
				InternalNameToAlbumName.Add(key, value);
			}
			MusicSwapperPlugin.Logger.LogMessage((object)$"Loaded {val.Count} track titles from {fileName}");
		}

		public void SetAllTracks(HashSet<UnityObjectWrapperKey<MusicTrackDef>> allTracks)
		{
			AllTrackTitles = new HashSet<TrackTitle>();
			TrackNameToMusicTrackDef = new Dictionary<string, MusicTrackDef>();
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			foreach (MusicTrackDef item in allTracks.Select((UnityObjectWrapperKey<MusicTrackDef> x) => x.value))
			{
				string cachedName = item.cachedName;
				if (InternalNameToAlbumName.TryGetValue(cachedName, out var value))
				{
					if (!list.Contains(value))
					{
						list.Add(value);
					}
					AllTrackTitles.Add(value);
					TrackNameToMusicTrackDef.TryAdd(value, item);
				}
				else if (!list2.Contains(cachedName))
				{
					list2.Add(cachedName);
				}
				AllTrackTitles.Add(cachedName);
				TrackNameToMusicTrackDef.TryAdd(cachedName, item);
			}
			list.Sort();
			list2.Sort();
			List<string> list3 = list;
			List<string> list4 = list2;
			List<TrackTitle> list5 = new List<TrackTitle>(list3.Count + list4.Count);
			foreach (string item2 in list3)
			{
				list5.Add(item2);
			}
			foreach (string item3 in list4)
			{
				list5.Add(item3);
			}
			PrimaryTrackTitles = list5;
			if (PrimaryTrackTitles.Remove("None"))
			{
				PrimaryTrackTitles.Add("None");
			}
		}
	}
}