Decompiled source of BetterPeakOST v1.2.0

BetterPeakOST.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BetterPeakOST.Components;
using BetterPeakOST.Configuration;
using BetterPeakOST.Network;
using BetterPeakOST.Patches;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using Zorro.Core;

[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("Adeithe")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("BetterPeakOST")]
[assembly: AssemblyTitle("BetterPeakOST")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BetterPeakOST
{
	[BepInPlugin("Adeithe.Peak.BetterPeakOST", "BetterPeakOST", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ConfigManager Config = new ConfigManager();

		internal static readonly ManualLogSource Logger = Logger.CreateLogSource(Name);

		internal static readonly BepInPlugin Metadata = MetadataHelper.GetMetadata(typeof(Plugin));

		internal static readonly string DirectoryPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		internal static readonly string TemporaryDir = Path.Combine(Application.persistentDataPath, ".tmp");

		private static ConcurrentDictionary<string, object> fileLocks = new ConcurrentDictionary<string, object>();

		private Harmony harmony = new Harmony("Adeithe.Peak.BetterPeakOST");

		public const string Id = "Adeithe.Peak.BetterPeakOST";

		public static string Name => "BetterPeakOST";

		public static string Version => "1.2.0";

		private void Awake()
		{
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			List<Type> list = types.Where((Type t) => t.Namespace == ((object)this).GetType().Namespace + ".Patches" && t.Name.EndsWith("Patch")).ToList();
			list.ForEach((Action<Type>)harmony.PatchAll);
			Logger.LogInfo((object)$"Loaded {((BaseUnityPlugin)this).Info.Metadata.Name} v{((BaseUnityPlugin)this).Info.Metadata.Version}");
		}

		private void OnDestroy()
		{
			try
			{
				Directory.Delete(TemporaryDir, recursive: true);
			}
			catch
			{
			}
		}

		public static bool ShouldExecuteMusicTransition(Vector3 originPos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return ShouldExecuteMusicTransition(Vector3.Distance(originPos, ((Component)Camera.main).transform.position));
		}

		public static bool ShouldExecuteMusicTransition(float distance)
		{
			float value = Config.MusicSyncMaximumDistance.Value;
			if (value <= 0f)
			{
				return Config.SyncMusicTransitions.Value;
			}
			if (Config.SyncMusicTransitions.Value)
			{
				return distance <= value;
			}
			return false;
		}

		internal static T FileLock<T>(string path, Func<T> fn)
		{
			T val = default(T);
			object orAdd = fileLocks.GetOrAdd(path, (string _) => new object());
			lock (orAdd)
			{
				try
				{
					return fn();
				}
				finally
				{
					fileLocks.TryRemove(path, out object _);
				}
			}
		}
	}
}
namespace BetterPeakOST.Patches
{
	[HarmonyPatch(typeof(AmbienceAudio))]
	internal class AmbienceAudioPatch
	{
		internal static bool ShouldResetPriorityMusicTimer;

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		public static void Start_Postfix(AmbienceAudio __instance, ref bool ___playedBeach, ref bool ___playedTropicsOrRoots, ref bool ___playedAlpineOrMesa, ref bool ___playedTomb, ref bool ___playedCaldera, ref bool ___playedKiln, ref bool ___playedPeak)
		{
			MusicManager.SetAmbienceAudio(__instance);
			___playedBeach = true;
			___playedTropicsOrRoots = true;
			___playedAlpineOrMesa = true;
			___playedTomb = true;
			___playedCaldera = true;
			___playedKiln = true;
			___playedPeak = true;
		}

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		public static void Update_Postfix(AmbienceAudio __instance, ref float ___priorityMusicTimer, ref float ___inKiln, ref GameObject ___volcanoObj)
		{
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_00b7: Expected I4, but got Unknown
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: 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_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Invalid comparison between Unknown and I4
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldResetPriorityMusicTimer)
			{
				ShouldResetPriorityMusicTimer = false;
				___priorityMusicTimer = 120f;
			}
			CharacterData component = ((Component)((Component)__instance).transform.root).GetComponent<CharacterData>();
			bool flag = component.sinceDead > 0.5f && !component.passedOut && !component.dead && !component.fullyPassedOut;
			if (!__instance.inTomb && flag && !Character.localCharacter.warping)
			{
				Segment currentSegment = Singleton<MapHandler>.Instance.GetCurrentSegment();
				Vector3 position = ((Component)__instance).transform.position;
				MusicTrack musicTrack = MusicTrack.None;
				float num = position.z + 20f;
				float volume = 0.5f;
				switch ((int)currentSegment)
				{
				case 0:
					volume = 0.5f;
					num = __instance.beachStingerZ;
					if (position.y > 135f)
					{
						musicTrack = MusicTrack.GrabYourBag;
					}
					break;
				case 1:
					volume = 0.5f;
					num = __instance.tropicsStingerZ;
					musicTrack = MusicTrack.Overgrown;
					if (position.y > 405f)
					{
						musicTrack = MusicTrack.IveBeenPoisoned;
					}
					break;
				case 2:
				{
					volume = 0.6f;
					bool flag2 = Singleton<MapHandler>.Instance.BiomeIsPresent((BiomeType)2);
					num = (flag2 ? __instance.alpineStingerZ : 1024f);
					musicTrack = (flag2 ? MusicTrack.SnowSignal : MusicTrack.WeMustGoBack);
					if (flag2 && position.y > 773f)
					{
						musicTrack = MusicTrack.StrugglingToStayWarm;
					}
					break;
				}
				case 3:
					volume = 0.75f;
					num = 1317f;
					musicTrack = MusicTrack.Obsidian;
					if (position.x > -15f && position.x < 20f && position.y > 825f)
					{
						musicTrack = MusicTrack.OnlyWayOutIsUp;
						num = 1695f;
					}
					break;
				case 4:
					volume = 0.6f;
					num = 1800f;
					if (position.y > 1050f && !MusicManager.IsPlaying)
					{
						musicTrack = MusicTrack.Meltdown;
					}
					if (position.y > 1160f)
					{
						musicTrack = MusicTrack.ReachingTheTop;
					}
					break;
				}
				if (musicTrack != 0 && position.z > num && !MusicManager.HasPlayed(musicTrack))
				{
					if ((int)currentSegment == 3 && !Object.op_Implicit((Object)(object)__instance.volcanoObj))
					{
						___volcanoObj = GameObject.Find("VolcanoModel");
					}
					RPCTransitionMusic.Invoke(musicTrack, volume, 2f, 2f, 0f);
					return;
				}
			}
			if (__instance.inTomb)
			{
				if (((Component)__instance).transform.position.z > 730f && !MusicManager.HasPlayed(MusicTrack.ImpossibleReach))
				{
					RPCTransitionMusic.Invoke(MusicTrack.ImpossibleReach, 0.5f, 2f, 2f, 0f);
				}
				else if (((Component)__instance).transform.position.z < 630f && !MusicManager.HasPlayed(MusicTrack.Canopy))
				{
					RPCTransitionMusic.Invoke(MusicTrack.Canopy, 0.5f, 2f, 2f, 0f);
				}
			}
		}
	}
	[HarmonyPatch(typeof(GUIManager))]
	internal class GUIManagerPatch
	{
		[HarmonyPatch("TheLavaRises")]
		[HarmonyPostfix]
		public static void TheLavaRises_Postfix()
		{
			if (!PhotonNetwork.InRoom || NetworkSync.GetAuthorityActorNumber() == PhotonNetwork.LocalPlayer.ActorNumber)
			{
				RPCTransitionMusic.Invoke(MusicTrack.RunFastOrBurnTrying, 0.4f, 2f, 0f, 0f);
			}
		}
	}
	[HarmonyPatch(typeof(ItemSlot))]
	internal class ItemSlotPatch
	{
		[HarmonyPatch("SetItem")]
		[HarmonyPostfix]
		public static void SetItem_Postfix(Item itemPrefab)
		{
			if (itemPrefab.itemID == 13)
			{
				RPCTransitionMusic.Invoke(MusicTrack.BingBong, 0.35f, 3f, 3f, 17f);
			}
		}
	}
	[HarmonyPatch(typeof(Lava))]
	internal class LavaPatch
	{
		private static MusicTrack track = MusicTrack.CookingEggsOnHotRocks;

		[HarmonyPatch("TryCookItems")]
		[HarmonyPostfix]
		public static void TryCookItems_Postfix(Lava __instance, List<Item> ___itemToCookList)
		{
			if (!NetworkSync.IsAuthorizedPlayer() || MusicManager.HasPlayed(track))
			{
				return;
			}
			foreach (Item ___itemToCook in ___itemToCookList)
			{
				if (!((Object)(object)___itemToCook == (Object)null) && (___itemToCook.itemID == 26 || ___itemToCook.itemID == 57) && ((Component)___itemToCook).GetComponent<ItemCooking>().timesCookedLocal == 1)
				{
					RPCTransitionMusic.Invoke(track, 0.6f, 2f, 1f, 0f);
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(MainMenu))]
	internal class MainMenuPatch
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass1_0
		{
			public Task<string> task;

			internal bool <LoadMusic>b__0()
			{
				return task.IsCompleted;
			}
		}

		[CompilerGenerated]
		private sealed class <LoadMusic>d__1 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public MusicTrack track;

			private <>c__DisplayClass1_0 <>8__1;

			public AudioSource source;

			private string <filePath>5__2;

			private UnityWebRequest <www>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadMusic>d__1(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<filePath>5__2 = null;
				<www>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Expected O, but got Unknown
				//IL_0147: Unknown result type (might be due to invalid IL or missing references)
				//IL_014d: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass1_0();
						<>8__1.task = MusicManager.DecodeMusicFile(track);
						<>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.task.IsCompleted));
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -1;
						if (<>8__1.task.IsFaulted)
						{
							Debug.LogException((Exception)<>8__1.task.Exception);
						}
						if (<>8__1.task.IsFaulted || <>8__1.task.IsCanceled)
						{
							result = false;
							break;
						}
						<filePath>5__2 = <>8__1.task.Result;
						if (string.IsNullOrWhiteSpace(<filePath>5__2))
						{
							result = false;
							break;
						}
						<www>5__3 = UnityWebRequestMultimedia.GetAudioClip("file://" + <filePath>5__2, (AudioType)14);
						<>1__state = -3;
						<>2__current = <www>5__3.SendWebRequest();
						<>1__state = 2;
						result = true;
						break;
					case 2:
					{
						<>1__state = -3;
						if ((int)<www>5__3.result != 1)
						{
							Plugin.Logger.LogWarning((object)("Failed to load audio clip from path \"" + <filePath>5__2 + "\": " + <www>5__3.error));
							result = false;
							<>m__Finally1();
							break;
						}
						AudioClip content = DownloadHandlerAudioClip.GetContent(<www>5__3);
						((Object)content).name = $"{track}";
						source.clip = content;
						source.mute = false;
						if (!source.isPlaying)
						{
							source.Play();
						}
						<>m__Finally1();
						<www>5__3 = null;
						result = false;
						break;
					}
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<www>5__3 != null)
				{
					((IDisposable)<www>5__3).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void Start_Postfix(MainMenu __instance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).name != "Title")
			{
				return;
			}
			DateTime dateTime = Plugin.Config.NextIslandAt.Subtract(TimeSpan.FromHours(24.0));
			MusicTrack musicTrack = ((Plugin.Config.LastExpeditionAt >= dateTime) ? MusicTrack.WhereItAllBegins : MusicTrack.ANewDay);
			Plugin.Logger.LogInfo((object)$"Attempting to set custom Main Menu music to {musicTrack}...");
			GameObject val = GameObject.Find("Title Music");
			AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource val2 in componentsInChildren)
			{
				if ((Object)(object)val2.clip == (Object)null || string.IsNullOrEmpty(((Object)val2.clip).name))
				{
					continue;
				}
				string name = ((Object)val2.clip).name;
				if (name.Contains("Music Title") || (name.StartsWith("Music") && name.EndsWith("Stinger")))
				{
					val2.mute = true;
					if (!((Object)((Component)val2).gameObject).name.Contains("Mesa") || !((Object)val2.clip).name.Contains("Riser"))
					{
						((MonoBehaviour)__instance).StartCoroutine(LoadMusic(val2, musicTrack));
					}
				}
			}
		}

		[IteratorStateMachine(typeof(<LoadMusic>d__1))]
		private static IEnumerator LoadMusic(AudioSource source, MusicTrack track)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadMusic>d__1(0)
			{
				source = source,
				track = track
			};
		}
	}
	[HarmonyPatch(typeof(MyresAmbience))]
	internal class MyresAmbiencePatch
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass3_0
		{
			public Task<string> task;

			internal bool <LoadFearMusic>b__0()
			{
				return task.IsCompleted;
			}
		}

		[CompilerGenerated]
		private sealed class <LoadFearMusic>d__3 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private <>c__DisplayClass3_0 <>8__1;

			public AudioSource source;

			private string <filePath>5__2;

			private UnityWebRequest <www>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadFearMusic>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<filePath>5__2 = null;
				<www>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Expected O, but got Unknown
				//IL_0152: Unknown result type (might be due to invalid IL or missing references)
				//IL_0158: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass3_0();
						<>8__1.task = MusicManager.DecodeMusicFile(MusicTrack.SomethingLurksInTheShadows);
						<>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.task.IsCompleted));
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -1;
						if (<>8__1.task.IsFaulted)
						{
							Debug.LogException((Exception)<>8__1.task.Exception);
						}
						if (<>8__1.task.IsCanceled || <>8__1.task.IsFaulted)
						{
							result = false;
							break;
						}
						<filePath>5__2 = <>8__1.task.Result;
						if (string.IsNullOrWhiteSpace(<filePath>5__2))
						{
							Plugin.Logger.LogWarning((object)"Failed to set Scoutmaster Myers fear music due to a missing audio file path. The default will be used instead...");
							result = false;
							break;
						}
						<www>5__3 = UnityWebRequestMultimedia.GetAudioClip("file://" + <filePath>5__2, (AudioType)14);
						<>1__state = -3;
						<>2__current = <www>5__3.SendWebRequest();
						<>1__state = 2;
						result = true;
						break;
					case 2:
						<>1__state = -3;
						if ((int)<www>5__3.result != 1)
						{
							Plugin.Logger.LogWarning((object)("Failed to load audio clip from path \"" + <filePath>5__2 + "\": " + <www>5__3.error));
							result = false;
							<>m__Finally1();
							break;
						}
						audioClip = DownloadHandlerAudioClip.GetContent(<www>5__3);
						((Object)audioClip).name = MusicTrack.SomethingLurksInTheShadows.ToString();
						source.clip = audioClip;
						Plugin.Logger.LogInfo((object)"Scoutmaster Myers fear music set!");
						<>m__Finally1();
						<www>5__3 = null;
						isLoading = false;
						result = false;
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<www>5__3 != null)
				{
					((IDisposable)<www>5__3).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static AudioClip? audioClip;

		private static bool isLoading;

		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		public static void Update_Prefix(MyresAmbience __instance)
		{
			if (!Object.op_Implicit((Object)(object)__instance.anim))
			{
				return;
			}
			AudioSource fearMusic = __instance.fearMusic;
			if (!isLoading && ((Object)fearMusic.clip).name != MusicTrack.SomethingLurksInTheShadows.ToString())
			{
				isLoading = true;
				((MonoBehaviour)__instance).StartCoroutine(LoadFearMusic(__instance.fearMusic));
			}
			if (fearMusic.isPlaying && __instance.anim.GetFloat("Myers Distance") < 64f)
			{
				if (fearMusic.time < 62.9f)
				{
					fearMusic.time = 63f;
				}
				if (MusicManager.IsPlaying)
				{
					MusicManager.Pause();
				}
			}
		}

		[IteratorStateMachine(typeof(<LoadFearMusic>d__3))]
		private static IEnumerator LoadFearMusic(AudioSource source)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadFearMusic>d__3(0)
			{
				source = source
			};
		}
	}
	[HarmonyPatch(typeof(NetworkConnector))]
	internal class NetworkConnectorPatch
	{
		[HarmonyPatch("OnJoinedRoom")]
		[HarmonyPostfix]
		public static void OnJoinedRoom_Postfix()
		{
			NetworkSync.Ensure();
		}

		[HarmonyPatch("OnLeftRoom")]
		[HarmonyPostfix]
		public static void OnLeftRoom_Postfix()
		{
			NetworkSync? instance = NetworkSync.Instance;
			if (instance == null || instance.TryCleanup())
			{
				Plugin.Logger.LogInfo((object)"Cleaned up NetworkSync instance");
			}
		}
	}
	[HarmonyPatch(typeof(NextLevelService))]
	internal class NextLevelServicePatch
	{
		[HarmonyPatch("NewData")]
		[HarmonyPostfix]
		public static void NewData_Postfix(NextLevelService __instance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			NextLevelData value = __instance.Data.Value;
			int secondsLeft = ((NextLevelData)(ref value)).SecondsLeft;
			Plugin.Config.NextIslandAt = DateTime.UtcNow.AddSeconds(secondsLeft);
		}
	}
	[HarmonyPatch(typeof(PeakHandler))]
	internal class PeakHandlerPatch
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass4_0
		{
			public Task<string> task;

			internal bool <LoadEndCreditsMusic>b__0()
			{
				return task.IsCompleted;
			}
		}

		[CompilerGenerated]
		private sealed class <LoadEndCreditsMusic>d__4 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public MusicTrack track;

			private <>c__DisplayClass4_0 <>8__1;

			public AudioSource source;

			private string <filePath>5__2;

			private UnityWebRequest <www>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadEndCreditsMusic>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<filePath>5__2 = null;
				<www>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Expected O, but got Unknown
				//IL_0162: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass4_0();
						<>8__1.task = MusicManager.DecodeMusicFile(track);
						<>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.task.IsCompleted));
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -1;
						if (<>8__1.task.IsFaulted)
						{
							Debug.LogException((Exception)<>8__1.task.Exception);
						}
						if (<>8__1.task.IsCanceled || <>8__1.task.IsFaulted)
						{
							result = false;
							break;
						}
						<filePath>5__2 = <>8__1.task.Result;
						if (string.IsNullOrWhiteSpace(<filePath>5__2))
						{
							Plugin.Logger.LogWarning((object)"Failed to set End Credits music due to a missing audio file path. The default will be used instead...");
							result = false;
							break;
						}
						source.mute = true;
						<www>5__3 = UnityWebRequestMultimedia.GetAudioClip("file://" + <filePath>5__2, (AudioType)14);
						<>1__state = -3;
						<>2__current = <www>5__3.SendWebRequest();
						<>1__state = 2;
						result = true;
						break;
					case 2:
						<>1__state = -3;
						if ((int)<www>5__3.result != 1)
						{
							Plugin.Logger.LogWarning((object)("Failed to load audio clip from path \"" + <filePath>5__2 + "\": " + <www>5__3.error));
							result = false;
							<>m__Finally1();
							break;
						}
						audioClip = DownloadHandlerAudioClip.GetContent(<www>5__3);
						((Object)audioClip).name = $"{track}";
						source.clip = audioClip;
						source.mute = false;
						Plugin.Logger.LogInfo((object)"End Credits music set!");
						source.Play();
						<>m__Finally1();
						<www>5__3 = null;
						isLoading = false;
						result = false;
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<www>5__3 != null)
				{
					((IDisposable)<www>5__3).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const string targetObj = "Map/Biome_4/Volcano/Peak/CutsceneEndingSpot/Cutscene Ending/Helicopter_End/SFX/Music 2";

		private static AudioClip? audioClip;

		private static bool isLoading;

		[HarmonyPatch("EndScreenComplete")]
		[HarmonyPrefix]
		public static void EndScreenComplete_Prefix(PeakHandler __instance)
		{
			GameObject val = GameObject.Find("Map/Biome_4/Volcano/Peak/CutsceneEndingSpot/Cutscene Ending/Helicopter_End/SFX/Music 2");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"Failed to find the End Credits music object! The Peak ending music will not be changed.");
				return;
			}
			bool won = Character.localCharacter.refs.stats.won;
			bool flag = !Character.localCharacter.refs.stats.won && Character.localCharacter.refs.stats.somebodyElseWon;
			if (won || flag)
			{
				MusicTrack track = MusicTrack.Whiteout;
				if (won)
				{
					track = MusicTrack.Ascent;
				}
				if (!isLoading)
				{
					AudioSource component = val.GetComponent<AudioSource>();
					((MonoBehaviour)__instance).StartCoroutine(LoadEndCreditsMusic(component, track));
					isLoading = true;
				}
			}
		}

		[IteratorStateMachine(typeof(<LoadEndCreditsMusic>d__4))]
		private static IEnumerator LoadEndCreditsMusic(AudioSource source, MusicTrack track)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadEndCreditsMusic>d__4(0)
			{
				source = source,
				track = track
			};
		}
	}
	[HarmonyPatch(typeof(RunManager))]
	internal class RunManagerPatch
	{
		[HarmonyPatch("StartRun")]
		[HarmonyPostfix]
		public static void StartRun_Postfix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (!(((Scene)(ref activeScene)).name == "Airport"))
			{
				Plugin.Config.LastExpeditionAt = DateTime.UtcNow;
				MusicManager.Reset();
			}
		}
	}
}
namespace BetterPeakOST.Network
{
	public sealed class NetworkSync
	{
		internal const string k_VID = "BetterPeakOST_Sync_ViewID";

