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)
{
}
}
}