Decompiled source of HachimiMusic v0.5.2

BepInEx/plugins/HJM-HachimiMusic/HJM.BoomboxPlaylist.dll

Decompiled 16 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using BepInEx;
using BepInEx.Configuration;
using CustomBoomboxMusic;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HJM.BoomboxPlaylist
{
	[BepInPlugin("hjm.boomboxplaylist", "HachimiMusic / 基米音乐汇", "0.5.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal sealed class Playback
		{
			internal bool Armed;

			internal AudioClip Clip;

			internal double EndsAt;

			internal int Cursor = -1;

			internal uint Revision;

			internal uint SessionSeed;

			internal bool HasSession;
		}

		public const string Id = "hjm.boomboxplaylist";

		internal static Plugin Instance;

		private static readonly ConditionalWeakTable<BoomboxItem, Playback> States = new ConditionalWeakTable<BoomboxItem, Playback>();

		private static readonly MethodInfo StartTrack = AccessTools.Method(typeof(BoomboxItem), "StartMusic", (Type[])null, (Type[])null);

		private static readonly MethodInfo NextClip = AccessTools.Method(typeof(CustomBoomboxMusic).GetNestedType("BoomboxPlayPatch", BindingFlags.NonPublic), "GetNextClip", (Type[])null, (Type[])null);

		private static readonly MethodInfo LocalPlay = AccessTools.Method(typeof(ModNetworkBehaviour), "Play", (Type[])null, (Type[])null);

		internal BoomboxKeys Keys;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Expected O, but got Unknown
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Expected O, but got Unknown
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Expected O, but got Unknown
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Expected O, but got Unknown
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Expected O, but got Unknown
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Expected O, but got Unknown
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Expected O, but got Unknown
			//IL_0313: Expected O, but got Unknown
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Expected O, but got Unknown
			Instance = this;
			Keys = new BoomboxKeys();
			Keys.Previous.performed += PreviousPressed;
			Keys.Next.performed += NextPressed;
			Keys.Random.performed += RandomPressed;
			((LcInputActions)Keys).Enable();
			harmony = new Harmony("hjm.boomboxplaylist");
			BoomboxWeight.Install(harmony);
			VolumeCompat.Install(harmony);
			string[] array = new string[3] { "StartHost", "StartServer", "StartClient" };
			foreach (string text in array)
			{
				harmony.Patch((MethodBase)AccessTools.Method(typeof(NetworkManager), text, (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(SessionPlaylist), "NetworkStarted", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			harmony.Patch((MethodBase)AccessTools.Method(typeof(NetworkManager), "Shutdown", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SessionPlaylist), "NetworkStopping", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(StartOfRound), "OnShipLandedMiscEvents", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(SessionPlaylist), "Landed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(ModNetworkBehaviour), "Play", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "Started", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(ModNetworkBehaviour), "IsInBoomboxRange", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "SafeRange", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CustomBoomboxMusic), "AnnouncePlaying", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "Announce", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(NextClip.DeclaringType, "Prefix", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "CorePower", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)StartTrack, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "AfterStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BoomboxItem), "PocketItem", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "KeepPocketMusic", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BoomboxItem), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "Refill", (Type[])null), new HarmonyMethod(typeof(Plugin), "Tick", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BoomboxItem), "UseUpBatteries", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "KeepPowered", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"0.5.2 HachimiMusic: 5 lb boombox; aimed world-boombox controls, held/utility-slot volume, shared landing playlist and pocket playback.");
		}

		private void Update()
		{
			SessionPlaylist.Poll();
		}

		internal void LogPlaylist(string message)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)message);
		}

		private void OnDestroy()
		{
			SessionPlaylist.Reset();
			if (Keys != null)
			{
				Keys.Previous.performed -= PreviousPressed;
				Keys.Next.performed -= NextPressed;
				Keys.Random.performed -= RandomPressed;
				((LcInputActions)Keys).Disable();
			}
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void PreviousPressed(CallbackContext context)
		{
			HandleKey(-1);
		}

		private void NextPressed(CallbackContext context)
		{
			HandleKey(1);
		}

		private void RandomPressed(CallbackContext context)
		{
			HandleKey(0);
		}

		internal static bool CanControl(PlayerControllerB p)
		{
			if ((Object)(object)p != (Object)null && ((NetworkBehaviour)p).IsOwner && p.isPlayerControlled && !p.isPlayerDead && !p.inTerminalMenu && !p.isTypingChat && !p.inSpecialMenu && !p.inSpecialInteractAnimation && !p.isGrabbingObjectAnimation)
			{
				if (!((Object)(object)p.quickMenuManager == (Object)null))
				{
					return !p.quickMenuManager.isMenuOpen;
				}
				return true;
			}
			return false;
		}

		private static void HandleKey(int direction)
		{
			WorldControls.Control(((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController, direction);
		}

		internal static BoomboxItem HeldBox(PlayerControllerB p)
		{
			if (!((Object)(object)p == (Object)null))
			{
				GrabbableObject currentlyHeldObjectServer = p.currentlyHeldObjectServer;
				return (BoomboxItem)(object)((currentlyHeldObjectServer is BoomboxItem) ? currentlyHeldObjectServer : null);
			}
			return null;
		}

		internal static BoomboxItem CarriedBox(PlayerControllerB p)
		{
			if ((Object)(object)p == (Object)null)
			{
				return null;
			}
			GrabbableObject currentlyHeldObjectServer = p.currentlyHeldObjectServer;
			BoomboxItem val = (BoomboxItem)(object)((currentlyHeldObjectServer is BoomboxItem) ? currentlyHeldObjectServer : null);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			GrabbableObject itemOnlySlot = p.ItemOnlySlot;
			BoomboxItem val2 = (BoomboxItem)(object)((itemOnlySlot is BoomboxItem) ? itemOnlySlot : null);
			BoomboxItem val3 = val2;
			if ((Object)(object)val2 != (Object)null && val2.isPlayingMusic)
			{
				return val2;
			}
			if (p.ItemSlots != null)
			{
				GrabbableObject[] itemSlots = p.ItemSlots;
				foreach (GrabbableObject obj in itemSlots)
				{
					BoomboxItem val4 = (BoomboxItem)(object)((obj is BoomboxItem) ? obj : null);
					if (!((Object)(object)val4 == (Object)null))
					{
						if (val4.isPlayingMusic)
						{
							return val4;
						}
						if ((Object)(object)val3 == (Object)null)
						{
							val3 = val4;
						}
					}
				}
			}
			return val3;
		}

		internal static IEnumerable<CodeInstruction> KeepPocketMusic(IEnumerable<CodeInstruction> instructions)
		{
			int replaced = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, StartTrack))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = AccessTools.Method(typeof(Plugin), "PocketPower", (Type[])null, (Type[])null);
					replaced++;
				}
				yield return instruction;
			}
			if (replaced != 1)
			{
				throw new InvalidOperationException("Unexpected boombox PocketItem layout: " + replaced);
			}
		}

		private static void PocketPower(BoomboxItem box, bool startMusic, bool pitchDown)
		{
		}

		internal static bool CorePower(BoomboxItem __0, bool __1, ref bool __result)
		{
			if (!__1)
			{
				return true;
			}
			PowerStart(__0, startMusic: true);
			__result = false;
			return false;
		}

		internal static bool PowerStart(BoomboxItem __instance, bool startMusic)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (!startMusic)
			{
				return true;
			}
			if (!((NetworkBehaviour)__instance).IsOwner)
			{
				return false;
			}
			Playback playback = State(__instance);
			AudioFile clip;
			if (AudioManager.AudioClips.Count == 0)
			{
				clip = (AudioFile)NextClip.Invoke(null, new object[1] { __instance });
			}
			else
			{
				if (!PlaylistReady())
				{
					return false;
				}
				Align(playback, __instance);
				if (SessionPlaylist.Order.Count == 0)
				{
					return false;
				}
				clip = SessionPlaylist.Order[(playback.Cursor >= 0) ? playback.Cursor : 0];
			}
			Play(__instance, clip);
			return false;
		}

		internal static void Navigate(BoomboxItem box, int direction)
		{
			if (!((Object)(object)box == (Object)null) && ((NetworkBehaviour)box).IsSpawned && ((NetworkBehaviour)box).IsOwner && box.isPlayingMusic)
			{
				Select(box, direction);
			}
		}

		internal static void WorldSelect(BoomboxItem box, int command)
		{
			if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsServer && WorldControls.IsWorld(box) && box.isPlayingMusic)
			{
				Select(box, command);
			}
		}

		private static void Select(BoomboxItem box, int direction)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if (AudioManager.AudioClips.Count == 0)
			{
				Play(box, (AudioFile)NextClip.Invoke(null, new object[1] { box }));
			}
			else if (PlaylistReady())
			{
				Playback playback = State(box);
				Align(playback, box);
				int count = SessionPlaylist.Order.Count;
				if (count != 0)
				{
					int index = ((direction == 0) ? SessionPlaylist.RandomIndex(box, playback.Cursor, playback.Revision) : ((Math.Max(0, playback.Cursor) + ((direction >= 0) ? 1 : (-1)) + count) % count));
					Play(box, SessionPlaylist.Order[index]);
				}
			}
		}

		internal static void RandomTrack(BoomboxItem box)
		{
			if (!((Object)(object)box == (Object)null) && ((NetworkBehaviour)box).IsSpawned && ((NetworkBehaviour)box).IsOwner && box.isPlayingMusic && PlaylistReady())
			{
				Select(box, 0);
			}
		}

		private static bool PlaylistReady()
		{
			if (SessionPlaylist.Ready)
			{
				return true;
			}
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip("音箱歌单", "正在等待房主同步歌单,请稍后再试。", false, false, "LC_Tip1");
			}
			return false;
		}

		private static void Align(Playback state, BoomboxItem box)
		{
			if (!state.HasSession || state.SessionSeed != SessionPlaylist.Seed)
			{
				state.HasSession = true;
				state.SessionSeed = SessionPlaylist.Seed;
				state.Cursor = -1;
				state.Revision = 0u;
			}
			if ((Object)(object)box.boomboxAudio != (Object)null)
			{
				state.Cursor = SessionPlaylist.Index(box.boomboxAudio.clip);
			}
		}

		private static void Play(BoomboxItem box, AudioFile clip)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ModNetworkBehaviour.Instance != (Object)null)
			{
				if (clip.Crc.HasValue)
				{
					ModNetworkBehaviour.Instance.StartPlayingMusicServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)box).NetworkObject), clip.Crc.Value, clip.Name);
				}
				else if (clip.VanillaId.HasValue)
				{
					ModNetworkBehaviour.Instance.StartPlayingVanillaMusicServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)box).NetworkObject), clip.VanillaId.Value);
				}
			}
			else
			{
				LocalPlay.Invoke(null, new object[2] { box, clip });
			}
		}

		internal static Playback State(BoomboxItem box)
		{
			return States.GetOrCreateValue(box);
		}

		internal static void Refill(BoomboxItem __instance)
		{
			if ((Object)(object)__instance != (Object)null && ((GrabbableObject)__instance).insertedBattery != null)
			{
				((GrabbableObject)__instance).insertedBattery.charge = 1f;
				((GrabbableObject)__instance).insertedBattery.empty = false;
			}
		}

		internal static bool KeepPowered(BoomboxItem __instance)
		{
			Refill(__instance);
			return false;
		}

		internal static void Arm(BoomboxItem box)
		{
			if (!((Object)(object)box == (Object)null) && !((Object)(object)box.boomboxAudio == (Object)null) && !((Object)(object)box.boomboxAudio.clip == (Object)null))
			{
				box.boomboxAudio.loop = false;
				Playback playback = State(box);
				playback.Clip = box.boomboxAudio.clip;
				playback.EndsAt = Time.realtimeSinceStartupAsDouble + (double)playback.Clip.length;
				playback.Armed = true;
			}
		}

		internal static void Started(BoomboxItem boombox, AudioFile clip)
		{
			Playback playback = State(boombox);
			if (SessionPlaylist.Ready)
			{
				Align(playback, boombox);
				playback.Cursor = SessionPlaylist.Index(clip.AudioClip);
				playback.Revision++;
			}
			Arm(boombox);
		}

		internal static void AfterStart(BoomboxItem __instance, bool startMusic)
		{
			if (!startMusic)
			{
				State(__instance).Armed = false;
			}
			else if ((Object)(object)ModNetworkBehaviour.Instance == (Object)null && __instance.isPlayingMusic)
			{
				Arm(__instance);
			}
		}

		internal static void Tick(BoomboxItem __instance)
		{
			if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsSpawned || !((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayingMusic || !((GrabbableObject)__instance).isBeingUsed || AudioListener.pause || !((Component)__instance).gameObject.activeInHierarchy)
			{
				return;
			}
			AudioSource boomboxAudio = __instance.boomboxAudio;
			if (!((Object)(object)boomboxAudio == (Object)null) && ((Behaviour)boomboxAudio).enabled && !((Object)(object)boomboxAudio.clip == (Object)null) && !boomboxAudio.isPlaying)
			{
				Playback playback = State(__instance);
				if (playback.Armed && !((Object)(object)playback.Clip != (Object)(object)boomboxAudio.clip) && !(Time.realtimeSinceStartupAsDouble < playback.EndsAt))
				{
					playback.Armed = false;
					((BaseUnityPlugin)Instance).Logger.LogInfo((object)"Track ended; requesting the next song in the session playlist.");
					Navigate(__instance, 1);
				}
			}
		}

		internal static bool SafeRange(BoomboxItem boombox, ref bool __result)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			__result = false;
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController);
			if ((Object)(object)val == (Object)null && (Object)(object)StartOfRound.Instance != (Object)null)
			{
				val = StartOfRound.Instance.localPlayerController;
			}
			if ((Object)(object)val == (Object)null || (Object)(object)boombox == (Object)null || (Object)(object)boombox.boomboxAudio == (Object)null)
			{
				return false;
			}
			PlayerControllerB val2 = (val.isPlayerDead ? val.spectatedPlayerScript : val);
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			__result = Vector3.Distance(((Component)boombox.boomboxAudio).transform.position, ((Component)val2).transform.position) <= boombox.boomboxAudio.maxDistance || (((NetworkBehaviour)boombox).IsSpawned && (((NetworkBehaviour)boombox).IsOwner || ((NetworkBehaviour)boombox).OwnerClientId == val2.actualClientId));
			return false;
		}

		internal static bool Announce(AudioFile audioFile)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)("正在播放:" + audioFile.Name));
			if (CustomBoomboxMusic.Instance.DisplayNowPlaying && (Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip("正在播放", audioFile.Name, false, false, "LC_Tip1");
			}
			return false;
		}
	}
	public sealed class BoomboxKeys : LcInputActions
	{
		[InputAction("<Keyboard>/pageUp", Name = "音箱:上一首 / Previous track")]
		public InputAction Previous { get; set; }

		[InputAction("<Keyboard>/pageDown", Name = "音箱:下一首 / Next track")]
		public InputAction Next { get; set; }

		[InputAction("<Keyboard>/r", Name = "音箱:随机切歌 / Random track")]
		public InputAction Random { get; set; }

		public BoomboxKeys()
			: base(new BepInPlugin("hjm.boomboxplaylist", "HachimiMusic / 基米音乐汇", "0.5.0"))
		{
		}//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown

	}
	internal static class SessionPlaylist
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__Requested;

			public static HandleNamedMessageDelegate <1>__Received;

			public static Action<ulong> <2>__Connected;
		}

		private const string RequestMessage = "hjm.boomboxplaylist.seed.request.v1";

		private const string SeedMessage = "hjm.boomboxplaylist.seed.v1";

		private const int Protocol = 1;

		private static NetworkManager network;

		private static List<AudioFile> order;

		private static double nextRequest;

		internal static uint Seed { get; private set; }

		internal static bool Ready { get; private set; }

		internal static IReadOnlyList<AudioFile> Order => order;

		internal static void NetworkStarted(NetworkManager __instance, bool __result)
		{
			if (__result)
			{
				Bind(__instance);
			}
		}

		internal static void NetworkStopping(NetworkManager __instance)
		{
			if ((Object)(object)network == (Object)(object)__instance)
			{
				Reset();
			}
		}

		internal static void Bind(NetworkManager manager)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			if (!((Object)(object)network == (Object)(object)manager))
			{
				Reset();
				network = manager;
				WorldControls.Bind(manager);
				CustomMessagingManager customMessagingManager = manager.CustomMessagingManager;
				object obj = <>O.<0>__Requested;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = Requested;
					<>O.<0>__Requested = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("hjm.boomboxplaylist.seed.request.v1", (HandleNamedMessageDelegate)obj);
				CustomMessagingManager customMessagingManager2 = manager.CustomMessagingManager;
				object obj2 = <>O.<1>__Received;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = Received;
					<>O.<1>__Received = val2;
					obj2 = (object)val2;
				}
				customMessagingManager2.RegisterNamedMessageHandler("hjm.boomboxplaylist.seed.v1", (HandleNamedMessageDelegate)obj2);
				manager.OnClientConnectedCallback += Connected;
				if (manager.IsServer)
				{
					Accept(NewSeed());
				}
				else if (manager.IsConnectedClient)
				{
					Request();
				}
			}
		}

		private static uint NewSeed()
		{
			byte[] array = new byte[4];
			uint num;
			using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create())
			{
				do
				{
					randomNumberGenerator.GetBytes(array);
					num = BitConverter.ToUInt32(array, 0);
				}
				while (Ready && num == Seed);
			}
			return num;
		}

		internal static void Landed()
		{
			if ((Object)(object)network == (Object)null || !network.IsListening || !network.IsServer)
			{
				return;
			}
			Accept(NewSeed());
			foreach (ulong connectedClientsId in network.ConnectedClientsIds)
			{
				if (connectedClientsId != 0L)
				{
					SendSeed(connectedClientsId);
				}
			}
		}

		internal static void Poll()
		{
			if ((Object)(object)network != (Object)null && !network.IsServer && !Ready && network.IsConnectedClient && Time.realtimeSinceStartupAsDouble >= nextRequest)
			{
				Request();
			}
		}

		internal static void Reset()
		{
			WorldControls.Reset();
			if ((Object)(object)network != (Object)null)
			{
				network.OnClientConnectedCallback -= Connected;
				if (network.CustomMessagingManager != null)
				{
					network.CustomMessagingManager.UnregisterNamedMessageHandler("hjm.boomboxplaylist.seed.request.v1");
					network.CustomMessagingManager.UnregisterNamedMessageHandler("hjm.boomboxplaylist.seed.v1");
				}
			}
			network = null;
			order = null;
			Ready = false;
			Seed = 0u;
			nextRequest = 0.0;
		}

		private static void Connected(ulong id)
		{
			if ((Object)(object)network != (Object)null && !network.IsServer && id == network.LocalClientId)
			{
				Request();
			}
		}

		private unsafe static void Request()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			nextRequest = Time.realtimeSinceStartupAsDouble + 2.0;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
			try
			{
				int num = 1;
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				network.CustomMessagingManager.SendNamedMessage("hjm.boomboxplaylist.seed.request.v1", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void Requested(ulong sender, FastBufferReader reader)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)network == (Object)null) && network.IsServer && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position >= 4)
			{
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				if (num == 1)
				{
					SendSeed(sender);
				}
			}
		}

		private unsafe static void SendSeed(ulong client)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1);
			try
			{
				int num = 1;
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				uint seed = Seed;
				((FastBufferWriter)(ref val)).WriteValueSafe<uint>(ref seed, default(ForPrimitives));
				num = Catalog().Count;
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				seed = CatalogHash();
				((FastBufferWriter)(ref val)).WriteValueSafe<uint>(ref seed, default(ForPrimitives));
				network.CustomMessagingManager.SendNamedMessage("hjm.boomboxplaylist.seed.v1", client, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void Received(ulong sender, FastBufferReader reader)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)network == (Object)null || network.IsServer || sender != 0L || ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position < 16)
			{
				return;
			}
			int num = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
			uint num2 = default(uint);
			((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref num2, default(ForPrimitives));
			int num3 = default(int);
			((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num3, default(ForPrimitives));
			uint num4 = default(uint);
			((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref num4, default(ForPrimitives));
			if (num != 1 || num3 != Catalog().Count || num4 != CatalogHash())
			{
				if ((Object)(object)Plugin.Instance != (Object)null)
				{
					Plugin.Instance.LogPlaylist("房主与本机歌曲文件或音箱设置不一致;请安装相同版本的歌单。");
				}
				nextRequest = Time.realtimeSinceStartupAsDouble + 30.0;
			}
			else if (!Ready || Seed != num2)
			{
				Accept(num2);
			}
		}

		private static void Accept(uint seed)
		{
			Seed = seed;
			order = Shuffle(Catalog(), seed);
			Ready = true;
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.LogPlaylist("Session playlist seed=" + seed + ", songs=" + order.Count + ", order=" + string.Join(",", order.Select((AudioFile f) => f.Crc.Value.ToString("x8"))));
			}
		}

		private static List<AudioFile> Catalog()
		{
			return (from f in AudioManager.AudioClips
				where f.Crc.HasValue
				group f by f.Crc.Value into g
				select g.First() into f
				orderby f.Crc.Value
				select f).ToList();
		}

		private static uint CatalogHash()
		{
			uint num = 2166136261u;
			foreach (AudioFile item in Catalog())
			{
				for (int i = 0; i < 4; i++)
				{
					num = (num ^ (byte)(item.Crc.Value >> i * 8)) * 16777619;
				}
			}
			return num;
		}

		internal static List<AudioFile> Shuffle(IEnumerable<AudioFile> files, uint seed)
		{
			List<AudioFile> list = files.OrderBy((AudioFile f) => f.Crc.Value).ToList();
			uint state = ((seed == 0) ? 1831565813u : seed);
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = (int)(Next(ref state) % (uint)(num + 1));
				AudioFile value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
			return list;
		}

		private static uint Next(ref uint state)
		{
			state ^= state << 13;
			state ^= state >> 17;
			state ^= state << 5;
			return state;
		}

		internal static int Index(AudioClip clip)
		{
			if (order != null)
			{
				return order.FindIndex((AudioFile f) => (Object)(object)f.AudioClip == (Object)(object)clip);
			}
			return -1;
		}

		internal static int RandomIndex(BoomboxItem box, int current, uint revision)
		{
			if (order.Count < 2)
			{
				return 0;
			}
			uint state = Seed ^ (uint)(int)((NetworkBehaviour)box).NetworkObjectId ^ (uint)(int)(((NetworkBehaviour)box).NetworkObjectId >> 32) ^ (uint)((int)(revision + 1) * -1640531527);
			if (state == 0)
			{
				state = 1831565813u;
			}
			return (Math.Max(0, current) + 1 + (int)(Next(ref state) % (uint)(order.Count - 1))) % order.Count;
		}
	}
	internal static class WorldControls
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__Receive;
		}

		private const string Message = "hjm.hachimimusic.world-control.v1";

		private static NetworkManager network;

		private static readonly FieldInfo InteractionMask = AccessTools.Field(typeof(PlayerControllerB), "interactableObjectsMask");

		private static int Mask(PlayerControllerB player)
		{
			return (int)InteractionMask.GetValue(player);
		}

		internal static void Bind(NetworkManager manager)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			network = manager;
			CustomMessagingManager customMessagingManager = manager.CustomMessagingManager;
			object obj = <>O.<0>__Receive;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = Receive;
				<>O.<0>__Receive = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("hjm.hachimimusic.world-control.v1", (HandleNamedMessageDelegate)obj);
		}

		internal static void Reset()
		{
			if ((Object)(object)network != (Object)null && network.CustomMessagingManager != null)
			{
				network.CustomMessagingManager.UnregisterNamedMessageHandler("hjm.hachimimusic.world-control.v1");
			}
			network = null;
		}

		internal static bool IsWorld(BoomboxItem box)
		{
			if ((Object)(object)box != (Object)null && ((NetworkBehaviour)box).IsSpawned && !((GrabbableObject)box).isHeld && !((GrabbableObject)box).isPocketed)
			{
				return (Object)(object)((GrabbableObject)box).playerHeldBy == (Object)null;
			}
			return false;
		}

		internal static float Range(PlayerControllerB player)
		{
			return Mathf.Clamp(player.grabDistance, 1f, 5f);
		}

		internal static BoomboxItem AimedBox(PlayerControllerB player)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player.gameplayCamera == (Object)null)
			{
				return null;
			}
			Transform transform = ((Component)player.gameplayCamera).transform;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(transform.position, transform.forward, ref val, Range(player), Mask(player), (QueryTriggerInteraction)0))
			{
				return null;
			}
			BoomboxItem componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<BoomboxItem>();
			if (!IsWorld(componentInParent))
			{
				return null;
			}
			return componentInParent;
		}

		internal static BoomboxItem Target(PlayerControllerB player, bool random)
		{
			BoomboxItem val = AimedBox(player);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			if (!random)
			{
				return Plugin.CarriedBox(player);
			}
			return Plugin.HeldBox(player);
		}

		internal static void Control(PlayerControllerB player, int command)
		{
			if (!Plugin.CanControl(player))
			{
				return;
			}
			BoomboxItem val = Target(player, command == 0);
			if (!((Object)(object)val == (Object)null) && val.isPlayingMusic)
			{
				if (IsWorld(val))
				{
					Request(val, command);
				}
				else if (command == 0)
				{
					Plugin.RandomTrack(val);
				}
				else
				{
					Plugin.Navigate(val, command);
				}
			}
		}

		internal unsafe static void Request(BoomboxItem box, int command)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)network == (Object)null || !network.IsListening || (Object)(object)box == (Object)null || !((NetworkBehaviour)box).IsSpawned || command < -1 || command > 1)
			{
				return;
			}
			if (network.IsServer)
			{
				Apply(network.LocalClientId, ((NetworkBehaviour)box).NetworkObjectId, command);
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, -1);
			try
			{
				ulong networkObjectId = ((NetworkBehaviour)box).NetworkObjectId;
				((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref command, default(ForPrimitives));
				network.CustomMessagingManager.SendNamedMessage("hjm.hachimimusic.world-control.v1", 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void Receive(ulong sender, FastBufferReader reader)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//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_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)network == (Object)null) && network.IsServer && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position >= 12)
			{
				ulong id = default(ulong);
				((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref id, default(ForPrimitives));
				int command = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref command, default(ForPrimitives));
				Apply(sender, id, command);
			}
		}

		internal static bool Apply(ulong sender, ulong id, int command)
		{
			if ((Object)(object)network == (Object)null || !network.IsServer || command < -1 || command > 1)
			{
				return false;
			}
			if (!network.SpawnManager.SpawnedObjects.TryGetValue(id, out var value))
			{
				return false;
			}
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null)
			{
				return false;
			}
			PlayerControllerB player = null;
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if ((Object)(object)val != (Object)null && val.actualClientId == sender)
				{
					player = val;
					break;
				}
			}
			BoomboxItem component = ((Component)value).GetComponent<BoomboxItem>();
			if (!CanReach(player, component) || !component.isPlayingMusic)
			{
				return false;
			}
			Plugin.WorldSelect(component, command);
			return true;
		}

		internal static bool CanReach(PlayerControllerB player, BoomboxItem box)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || !player.isPlayerControlled || player.isPlayerDead || !IsWorld(box))
			{
				return false;
			}
			Vector3 val = (((Object)(object)player.gameplayCamera == (Object)null) ? (((Component)player).transform.position + Vector3.up * 1.6f) : ((Component)player.gameplayCamera).transform.position);
			Collider componentInChildren = ((Component)box).GetComponentInChildren<Collider>();
			Vector3 val2;
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				Bounds bounds = componentInChildren.bounds;
				val2 = ((Bounds)(ref bounds)).center;
			}
			else
			{
				val2 = ((Component)box).transform.position;
			}
			Vector3 val3 = val2;
			if (Vector3.Distance(val, val3) > Range(player) + 0.25f)
			{
				return false;
			}
			RaycastHit val4 = default(RaycastHit);
			if (Physics.Linecast(val, val3, ref val4, Mask(player), (QueryTriggerInteraction)0))
			{
				return (Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<BoomboxItem>() == (Object)(object)box;
			}
			return true;
		}
	}
	internal static class VolumeCompat
	{
		private static FieldInfo looking;

		private static FieldInfo grabbing;

		private static FieldInfo boombox;

		private static FieldInfo enabled;

		private static FieldInfo multiplier;

		internal static void Install(Harmony harmony)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00b2: Expected O, but got Unknown
			Type type = Type.GetType("ObjectVolumeController.Patcher.ObjectsManager, ObjectVolumeController", throwOnError: true);
			Type? type2 = Type.GetType("ObjectVolumeController.Config.ConfigSettings, ObjectVolumeController", throwOnError: true);
			Type type3 = Type.GetType("ObjectVolumeController.AudioPlayers.AudioPlayerTypeBase, ObjectVolumeController", throwOnError: true);
			looking = AccessTools.Field(type, "lookingAtObjectType");
			grabbing = AccessTools.Field(type, "grabbingObjectType");
			boombox = AccessTools.Field(type, "boomboxItems");
			enabled = AccessTools.Field(type2, "enableVolumeControllerBoombox");
			multiplier = AccessTools.Field(type3, "currentVolumeMultiplier");
			harmony.Patch((MethodBase)AccessTools.Method(type, "OnPressVolumeKey", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VolumeCompat), "Prepare", (Type[])null), new HarmonyMethod(typeof(VolumeCompat), "Feedback", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static bool Prepare(out float __state)
		{
			__state = float.NaN;
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance == (Object)null) ? null : GameNetworkManager.Instance.localPlayerController);
			if ((Object)(object)val == (Object)null && (Object)(object)StartOfRound.Instance != (Object)null)
			{
				val = StartOfRound.Instance.localPlayerController;
			}
			if ((Object)(object)Plugin.HeldBox(val) == (Object)null)
			{
				return true;
			}
			if (!Plugin.CanControl(val))
			{
				return false;
			}
			if (!((ConfigEntry<bool>)enabled.GetValue(null)).Value)
			{
				return true;
			}
			object value = boombox.GetValue(null);
			if (value == null)
			{
				return true;
			}
			looking.SetValue(null, null);
			grabbing.SetValue(null, value);
			__state = (float)multiplier.GetValue(value);
			return true;
		}

		private static void Feedback(float __state)
		{
			if (float.IsNaN(__state))
			{
				return;
			}
			object value = boombox.GetValue(null);
			if (value != null)
			{
				float num = (float)multiplier.GetValue(value);
				if (num != __state && (Object)(object)HUDManager.Instance != (Object)null)
				{
					HUDManager.Instance.DisplayTip("音箱音量", Mathf.RoundToInt(num * 100f) + "%", false, false, "LC_Tip1");
				}
			}
		}
	}
	internal static class BoomboxWeight
	{
		private const float ItemWeight = 1.0476191f;

		internal static void Install(Harmony harmony)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(StartOfRound), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(BoomboxWeight), "CatalogReady", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BoomboxItem), "Start", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BoomboxWeight), "Spawned", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void CatalogReady(StartOfRound __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.allItemsList == (Object)null || __instance.allItemsList.itemsList == null)
			{
				return;
			}
			foreach (Item items in __instance.allItemsList.itemsList)
			{
				if ((Object)(object)items != (Object)null && (Object)(object)items.spawnPrefab != (Object)null && (Object)(object)items.spawnPrefab.GetComponent<BoomboxItem>() != (Object)null)
				{
					items.weight = 1.0476191f;
				}
			}
		}

		private static void Spawned(BoomboxItem __instance)
		{
			if ((Object)(object)__instance != (Object)null && (Object)(object)((GrabbableObject)__instance).itemProperties != (Object)null)
			{
				((GrabbableObject)__instance).itemProperties.weight = 1.0476191f;
			}
		}
	}
}