		internal const string k_OWNER = "BetterPeakOST_Sync_Owner";

		private GameObject gameObject;

		private PhotonView photonView;

		private PhotonRoomEventListener listener;

		public static NetworkSync? Instance { get; private set; }

		public int ViewID => photonView.ViewID;

		private NetworkSync(GameObject gameObject)
		{
			this.gameObject = gameObject;
			photonView = gameObject.AddComponent<PhotonView>();
			listener = gameObject.AddComponent<PhotonRoomEventListener>();
			AddReceiver<RPCTransitionMusic>();
			Plugin.Logger.LogInfo((object)"NetworkSync initialized.");
		}

		public void AddReceiver<T>() where T : MonoBehaviourPun
		{
			if (!((Object)(object)gameObject.GetComponent<T>() != (Object)null))
			{
				gameObject.AddComponent<T>();
			}
		}

		internal bool TryCleanup()
		{
			if (PhotonNetwork.InRoom)
			{
				return false;
			}
			listener.cachedOwner = -1;
			photonView.ViewID = 0;
			return ViewID == 0;
		}

		public static bool WasSentByAuthorizedPlayer(PhotonMessageInfo info)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			int authorityActorNumber = GetAuthorityActorNumber();
			if (authorityActorNumber >= 0)
			{
				return info.Sender.ActorNumber == authorityActorNumber;
			}
			return true;
		}

