Decompiled source of BigRadio v1.0.1

BigRadio.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BigRadio")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+36783b4aa600e8cf1c6e45b85fef1d23f6153c65")]
[assembly: AssemblyProduct("BigRadio")]
[assembly: AssemblyTitle("BigRadio")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 BigRadio
{
	internal static class Core
	{
		private sealed class Pending
		{
			public string Key;

			public string File;

			public UnityWebRequest Request;
		}

		private const string StationSection = "Stations";

		private const float PollInterval = 0.25f;

		private static ConfigEntry<string> _musicFolderCfg;

		private static ConfigEntry<string> _reloadKeyCfg;

		private static ConfigEntry<bool> _verboseCfg;

		private static ConfigEntry<bool> _shuffleCfg;

		private static readonly Random Rng = new Random();

		private static readonly Dictionary<string, ConfigEntry<string>> Stations = new Dictionary<string, ConfigEntry<string>>();

		private static readonly Dictionary<IntPtr, string> GroupToKey = new Dictionary<IntPtr, string>();

		private static readonly HashSet<string> UsedKeys = new HashSet<string>();

		private static readonly Dictionary<string, AudioClip> Clips = new Dictionary<string, AudioClip>();

		private static readonly List<string> AvailableFiles = new List<string>();

		private static readonly Dictionary<IntPtr, AudioClip> Primary = new Dictionary<IntPtr, AudioClip>();

		private static readonly HashSet<IntPtr> Muted = new HashSet<IntPtr>();

		private static bool _inOwnPlay;

		private static readonly List<Pending> PendingLoads = new List<Pending>();

		private static readonly List<AudioClip> ToDestroy = new List<AudioClip>();

		private static readonly Dictionary<string, List<MusicPlayer>> ByKey = new Dictionary<string, List<MusicPlayer>>();

		private static int _reloadVk;

		private static bool _keyWasDown;

		private static float _nextPoll;

		private static readonly HashSet<string> Reported = new HashSet<string>();

		private static readonly Action TickAction = TickInner;

		internal static string MusicFolder { get; private set; }

		private static bool Verbose
		{
			get
			{
				if (_verboseCfg != null)
				{
					return _verboseCfg.Value;
				}
				return false;
			}
		}

		[DllImport("user32.dll")]
		private static extern short GetAsyncKeyState(int vKey);

		internal static void Init()
		{
			ConfigFile cfg = Plugin.Cfg;
			string text = Path.Combine(Paths.ConfigPath, "BigRadio");
			_musicFolderCfg = cfg.Bind<string>("General", "Music Folder", text, "Folder that holds your music files. Put .ogg, .wav or .mp3 files here, then restart the game so they appear in the station lists below.");
			_reloadKeyCfg = cfg.Bind<string>("General", "Reload Key", "F8", "Key that reloads this config while the game runs. F1-F24, or a single letter or digit.");
			_shuffleCfg = cfg.Bind<bool>("General", "Shuffle On Reload", true, "Reload key reshuffles: every audio file in the music folder is dealt out to a random station, never the same file twice. Turn off to keep your hand-written station list.");
			_verboseCfg = cfg.Bind<bool>("General", "Verbose Logging", false, "Log every radio playback change. Turn on when reporting a bug.");
			ApplyGeneralSettings();
			ScanFiles();
		}

		private static void ApplyGeneralSettings()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			string text = (_musicFolderCfg.Value ?? "").Trim().Trim('"');
			MusicFolder = ((text.Length == 0) ? Path.Combine(Paths.ConfigPath, "BigRadio") : text);
			try
			{
				Directory.CreateDirectory(MusicFolder);
				string path = Path.Combine(MusicFolder, "PUT_YOUR_MUSIC_HERE.txt");
				if (!File.Exists(path))
				{
					File.WriteAllText(path, "Put your .ogg, .wav or .mp3 files in this folder.\r\nThen open ArtemisCorp.BigRadio.cfg (mod manager: Config editor) and write a file name\r\nnext to a station under [Stations], e.g.  musicGroup_DanceFM = my song.ogg\r\nStations appear in the config after you have loaded into a walk once.\r\nPress F8 in-game to reload.\r\n");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not create music folder '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(MusicFolder);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				l.LogWarning(val);
			}
			_reloadVk = ParseKey(_reloadKeyCfg.Value);
		}

		private static int ParseKey(string raw)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			string text = (raw ?? "").Trim().ToUpperInvariant();
			if (text.Length >= 2 && text[0] == 'F' && int.TryParse(text.Substring(1), out var result) && result >= 1 && result <= 24)
			{
				return 112 + result - 1;
			}
			if (text.Length == 1 && char.IsLetterOrDigit(text[0]))
			{
				return text[0];
			}
			ManualLogSource l = Plugin.L;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(39, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ReloadKey '");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(raw);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' not recognised - using F8.");
			}
			l.LogWarning(val);
			return 119;
		}

		internal static void OnManagerInitialized(FmRadioManager manager)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			Il2CppReferenceArray<MusicGroup> stationTrackGroups = manager.stationTrackGroups;
			if (stationTrackGroups == null)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (MusicGroup item in (Il2CppArrayBase<MusicGroup>)(object)stationTrackGroups)
			{
				if (!((Object)(object)item == (Object)null) && !GroupToKey.ContainsKey(((Il2CppObjectBase)item).Pointer))
				{
					string text = Register(item);
					if (text != null)
					{
						list.Add(text);
					}
				}
			}
			if (list.Count > 0)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(23, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Found ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" radio stations: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", list));
				}
				l.LogInfo(val);
			}
		}

		private static void ScanFiles()
		{
			AvailableFiles.Clear();
			AvailableFiles.Add("");
			try
			{
				List<string> list = new List<string>();
				foreach (string item in Directory.EnumerateFiles(MusicFolder))
				{
					switch (Path.GetExtension(item).ToLowerInvariant())
					{
					case ".ogg":
					case ".wav":
					case ".mp3":
						list.Add(Path.GetFileName(item));
						break;
					}
				}
				list.Sort(StringComparer.OrdinalIgnoreCase);
				AvailableFiles.AddRange(list);
			}
			catch (Exception e)
			{
				Report("scan music folder", e);
			}
		}

		private static string Register(MusicGroup group)
		{
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			if ((Object)(object)group == (Object)null)
			{
				return null;
			}
			if (GroupToKey.TryGetValue(((Il2CppObjectBase)group).Pointer, out var value))
			{
				return value;
			}
			string text = Regex.Replace((((Object)group).name ?? "").Replace("musicGroup_", ""), "[^A-Za-z0-9 _-]", "").Trim();
			if (text.Length == 0)
			{
				text = "unknown";
			}
			int num = -1;
			try
			{
				num = FmRadioManager.GetIndex(group);
			}
			catch
			{
			}
			string text2 = ((num >= 0) ? $"Station {num + 1} ({text})" : ("Station (" + text + ")"));
			int num2 = 2;
			while (UsedKeys.Contains(text2))
			{
				text2 = $"Station {num + 1} ({text}) {num2}";
				num2++;
			}
			ConfigEntry<string> value2 = Plugin.Cfg.Bind<string>("Stations", text2, "", new ConfigDescription("Track for this station. Leave empty for the game's original music.", (AcceptableValueBase)(object)new AcceptableValueList<string>(AvailableFiles.ToArray()), Array.Empty<object>()));
			UsedKeys.Add(text2);
			Stations[text2] = value2;
			GroupToKey[((Il2CppObjectBase)group).Pointer] = text2;
			QueueLoad(text2);
			return text2;
		}

		private static void QueueLoad(string key)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			for (int num = PendingLoads.Count - 1; num >= 0; num--)
			{
				if (!(PendingLoads[num].Key != key))
				{
					try
					{
						PendingLoads[num].Request.Abort();
						PendingLoads[num].Request.Dispose();
					}
					catch
					{
					}
					PendingLoads.RemoveAt(num);
				}
			}
			string text = (Stations[key].Value ?? "").Trim().Trim('"');
			bool flag = default(bool);
			if (text.Length == 0)
			{
				DropClip(key);
				if (Verbose)
				{
					ManualLogSource l = Plugin.L;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(key);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] original music");
					}
					l.LogInfo(val);
				}
				return;
			}
			string text2 = (Path.IsPathRooted(text) ? text : Path.Combine(MusicFolder, text));
			if (!File.Exists(text2))
			{
				DropClip(key);
				ManualLogSource l2 = Plugin.L;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(44, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(key);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] file not found: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" - playing original music");
				}
				l2.LogWarning(val2);
				return;
			}
			AudioType val3 = (AudioType)(Path.GetExtension(text2).ToLowerInvariant() switch
			{
				".ogg" => 14, 
				".wav" => 20, 
				".mp3" => 13, 
				_ => 0, 
			});
			if ((int)val3 == 0)
			{
				DropClip(key);
				ManualLogSource l3 = Plugin.L;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(73, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(key);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] unsupported format: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (use .ogg, .wav or .mp3) - playing original music");
				}
				l3.LogWarning(val2);
			}
			else
			{
				UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(new Uri(text2).AbsoluteUri, val3);
				audioClip.SendWebRequest();
				PendingLoads.Add(new Pending
				{
					Key = key,
					File = text,
					Request = audioClip
				});
			}
		}

		private static void DropClip(string key)
		{
			if (Clips.Remove(key, out var value))
			{
				ToDestroy.Add(value);
				ClearOverrides();
			}
		}

		private static void FinishLoads()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			bool flag = default(bool);
			for (int num = PendingLoads.Count - 1; num >= 0; num--)
			{
				Pending pending = PendingLoads[num];
				if (pending.Request.isDone)
				{
					PendingLoads.RemoveAt(num);
					try
					{
						if ((int)pending.Request.result != 1)
						{
							DropClip(pending.Key);
							ManualLogSource l = Plugin.L;
							BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(46, 3, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pending.Key);
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pending.File);
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" failed to load (");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pending.Request.error);
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") - playing original music");
							}
							l.LogWarning(val);
						}
						else
						{
							AudioClip content = DownloadHandlerAudioClip.GetContent(pending.Request);
							if ((Object)(object)content == (Object)null || content.length <= 0f)
							{
								DropClip(pending.Key);
								ManualLogSource l2 = Plugin.L;
								BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(49, 2, ref flag);
								if (flag)
								{
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
									((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pending.Key);
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] ");
									((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pending.File);
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" could not be decoded - playing original music");
								}
								l2.LogWarning(val);
							}
							else
							{
								((Object)content).name = "BigRadio_" + pending.Key;
								((Object)content).hideFlags = (HideFlags)32;
								if (Clips.TryGetValue(pending.Key, out var value))
								{
									ToDestroy.Add(value);
								}
								Clips[pending.Key] = content;
								ClearOverrides();
								ManualLogSource l3 = Plugin.L;
								BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(13, 3, ref flag);
								if (flag)
								{
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(pending.Key);
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("] ");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(pending.File);
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded (");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(FormatTime(content.length));
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
								}
								l3.LogInfo(val2);
							}
						}
					}
					finally
					{
						pending.Request.Dispose();
					}
				}
			}
			if (PendingLoads.Count != 0 || ToDestroy.Count <= 0)
			{
				return;
			}
			foreach (AudioClip item in ToDestroy)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			ToDestroy.Clear();
		}

		private static string FormatTime(float seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			if (!(timeSpan.TotalHours >= 1.0))
			{
				return timeSpan.ToString("m\\:ss");
			}
			return timeSpan.ToString("h\\:mm\\:ss");
		}

		private static void ClearOverrides()
		{
			Primary.Clear();
			Muted.Clear();
		}

		private static void Reload()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			Plugin.Cfg.Reload();
			ApplyGeneralSettings();
			if (_shuffleCfg != null && _shuffleCfg.Value)
			{
				Shuffle();
			}
			ManualLogSource l = Plugin.L;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Reloading ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Stations.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" stations from config...");
			}
			l.LogInfo(val);
			foreach (string item in new List<string>(Stations.Keys))
			{
				QueueLoad(item);
			}
			ClearOverrides();
		}

		private static void Shuffle()
		{
			if (Stations.Count == 0)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (string availableFile in AvailableFiles)
			{
				if (availableFile.Length == 0)
				{
					continue;
				}
				try
				{
					if (File.Exists(Path.Combine(MusicFolder, availableFile)))
					{
						list.Add(availableFile);
					}
				}
				catch
				{
				}
			}
			for (int num = list.Count - 1; num > 0; num--)
			{
				int num2 = Rng.Next(num + 1);
				List<string> list2 = list;
				int index = num;
				int index2 = num2;
				string value = list[num2];
				string value2 = list[num];
				list2[index] = value;
				list[index2] = value2;
			}
			List<string> list3 = new List<string>(Stations.Keys);
			for (int num3 = list3.Count - 1; num3 > 0; num3--)
			{
				int num4 = Rng.Next(num3 + 1);
				List<string> list2 = list3;
				int index2 = num3;
				int index = num4;
				string value2 = list3[num4];
				string value = list3[num3];
				list2[index2] = value2;
				list3[index] = value;
			}
			int num5 = 0;
			foreach (string item in list3)
			{
				string text = ((num5 < list.Count) ? list[num5] : "");
				Stations[item].Value = text;
				if (text.Length > 0)
				{
					num5++;
				}
			}
			Plugin.L.LogInfo((object)((list.Count == 0) ? "Shuffle: no audio files in the music folder." : $"Shuffled {num5} track(s) across {list3.Count} stations."));
		}

		internal static void Tick()
		{
			Safe(TickAction, "Tick");
		}

		private static void TickInner()
		{
			int num;
			if (_reloadVk != 0)
			{
				num = (((GetAsyncKeyState(_reloadVk) & 0x8000) != 0) ? 1 : 0);
				if (num != 0 && !_keyWasDown && Application.isFocused)
				{
					Reload();
				}
			}
			else
			{
				num = 0;
			}
			_keyWasDown = (byte)num != 0;
			if (PendingLoads.Count > 0 || ToDestroy.Count > 0)
			{
				FinishLoads();
			}
			if (Clips.Count != 0 && !(Time.unscaledTime < _nextPoll))
			{
				_nextPoll = Time.unscaledTime + 0.25f;
				Poll();
			}
		}

		private static void Poll()
		{
			Il2CppReferenceArray<Object> val = Object.FindObjectsOfType(Il2CppType.Of<MusicPlayer>());
			if (val == null)
			{
				return;
			}
			ByKey.Clear();
			foreach (Object item in (Il2CppArrayBase<Object>)(object)val)
			{
				if (item == (Object)null)
				{
					continue;
				}
				MusicPlayer val2 = ((Il2CppObjectBase)item).TryCast<MusicPlayer>();
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				MusicGroup musicConfig = val2.MusicConfig;
				string value = null;
				if ((Object)(object)musicConfig != (Object)null)
				{
					GroupToKey.TryGetValue(((Il2CppObjectBase)musicConfig).Pointer, out value);
				}
				if (value == null || !Clips.ContainsKey(value))
				{
					Release(val2);
					continue;
				}
				if (!ByKey.TryGetValue(value, out var value2))
				{
					value2 = new List<MusicPlayer>();
					ByKey[value] = value2;
				}
				value2.Add(val2);
			}
			foreach (KeyValuePair<string, List<MusicPlayer>> item2 in ByKey)
			{
				HandleStation(item2.Key, item2.Value);
			}
		}

		private static void HandleStation(string key, List<MusicPlayer> players)
		{
			if (!Clips.TryGetValue(key, out var value) || (Object)(object)value == (Object)null)
			{
				return;
			}
			Dictionary<IntPtr, List<MusicPlayer>> dictionary = new Dictionary<IntPtr, List<MusicPlayer>>();
			foreach (MusicPlayer player in players)
			{
				IntPtr key2;
				try
				{
					Transform val = (((Object)(object)((Component)player).transform != (Object)null) ? ((Component)player).transform.parent : null);
					key2 = (((Object)(object)val != (Object)null) ? ((Il2CppObjectBase)val).Pointer : ((Il2CppObjectBase)player).Pointer);
				}
				catch
				{
					key2 = ((Il2CppObjectBase)player).Pointer;
				}
				if (!dictionary.TryGetValue(key2, out var value2))
				{
					value2 = (dictionary[key2] = new List<MusicPlayer>());
				}
				value2.Add(player);
			}
			foreach (List<MusicPlayer> value3 in dictionary.Values)
			{
				MusicPlayer val2 = null;
				int num = int.MaxValue;
				foreach (MusicPlayer item in value3)
				{
					int num2;
					try
					{
						num2 = item.Index;
					}
					catch
					{
						num2 = 0;
					}
					if (num2 < num)
					{
						num = num2;
						val2 = item;
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				foreach (MusicPlayer item2 in value3)
				{
					if (((Il2CppObjectBase)item2).Pointer == ((Il2CppObjectBase)val2).Pointer)
					{
						Takeover(item2, key, value);
					}
					else
					{
						Silence(item2, key);
					}
				}
			}
		}

		private static void Takeover(MusicPlayer mp, string key, AudioClip clip)
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			IntPtr pointer = ((Il2CppObjectBase)mp).Pointer;
			AudioSourceController aSC;
			try
			{
				aSC = mp.ASC;
			}
			catch
			{
				return;
			}
			if ((Object)(object)aSC == (Object)null)
			{
				return;
			}
			bool flag2 = default(bool);
			if (Primary.TryGetValue(pointer, out var value))
			{
				if (!aSC.IsPlaying && !aSC.IsHibernating)
				{
					Primary.Remove(pointer);
					return;
				}
				bool flag = ((Il2CppObjectBase)value).Pointer != ((Il2CppObjectBase)clip).Pointer;
				if (!flag)
				{
					AudioClip clip2 = aSC.Clip;
					flag = (Object)(object)clip2 == (Object)null || ((Il2CppObjectBase)clip2).Pointer != ((Il2CppObjectBase)clip).Pointer;
				}
				if (flag)
				{
					Primary[pointer] = clip;
					PlayOurs(mp, clip);
					if (Verbose)
					{
						ManualLogSource l = Plugin.L;
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(key);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] restarted custom track");
						}
						l.LogInfo(val);
					}
				}
				EnsureLoop(mp);
			}
			else if (aSC.IsPlaying)
			{
				Primary[pointer] = clip;
				PlayOurs(mp, clip);
				EnsureLoop(mp);
				ManualLogSource l2 = Plugin.L;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(41, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(key);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] custom track now playing on this radio");
				}
				l2.LogInfo(val);
			}
		}

		private static void Silence(MusicPlayer mp, string key)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			IntPtr pointer = ((Il2CppObjectBase)mp).Pointer;
			if (!Muted.Add(pointer))
			{
				return;
			}
			try
			{
				mp.Stop(0.25f);
			}
			catch (Exception e)
			{
				Report("stop stem", e);
			}
			if (Verbose)
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(key);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] silenced an extra stem");
				}
				l.LogInfo(val);
			}
		}

		private static void Release(MusicPlayer mp)
		{
			IntPtr pointer = ((Il2CppObjectBase)mp).Pointer;
			bool num = Primary.Remove(pointer);
			bool flag = Muted.Remove(pointer);
			if (!num && !flag)
			{
				return;
			}
			try
			{
				AudioSourceController aSC = mp.ASC;
				if ((Object)(object)aSC != (Object)null && !aSC.IsPlaying)
				{
					mp.Play((AudioClip)null);
				}
			}
			catch (Exception e)
			{
				Report("restore original", e);
			}
		}

		private static void PlayOurs(MusicPlayer mp, AudioClip clip)
		{
			if (_inOwnPlay)
			{
				return;
			}
			_inOwnPlay = true;
			try
			{
				mp.Play(clip);
			}
			catch (Exception e)
			{
				Report("play custom clip", e);
			}
			finally
			{
				_inOwnPlay = false;
			}
		}

		private static void EnsureLoop(MusicPlayer mp)
		{
			try
			{
				AudioSourceController aSC = mp.ASC;
				if (!((Object)(object)aSC == (Object)null))
				{
					if (!aSC._loop)
					{
						aSC._loop = true;
					}
					AudioSource audioSource = aSC.AudioSource;
					if ((Object)(object)audioSource != (Object)null && !audioSource.loop)
					{
						audioSource.loop = true;
					}
				}
			}
			catch (Exception e)
			{
				Report("loop", e);
			}
		}

		internal static bool IsOverridden(MusicPlayer mp)
		{
			IntPtr pointer = ((Il2CppObjectBase)mp).Pointer;
			if (!Primary.ContainsKey(pointer))
			{
				return Muted.Contains(pointer);
			}
			return true;
		}

		internal static bool OnPlay(MusicPlayer mp, AudioClip clipOverride)
		{
			IntPtr pointer = ((Il2CppObjectBase)mp).Pointer;
			if (Muted.Contains(pointer))
			{
				return false;
			}
			if (!Primary.TryGetValue(pointer, out var value))
			{
				return true;
			}
			if ((Object)(object)value == (Object)null)
			{
				Primary.Remove(pointer);
				return true;
			}
			if (_inOwnPlay)
			{
				return true;
			}
			if (clipOverride != null && ((Il2CppObjectBase)clipOverride).Pointer == ((Il2CppObjectBase)value).Pointer)
			{
				return true;
			}
			PlayOurs(mp, value);
			EnsureLoop(mp);
			return false;
		}

		internal static void OnManualUpdate(MusicPlayer mp)
		{
			if (Primary.ContainsKey(((Il2CppObjectBase)mp).Pointer))
			{
				EnsureLoop(mp);
			}
		}

		internal static void Forget(MusicPlayer mp)
		{
			IntPtr pointer = ((Il2CppObjectBase)mp).Pointer;
			Primary.Remove(pointer);
			Muted.Remove(pointer);
		}

		internal static void Safe(Action action, string where)
		{
			try
			{
				action();
			}
			catch (Exception e)
			{
				Report(where, e);
			}
		}

		internal static void Report(string where, Exception e)
		{
			string text = $"{where}: {e.GetType().Name}: {e.Message}";
			if (Reported.Add(text))
			{
				Plugin.L.LogError((object)(text + Environment.NewLine + e.StackTrace));
			}
		}
	}
	[HarmonyPatch]
	internal static class RadioManagerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(FmRadioManager), "Initialize")]
		private static void InitializePostfix(FmRadioManager __instance)
		{
			Core.Safe(delegate
			{
				Core.OnManagerInitialized(__instance);
			}, "FmRadioManager.Initialize");
		}
	}
	[HarmonyPatch]
	internal static class MusicPlayerPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(MusicPlayer), "Play")]
		private static bool PlayPrefix(MusicPlayer __instance, AudioClip clipOverride)
		{
			try
			{
				return Core.OnPlay(__instance, clipOverride);
			}
			catch (Exception e)
			{
				Core.Report("MusicPlayer.Play", e);
				return true;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MusicPlayer), "Sync")]
		private static bool SyncPrefix(MusicPlayer __instance)
		{
			return !Core.IsOverridden(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MusicPlayer), "SetSyncPitch")]
		private static bool SetSyncPitchPrefix(MusicPlayer __instance)
		{
			return !Core.IsOverridden(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MusicPlayer), "ManualUpdate")]
		private static void ManualUpdatePostfix(MusicPlayer __instance)
		{
			Core.OnManualUpdate(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MusicPlayer), "OnDestroy")]
		private static void OnDestroyPrefix(MusicPlayer __instance)
		{
			Core.Forget(__instance);
		}
	}
	[BepInPlugin("ArtemisCorp.BigRadio", "BigRadio", "1.0.0")]
	public class Plugin : BasePlugin
	{
		public const string Guid = "ArtemisCorp.BigRadio";

		public const string Name = "BigRadio";

		public const string Version = "1.0.0";

		internal static ManualLogSource L;

		internal static ConfigFile Cfg;

		public override void Load()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			L = ((BasePlugin)this).Log;
			Cfg = ((BasePlugin)this).Config;
			Core.Init();
			Harmony val = new Harmony("ArtemisCorp.BigRadio");
			Type[] array = new Type[2]
			{
				typeof(RadioManagerPatches),
				typeof(MusicPlayerPatches)
			};
			bool flag = default(bool);
			foreach (Type type in array)
			{
				try
				{
					val.PatchAll(type);
				}
				catch (Exception ex)
				{
					ManualLogSource l = L;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(20, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Could not patch ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(type.Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					l.LogWarning(val2);
					L.LogWarning((object)"BigRadio keeps running; some vanilla audio behaviour may not be suppressed.");
				}
			}
			if (!ClassInjector.IsTypeRegisteredInIl2Cpp<RadioDriver>())
			{
				ClassInjector.RegisterTypeInIl2Cpp<RadioDriver>();
			}
			((BasePlugin)this).AddComponent<RadioDriver>();
			ManualLogSource l2 = L;
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(24, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>("BigRadio");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>("1.0.0");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" loaded. Music folder: ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(Core.MusicFolder);
			}
			l2.LogInfo(val3);
		}
	}
	public class RadioDriver : MonoBehaviour
	{
		public RadioDriver(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			Core.Tick();
		}
	}
}