		public static bool WasSentByLocalPlayer(PhotonMessageInfo info)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return info.Sender.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber;
		}

		public static bool IsAuthorizedPlayer()
		{
			if (!PhotonNetwork.InRoom)
			{
				return true;
			}
			int authorityActorNumber = GetAuthorityActorNumber();
			if (authorityActorNumber >= 0)
			{
				return authorityActorNumber == PhotonNetwork.LocalPlayer.ActorNumber;
			}
			return true;
		}

		public static int GetAuthorityActorNumber()
		{
			if (!PhotonNetwork.InRoom)
			{
				return -1;
			}
			NetworkSync? instance = Instance;
			if (instance != null && instance.listener.cachedOwner >= 0)
			{
				return Instance.listener.cachedOwner;
			}
			if (!((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"BetterPeakOST_Sync_Owner", out object value))
			{
				return PhotonNetwork.LocalPlayer.ActorNumber;
			}
			if (value == null)
			{
				return -1;
			}
			return (int)value;
		}

		public static Player? GetConnectedPlayer(int actorNumber)
		{
			if (!PhotonNetwork.InRoom)
			{
				return null;
			}
			if (!PhotonNetwork.CurrentRoom.Players.TryGetValue(actorNumber, out var value) || !value.IsInactive)
			{
				return null;
			}
			return value;
		}

		public static void Send(string methodName, Player player, params object[] parameters)
		{
			if (PhotonNetwork.InRoom)
			{
				NetworkSync? instance = Instance;
				if (instance != null)
				{
					instance.photonView.RPC(methodName, player, parameters);
				}
			}
		}

		public static void Send(string methodName, RpcTarget target, params object[] parameters)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.InRoom)
			{
				NetworkSync? instance = Instance;
				if (instance != null)
				{
					instance.photonView.RPC(methodName, target, parameters);
				}
			}
		}

		public static int GetAssignedViewID(int maxAttempts = 3)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_0092: Expected O, but got Unknown
			//IL_0092: Expected O, but got Unknown
			if (!PhotonNetwork.InRoom)
			{
				return 0;
			}
			if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"BetterPeakOST_Sync_ViewID", out object value))
			{
				Plugin.Logger.LogInfo((object)$"Fetched existing ViewID {value} for NetworkSync");
				return (int)value;
			}
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			int num = PhotonNetwork.AllocateViewID(actorNumber);
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"BetterPeakOST_Sync_ViewID", (object)num);
			((Dictionary<object, object>)val).Add((object)"BetterPeakOST_Sync_Owner", (object)actorNumber);
			Hashtable val2 = new Hashtable();
			((Dictionary<object, object>)val2).Add((object)"BetterPeakOST_Sync_ViewID", (object)null);
			if (!currentRoom.SetCustomProperties(val, val2, (WebFlags)null))
			{
				if (maxAttempts < 1)
				{
					return -1;
				}
				return GetAssignedViewID(maxAttempts - 1);
			}
			Send("RPC_RoomUpdate", (RpcTarget)5, "BetterPeakOST_Sync_ViewID", num);
			Plugin.Logger.LogInfo((object)$"PhotonNetwork assigned ViewID {num} to NetworkSync (Owner: {actorNumber})");
			return num;
		}

		public static NetworkSync? Ensure()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			int assignedViewID = GetAssignedViewID();
			if (assignedViewID < 0)
			{
				return null;
			}
			NetworkSync? instance = Instance;
			if (instance != null && instance.ViewID == assignedViewID)
			{
				return Instance;
			}
			if (Instance == null)
			{
				GameObject val = new GameObject("BetterPeakOST_NetworkSync");
				Object.DontDestroyOnLoad((Object)(object)val);
				Instance = new NetworkSync(val);
			}
			PhotonView val2 = Instance.photonView;
			if (val2.ViewID == assignedViewID)
			{
				return Instance;
			}
			if (val2.ViewID != 0)
			{
				val2.ViewID = 0;
			}
			val2.ViewID = assignedViewID;
			Plugin.Logger.LogInfo((object)$"NetworkSync is now using ViewID {assignedViewID}");
			return Instance;
		}
	}
	internal sealed class RPCTransitionMusic : MonoBehaviourPun
	{
		private static readonly int MinMinutesBetweenSameTrack = 15;

		private const string m_Request = "RPC_TransitionMusicRequest";

		private const string m_Call = "RPC_TransitionMusic";

		public static void Invoke(MusicTrack track, float volume, float fadeOutTime, float fadeInTime, float timestamp)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if (MusicManager.LastPlayed(track) > DateTime.Now.AddMinutes(-MinMinutesBetweenSameTrack))
			{
				return;
			}
			if (!PhotonNetwork.InRoom || PhotonNetwork.OfflineMode || PhotonNetwork.CurrentRoom.PlayerCount == 1)
			{
				MusicManager.PlayTrack(track, volume, fadeOutTime, fadeInTime, timestamp);
				return;
			}
			Vector3 position = ((Component)Camera.main).transform.position;
			int authorityActorNumber = NetworkSync.GetAuthorityActorNumber();
			if (authorityActorNumber < 0 || PhotonNetwork.LocalPlayer.ActorNumber == authorityActorNumber)
			{
				NetworkSync.Send("RPC_TransitionMusic", (RpcTarget)5, position, track, volume, fadeOutTime, fadeInTime, timestamp);
			}
			else
			{
				Player player = PhotonNetwork.CurrentRoom.GetPlayer(authorityActorNumber, false);
				NetworkSync.Send("RPC_TransitionMusicRequest", player, position, track, volume, fadeOutTime, fadeInTime, timestamp);
			}
		}

		[PunRPC]
		public void RPC_TransitionMusicRequest(Vector3 pos, MusicTrack track, float volume, float fadeOutTime, float fadeInTime, float timestamp, PhotonMessageInfo info)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.InRoom && NetworkSync.GetAuthorityActorNumber() == PhotonNetwork.LocalPlayer.ActorNumber)
			{
				if (volume < 0f || volume > 1f)
				{
					Plugin.Logger.LogWarning((object)string.Format("RPC: {0} from player \"{1}\" (Actor #{2}) with unexpected volume. Rejecting...", "RPC_TransitionMusicRequest", info.Sender.NickName, info.Sender.ActorNumber));
					return;
				}
				if (MusicManager.LastPlayed(track) > DateTime.Now.AddMinutes(-MinMinutesBetweenSameTrack))
				{
					Plugin.Logger.LogWarning((object)$"RPC: Player \"{info.Sender.NickName}\" (Actor #{info.Sender.ActorNumber}) requested \"{track}\" to be played again too fast. Rejecting...");
					return;
				}
				NetworkSync.Send("RPC_TransitionMusic", (RpcTarget)5, pos, track, volume, fadeOutTime, fadeInTime, timestamp);
			}
		}

		[PunRPC]
		public void RPC_TransitionMusic(Vector3 originPos, MusicTrack track, float volume, float fadeOutTime, float fadeInTime, float timestamp, PhotonMessageInfo info)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkSync.WasSentByAuthorizedPlayer(info))
			{
				return;
			}
			if (volume < 0f || volume > 1f)
			{
				Plugin.Logger.LogWarning((object)string.Format("RPC: {0} from player \"{1}\" (Actor #{2}) with unexpected volume. Ignoring...", "RPC_TransitionMusic", info.Sender.NickName, info.Sender.ActorNumber));
				return;
			}
			float distance = Vector3.Distance(originPos, ((Component)Camera.main).transform.position);
			if (Plugin.ShouldExecuteMusicTransition(distance))
			{
				MusicManager.PlayTrack(track, volume, fadeOutTime, fadeInTime, timestamp);
			}
		}
	}
}
namespace BetterPeakOST.Configuration
{
	public sealed class ConfigManager
	{
		private const string InternalNotice = "⚠ INTERNAL - Do not modify unless you have technical knowledge.\n";

		private ConfigFile Config = new ConfigFile(Path.Combine(Paths.ConfigPath, "Adeithe-BetterPeakOST.cfg"), true, Plugin.Metadata);

		private ConfigFile PersistentConfig = new ConfigFile(Path.Combine(Application.persistentDataPath, "Adeithe-BetterPeakOST-Persistent.cfg"), false, Plugin.Metadata);

		private ConfigEntry<long> lastPlayed;

		private ConfigEntry<long> nextIsland;

		public ConfigEntry<bool> SyncMusicTransitions;

		public ConfigEntry<float> MusicSyncMaximumDistance;

		public DateTime LastExpeditionAt
		{
			get
			{
				return DateTimeOffset.FromUnixTimeSeconds(lastPlayed.Value).DateTime;
			}
			set
			{
				lastPlayed.Value = new DateTimeOffset(value).ToUnixTimeSeconds();
			}
		}

		public DateTime NextIslandAt
		{
			get
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				DateTime utcNow = DateTime.UtcNow;
				NextLevelData value = GameHandler.GetService<NextLevelService>().Data.Value;
				int secondsLeft = ((NextLevelData)(ref value)).SecondsLeft;
				if (secondsLeft > 0)
				{
					return utcNow.AddSeconds(secondsLeft);
				}
				if (nextIsland.Value <= 0)
				{
					DateTime result = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, 17, 0, 1, DateTimeKind.Utc);
					if (utcNow.Hour > 17 || (utcNow.Hour == 17 && utcNow.Minute * 60 + utcNow.Second >= 1))
					{
						return result.AddDays(1.0);
					}
					return result;
				}
				return DateTimeOffset.FromUnixTimeSeconds(nextIsland.Value).DateTime;
			}
			set
			{
				nextIsland.Value = new DateTimeOffset(value).ToUnixTimeSeconds();
			}
		}

		internal ConfigManager()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			SyncMusicTransitions = Config.Bind<bool>("Network", "SyncMusicTransitions", true, "If enabled, music transitions will be synchronized with the other scouts regardless this setting on their end.");
			MusicSyncMaximumDistance = Config.Bind<float>("Network", "MusicSyncMaximumDistance", 75f, "The maximum distance a scout can be for a synchronized music transition to execute. Scouts further than this distance will not cause your music to be changed (0 to disable)");
			PersistentConfig.SaveOnConfigSet = true;
			lastPlayed = PersistentConfig.Bind<long>("Persistent", "LastExpeditionEpoch", 0L, new ConfigDescription("⚠ INTERNAL - Do not modify unless you have technical knowledge.\nThe epoch timestamp in seconds since the last time the player began an expedition.", (AcceptableValueBase)(object)new AcceptableValueRange<long>(0L, long.MaxValue), Array.Empty<object>()));
			nextIsland = PersistentConfig.Bind<long>("Persistent", "NextIslandEpoch", 0L, new ConfigDescription("⚠ INTERNAL - Do not modify unless you have technical knowledge.\nThe epoch timestamp in seconds until the next island is available to play.", (AcceptableValueBase)(object)new AcceptableValueRange<long>(0L, long.MaxValue), Array.Empty<object>()));
		}

		public void Reload()
		{
			Config.Reload();
			PersistentConfig.Reload();
		}
	}
}
namespace BetterPeakOST.Components
{
	internal class MusicDecoder
	{
		internal const int HeaderSize = 64;

		internal const string Magic = "PMOD";

		internal const byte Version = 1;

		public static void Decode(Stream input, Stream output)
		{
			var (key, iv) = ReadHeader(input);
			using MemoryStream memoryStream = new MemoryStream();
			Decrypt(key, iv, input, memoryStream);
			Decompress(memoryStream, output);
		}

		private static (byte[] key, byte[] iv) ReadHeader(Stream stream)
		{
			byte[] array = new byte["PMOD".Length];
			stream.Read(array);
			byte b = (byte)stream.ReadByte();
			if (Encoding.UTF8.GetString(array) != "PMOD")
			{
				throw new InvalidDataException("Stream data does not match required format");
			}
			if (b != 1)
			{
				throw new InvalidDataException($"Unsupported version {b} in header");
			}
			byte[] array2 = new byte[32];
			byte[] array3 = new byte[16];
			stream.Read(array2);
			stream.Read(array3);
			int num = 64 - (array2.Length + array3.Length + array.Length + 1);
			stream.Position += num;
			return (array2, array3);
		}

		private static void Decompress(Stream input, Stream output)
		{
			using BrotliStream brotliStream = new BrotliStream(input, CompressionMode.Decompress);
			brotliStream.CopyTo(output);
			output.Position = 0L;
		}

		private static void Decrypt(byte[] key, byte[] iv, Stream input, Stream output)
		{
			using Aes aes = Aes.Create();
			aes.KeySize = 256;
			aes.Key = key;
			aes.IV = iv;
			aes.Mode = CipherMode.CBC;
			aes.Padding = PaddingMode.PKCS7;
			using CryptoStream cryptoStream = new CryptoStream(input, aes.CreateDecryptor(), CryptoStreamMode.Read);
			cryptoStream.CopyTo(output);
			output.Position = 0L;
		}
	}
	internal sealed class MusicManager
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass16_0
		{
			public Task<string> task;

			internal bool <LoadAndPlayAudioClip>b__0()
			{
				return task.IsCompleted;
			}
		}

		[CompilerGenerated]
		private sealed class <FadeAudio>d__17 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AudioSource source;

			public float targetVolume;

			public float duration;

			private float <elapsed>5__2;

			private float <start>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FadeAudio>d__17(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<elapsed>5__2 = 0f;
					<start>5__3 = source.volume;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (<elapsed>5__2 < duration)
				{
					<elapsed>5__2 += Time.unscaledDeltaTime;
					source.volume = Mathf.Lerp(<start>5__3, targetVolume, Mathf.Clamp01(<elapsed>5__2 / duration));
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				source.volume = targetVolume;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadAndPlayAudioClip>d__16 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public MusicTrack track;

			private <>c__DisplayClass16_0 <>8__1;

			public float volume;

			public AudioSource source;

			public float fadeOutTime;

			public float timestamp;

			public float fadeInTime;

			private DateTime <start>5__2;

			private string <filePath>5__3;

			private UnityWebRequest <req>5__4;

			private AudioClip <clip>5__5;

			private TimeSpan <loadTime>5__6;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadAndPlayAudioClip>d__16(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 2) <= 2u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<filePath>5__3 = null;
				<req>5__4 = null;
				<clip>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Expected O, but got Unknown
				//IL_018a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0190: Invalid comparison between Unknown and I4
				//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
				bool result;
				try
				{
					AudioSource obj;
					AudioClip clip;
					float num;
					switch (<>1__state)
					{
					default:
						result = false;
						goto end_IL_0000;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass16_0();
						<start>5__2 = DateTime.Now;
						<>8__1.task = DecodeMusicFile(track);
						<>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.task.IsCompleted));
						<>1__state = 1;
						result = true;
						goto end_IL_0000;
					case 1:
						<>1__state = -1;
						if (<>8__1.task.IsFaulted)
						{
							Debug.LogException((Exception)<>8__1.task.Exception);
						}
						if (<>8__1.task.IsCanceled || <>8__1.task.IsFaulted)
						{
							result = false;
						}
						else
						{
							<filePath>5__3 = <>8__1.task.Result;
							if (string.IsNullOrWhiteSpace(<filePath>5__3))
							{
								Plugin.Logger.LogWarning((object)$"Failed to determine file path for music track \"{track}\"...");
								result = false;
							}
							else
							{
								volume = Mathf.Clamp01(volume);
								<req>5__4 = UnityWebRequestMultimedia.GetAudioClip("file://" + <filePath>5__3, (AudioType)14);
								<>1__state = -3;
								<>2__current = <req>5__4.SendWebRequest();
								<>1__state = 2;
								result = true;
							}
						}
						goto end_IL_0000;
					case 2:
						<>1__state = -3;
						if ((int)<req>5__4.result != 1)
						{
							Plugin.Logger.LogWarning((object)$"Failed to load audio clip from \"{<filePath>5__3}\". Skipping playback... (Result: {<req>5__4.result})");
							currentCoroutine = null;
							result = false;
							break;
						}
						<clip>5__5 = DownloadHandlerAudioClip.GetContent(<req>5__4);
						if ((Object)(object)<clip>5__5 == (Object)null)
						{
							Plugin.Logger.LogWarning((object)("Failed to load audio clip from \"" + <filePath>5__3 + "\". Skipping playback..."));
							currentCoroutine = null;
							result = false;
							break;
						}
						<loadTime>5__6 = DateTime.Now - <start>5__2;
						if (!source.isPlaying || !(fadeOutTime > 0f))
						{
							goto IL_0276;
						}
						<>2__current = FadeAudio(source, fadeOutTime);
						<>1__state = 3;
						result = true;
						goto end_IL_0000;
					case 3:
						<>1__state = -3;
						goto IL_0276;
					case 4:
						{
							<>1__state = -3;
							Plugin.Logger.LogInfo((object)$"Started playback for \"{track}\" (Took: {<loadTime>5__6.TotalMilliseconds}ms)");
							<clip>5__5 = null;
							<>m__Finally1();
							<req>5__4 = null;
							currentCoroutine = null;
							result = false;
							goto end_IL_0000;
						}
						IL_0276:
						((Object)<clip>5__5).name = $"{track}";
						obj = source;
						clip = <clip>5__5;
						num = timestamp;
						OverrideAudioClip(obj, clip, null, num).Play();
						history.Add(track, DateTime.Now);
						AmbienceAudioPatch.ShouldResetPriorityMusicTimer = true;
						<>2__current = FadeAudio(source, fadeInTime, volume);
						<>1__state = 4;
						result = true;
						goto end_IL_0000;
					}
					<>m__Finally1();
					end_IL_0000:;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__4 != null)
				{
					((IDisposable)<req>5__4).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static readonly string DirectoryPath = Path.Combine(Plugin.DirectoryPath, "music");

		private static Dictionary<MusicTrack, DateTime> history = new Dictionary<MusicTrack, DateTime>();

		private static AmbienceAudio? Ambience;

		private static Coroutine? currentCoroutine;

		private static MusicTrack? lastPlayed;

		public static bool IsReady
		{
			get
			{
				if ((Object)(object)Ambience != (Object)null)
				{
					return (Object)(object)Ambience.mainMusic != (Object)null;
				}
				return false;
			}
		}

		public static bool IsPlaying
		{
			get
			{
				if (IsReady)
				{
					AmbienceAudio? ambience = Ambience;
					bool? obj;
					if (ambience == null)
					{
						obj = null;
					}
					else
					{
						AudioSource mainMusic = ambience.mainMusic;
						obj = ((mainMusic != null) ? new bool?(mainMusic.isPlaying) : null);
					}
					bool? flag = obj;
					return flag.GetValueOrDefault();
				}
				return false;
			}
		}

		internal static void SetAmbienceAudio(AmbienceAudio component)
		{
			if ((Object)(object)Ambience != (Object)null && history.Count > 0)
			{
				StopCurrentCoroutine();
				Ambience.mainMusic.Stop();
			}
			Ambience = component;
		}

		public static void Pause()
		{
			if (!((Object)(object)Ambience == (Object)null) && !((Object)(object)Ambience.mainMusic == (Object)null) && Ambience.mainMusic.isPlaying)
			{
				Ambience.mainMusic.Pause();
			}
		}

		public static void PlayTrack(MusicTrack track, float volume, float fadeOutTime, float fadeInTime, float timestamp)
		{
			if ((Object)(object)Ambience == (Object)null || (Object)(object)Ambience.mainMusic == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"AmbienceAudio has not been set. Skipping playback...");
			}
			else if (track != lastPlayed)
			{
				lastPlayed = track;
				StopCurrentCoroutine();
				currentCoroutine = ((MonoBehaviour)Ambience).StartCoroutine(LoadAndPlayAudioClip(Ambience.mainMusic, track, volume, fadeOutTime, fadeInTime, timestamp));
			}
		}

		public static DateTime LastPlayed(MusicTrack track)
		{
			if (!history.TryGetValue(track, out var value))
			{
				return DateTime.MinValue;
			}
			return value;
		}

		public static bool HasPlayed(MusicTrack track)
		{
			return history.ContainsKey(track);
		}

		public static void Reset()
		{
			history.Clear();
			lastPlayed = null;
			StopCurrentCoroutine();
		}

		public static string GetEncodedFilePath(MusicTrack track)
		{
			string description = track.GetDescription();
			if (description == null)
			{
				Plugin.Logger.LogWarning((object)$"Failed to determine filename for music track \"{track}\"...");
				return string.Empty;
			}
			Uri uri = new Uri(Path.Combine(DirectoryPath, description + ".enc"));
			if (File.Exists(Path.Combine(Plugin.DirectoryPath, description + ".enc")))
			{
				uri = new Uri(Path.Combine(Plugin.DirectoryPath, description + ".enc"));
			}
			return uri.AbsolutePath.Replace("\\", "/");
		}

		[IteratorStateMachine(typeof(<LoadAndPlayAudioClip>d__16))]
		public static IEnumerator LoadAndPlayAudioClip(AudioSource source, MusicTrack track, float volume = 0.5f, float fadeOutTime = 0f, float fadeInTime = 0f, float timestamp = 0f)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAndPlayAudioClip>d__16(0)
			{
				source = source,
				track = track,
				volume = volume,
				fadeOutTime = fadeOutTime,
				fadeInTime = fadeInTime,
				timestamp = timestamp
			};
		}

		[IteratorStateMachine(typeof(<FadeAudio>d__17))]
		public static IEnumerator FadeAudio(AudioSource source, float duration, float targetVolume = 0f)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FadeAudio>d__17(0)
			{
				source = source,
				duration = duration,
				targetVolume = targetVolume
			};
		}

		public static AudioSource OverrideAudioClip(AudioSource source, AudioClip clip, bool? loop = null, float timestamp = 0f)
		{
			bool loop2 = loop ?? source.loop;
			if (source.isPlaying)
			{
				source.Stop();
			}
			source.clip = clip;
			source.loop = loop2;
			source.time = Mathf.Clamp(timestamp, 0f, Mathf.Max(0f, clip.length - 0.01f));
			return source;
		}

		public static Task<string> DecodeMusicFile(MusicTrack track)
		{
			return Task.Run(delegate
			{
				string description = track.GetDescription();
				if (description == null)
				{
					Plugin.Logger.LogWarning((object)$"Failed to determine filename for music track \"{track}\"...");
					return string.Empty;
				}
				string encFilePath = GetEncodedFilePath(track);
				if (string.IsNullOrWhiteSpace(encFilePath))
				{
					Plugin.Logger.LogWarning((object)$"Failed to determine file path for music track \"{track}\"...");
					return string.Empty;
				}
				string outFile = Path.Combine(Plugin.TemporaryDir, description + ".ogg");
				return File.Exists(outFile) ? outFile.Replace("\\", "/") : Plugin.FileLock(encFilePath, delegate
				{
					if (File.Exists(outFile))
					{
						return outFile.Replace("\\", "/");
					}
					if (!Directory.Exists(Plugin.TemporaryDir))
					{
						Directory.CreateDirectory(Plugin.TemporaryDir).Attributes |= FileAttributes.Hidden;
					}
					string text = Path.Combine(Plugin.TemporaryDir, $"{Guid.NewGuid()}.ogg.part");
					FileStream fileStream = new FileStream(encFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
					FileStream fileStream2 = new FileStream(text, FileMode.Create, FileAccess.Write);
					MusicDecoder.Decode(fileStream, fileStream2);
					fileStream.Dispose();
					fileStream2.Dispose();
					FileAttributes attributes = File.GetAttributes(text);
					attributes |= FileAttributes.Hidden | FileAttributes.Temporary;
					attributes |= FileAttributes.NotContentIndexed;
					File.SetAttributes(text, attributes);
					File.Move(text, outFile);
					return outFile.Replace("\\", "/");
				});
			});
		}

		private static void StopCurrentCoroutine()
		{
			if (currentCoroutine != null && !((Object)(object)Ambience == (Object)null))
			{
				((MonoBehaviour)Ambience).StopCoroutine(currentCoroutine);
				currentCoroutine = null;
			}
		}
	}
	internal enum MusicTrack
	{
		None,
		[Description("K40CC5R8YZJ04PVQM2N")]
		WhereItAllBegins,
		[Description("K40EX2MQAEFY10SNB34")]
		BingBong,
		[Description("K4092EPQDP0KGHD7H9W")]
		FillYourPockets,
		[Description("K40MMTRC0A7TYRA0EXK")]
		GrabYourBag,
		[Description("K402MFXQCNJJKMXPMDY")]
		SOS,
		[Description("K40N03EW2T3FSWRGH5C")]
		Foam,
		[Description("K4035H327QARRC0VQ6Q")]
		Overgrown,
		[Description("K400G7V5WHNVPW0AY93")]
		IveBeenPoisoned,
		[Description("K40BGHC4Y7GYHFHWGRC")]
		Canopy,
		[Description("K40P8WHNPJK6GK5Y1XZ")]
		Debugging,
		[Description("K404WDEGYSNHHKG67AF")]
		SnowSignal,
		[Description("K40FSB5VHG9RV2J8A72")]
		StrugglingToStayWarm,
		[Description("K40H7FS3YDRJH011EVK")]
		Ascent,
		[Description("K4046QA6WBF62S9R7P4")]
		Whiteout,
		[Description("K404YAVAQ583MQZZXWP")]
		CookingEggsOnHotRocks,
		[Description("K40D18M22S2CXKJXWMN")]
		RunFastOrBurnTrying,
		[Description("K4061K8VG200DW1QTEH")]
		OnlyWayOutIsUp,
		[Description("K4077R6JXJJRW721XRP")]
		Meltdown,
		[Description("K403G30RWH8MZA96SFV")]
		ImpossibleReach,
		[Description("K40SBJ3JGKBWYF68BSN")]
		Obsidian,
		[Description("K40EMTPAV3EX2C3PRY2")]
		PathToTheEnd,
		[Description("K40HH405JVXVP1XNC1H")]
		ReachingTheTop,
		[Description("K40ZJKWS8G0R1J411YD")]
		SomethingLurksInTheShadows,
		[Description("K4070T0B21D63397VHW")]
		WeMustGoBack,
		[Description("K40JJDZ04K2DJ9CBG3N")]
		ANewDay
	}
	internal static class MusicTrackExtension
	{
		internal static string? GetDescription(this MusicTrack track)
		{
			FieldInfo field = track.GetType().GetField(track.ToString());
			if (!Attribute.IsDefined(field, typeof(DescriptionAttribute)))
			{
				return null;
			}
			DescriptionAttribute descriptionAttribute = (DescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute));
			if (!string.IsNullOrWhiteSpace(descriptionAttribute?.Description))
			{
				return descriptionAttribute.Description;
			}
			return null;
		}
	}
	public sealed class PhotonRoomEventListener : MonoBehaviourPun, IInRoomCallbacks
	{
		internal int cachedOwner = -1;

		public void OnEnable()
		{
			PhotonNetwork.AddCallbackTarget((object)this);
		}

		public void OnDisable()
		{
			PhotonNetwork.RemoveCallbackTarget((object)this);
		}

		public void OnMasterClientSwitched(Player newMasterClient)
		{
		}

		public void OnPlayerEnteredRoom(Player newPlayer)
		{
		}

		public void OnRoomPropertiesUpdate(Hashtable changed)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00b7: Expected O, but got Unknown
			//IL_00b7: Expected O, but got Unknown
			if (((Dictionary<object, object>)(object)changed).ContainsKey((object)"BetterPeakOST_Sync_ViewID"))
			{
				NetworkSync.Ensure();
			}
			if (((Dictionary<object, object>)(object)changed).TryGetValue((object)"BetterPeakOST_Sync_Owner", out object value) && cachedOwner != (int)value)
			{
				Player connectedPlayer = NetworkSync.GetConnectedPlayer(cachedOwner);
				if (cachedOwner >= 0 && connectedPlayer != null)
				{
					Plugin.Logger.LogInfo((object)$"Unexpected NetworkSync ownership change from {cachedOwner} to {(int)value}");
					Room currentRoom = PhotonNetwork.CurrentRoom;
					Hashtable val = new Hashtable();
					((Dictionary<object, object>)val).Add((object)"BetterPeakOST_Sync_Owner", (object)cachedOwner);
					Hashtable val2 = new Hashtable();
					((Dictionary<object, object>)val2).Add((object)"BetterPeakOST_Sync_Owner", (object)(int)value);
					currentRoom.SetCustomProperties(val, val2, (WebFlags)null);
				}
				else
				{
					Player player = PhotonNetwork.CurrentRoom.GetPlayer((int)value, false);
					cachedOwner = ((player != null) ? player.ActorNumber : ((int)value));
					Plugin.Logger.LogInfo((object)$"Updated NetworkSync ownership to {cachedOwner}");
				}
			}
		}

		public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
		}

		public void OnPlayerLeftRoom(Player otherPlayer)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_0070: Expected O, but got Unknown
			//IL_0070: Expected O, but got Unknown
			if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"BetterPeakOST_Sync_Owner", out object value) && otherPlayer.ActorNumber == (int)value)
			{
				int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
				Room currentRoom = PhotonNetwork.CurrentRoom;
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)"BetterPeakOST_Sync_Owner", (object)actorNumber);
				Hashtable val2 = new Hashtable();
				((Dictionary<object, object>)val2).Add((object)"BetterPeakOST_Sync_Owner", (object)otherPlayer.ActorNumber);
				if (currentRoom.SetCustomProperties(val, val2, (WebFlags)null))
				{
					NetworkSync.Send("RPC_RoomUpdate", (RpcTarget)5, "BetterPeakOST_Sync_Owner", actorNumber);
					Plugin.Logger.LogInfo((object)$"Elected as new NetworkSync owner (Previous: {otherPlayer.ActorNumber})");
				}
			}
		}

		[PunRPC]
		public void RPC_RoomUpdate(string key, object val, PhotonMessageInfo info)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0041: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"BetterPeakOST_Sync_Owner", out object value) || info.Sender.ActorNumber == (int)value)
			{
				Hashtable val2 = new Hashtable();
				((Dictionary<object, object>)val2).Add((object)key, val);
				OnRoomPropertiesUpdate(val2);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}