Decompiled source of SteelSpeaker v0.2.0

BepInEx/plugins/SteelSpeaker/com.github.coleman71803.SteelSpeaker.dll

Decompiled a year ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using SteelSpeaker.Config;
using SteelSpeaker.Dev;
using SteelSpeaker.Interaction;
using SteelSpeaker.Managers;
using SteelSpeaker.Models;
using SteelSpeaker.Networking;
using SteelSpeaker.Prefabs;
using SteelSpeaker.UI;
using SteelSpeaker.Utils;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.coleman71803.SteelSpeaker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+de00c14257a3a336bdc6baceca0427bf099f56e1")]
[assembly: AssemblyProduct("com.github.coleman71803.SteelSpeaker")]
[assembly: AssemblyTitle("SteelSpeaker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.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 SteelSpeaker
{
	[BepInPlugin("com.github.coleman71803.SteelSpeaker", "SteelSpeaker", "0.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Id = "com.github.coleman71803.SteelSpeaker";

		internal static ManualLogSource Log { get; private set; }

		public static string Name => "SteelSpeaker";

		public static string Version => "0.2.0";

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			GameObject val = new GameObject("SteelSpeaker.ConfigHost");
			Object.DontDestroyOnLoad((Object)(object)val);
			val.AddComponent<MountOffsetTuner>();
			GameObject val2 = new GameObject("SteelSpeaker.Core");
			Object.DontDestroyOnLoad((Object)(object)val2);
			val2.AddComponent<SpeakerBehavior>();
			val2.AddComponent<SpeakerManager>();
			val2.AddComponent<SpeakerNetSync>();
			val2.AddComponent<EscapeMenuVolumeUI>();
			val2.AddComponent<UIHotkeyListener>();
			Log.LogInfo((object)("Plugin " + Name + " loaded. Core systems initialized (BackQuote ` UI toggle)."));
		}
	}
}
namespace SteelSpeaker.Utils
{
	public static class AttachmentService
	{
		public static void Attach(GameObject item, Transform root, string bonePath, Vector3 localPos, Vector3 localEuler)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			Transform val = (Transform)(string.IsNullOrEmpty(bonePath) ? ((object)root) : ((object)(root.Find(bonePath) ?? root)));
			Rigidbody component = item.GetComponent<Rigidbody>();
			Collider component2 = item.GetComponent<Collider>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.isKinematic = true;
			}
			if (Object.op_Implicit((Object)(object)component2))
			{
				component2.enabled = false;
			}
			item.transform.SetParent(val, false);
			item.transform.localPosition = localPos;
			item.transform.localRotation = Quaternion.Euler(localEuler);
		}

		public static void Detach(GameObject item, Vector3 tossImpulse)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody component = item.GetComponent<Rigidbody>();
			Collider component2 = item.GetComponent<Collider>();
			item.transform.SetParent((Transform)null, true);
			if (Object.op_Implicit((Object)(object)component))
			{
				component.isKinematic = false;
				component.AddForce(tossImpulse, (ForceMode)1);
			}
			if (Object.op_Implicit((Object)(object)component2))
			{
				component2.enabled = true;
			}
		}
	}
	public static class HostDetector
	{
		public static bool IsHost()
		{
			try
			{
				Type type = Type.GetType("Unity.Netcode.NetworkManager, Unity.Netcode.Runtime");
				object obj = (type?.GetProperty("Singleton", BindingFlags.Static | BindingFlags.Public))?.GetValue(null);
				PropertyInfo propertyInfo = type?.GetProperty("IsServer", BindingFlags.Instance | BindingFlags.Public);
				if (obj != null && propertyInfo != null && (bool)(propertyInfo.GetValue(obj) ?? ((object)false)))
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				PropertyInfo propertyInfo2 = Type.GetType("Photon.Pun.PhotonNetwork, PhotonUnityNetworking")?.GetProperty("IsMasterClient", BindingFlags.Static | BindingFlags.Public);
				if (propertyInfo2 != null && (bool)(propertyInfo2.GetValue(null) ?? ((object)false)))
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}
	}
	public static class SpeakerAttach
	{
		public static bool AttachToHook(GameObject speakerInstance, Transform characterHook, string clipAnchorPath = "ClipAnchor")
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)speakerInstance == (Object)null || (Object)(object)characterHook == (Object)null)
			{
				Debug.LogError((object)"[SteelSpeaker] SpeakerAttach.AttachToHook called with null args");
				return false;
			}
			Rigidbody val = speakerInstance.GetComponent<Rigidbody>() ?? speakerInstance.AddComponent<Rigidbody>();
			val.mass = 1.4f;
			val.drag = 0.1f;
			val.angularDrag = 0.1f;
			val.useGravity = true;
			val.interpolation = (RigidbodyInterpolation)1;
			val.isKinematic = false;
			Rigidbody val2 = ((Component)characterHook).GetComponent<Rigidbody>() ?? ((Component)characterHook).gameObject.AddComponent<Rigidbody>();
			val2.isKinematic = true;
			Transform val3 = speakerInstance.transform.Find(clipAnchorPath);
			if (!Object.op_Implicit((Object)(object)val3))
			{
				Debug.LogError((object)("[SteelSpeaker] ClipAnchor not found at path '" + clipAnchorPath + "'."));
				return false;
			}
			ConfigurableJoint val4 = speakerInstance.GetComponent<ConfigurableJoint>() ?? speakerInstance.AddComponent<ConfigurableJoint>();
			((Joint)val4).connectedBody = val2;
			((Joint)val4).autoConfigureConnectedAnchor = false;
			((Joint)val4).anchor = speakerInstance.transform.InverseTransformPoint(val3.position);
			((Joint)val4).connectedAnchor = Vector3.zero;
			val4.xMotion = (ConfigurableJointMotion)0;
			val4.yMotion = (ConfigurableJointMotion)0;
			val4.zMotion = (ConfigurableJointMotion)0;
			val4.angularXMotion = (ConfigurableJointMotion)1;
			val4.angularYMotion = (ConfigurableJointMotion)1;
			val4.angularZMotion = (ConfigurableJointMotion)1;
			SoftJointLimit val5 = default(SoftJointLimit);
			((SoftJointLimit)(ref val5)).limit = -25f;
			val4.lowAngularXLimit = val5;
			((SoftJointLimit)(ref val5)).limit = 25f;
			val4.highAngularXLimit = val5;
			((SoftJointLimit)(ref val5)).limit = 45f;
			val4.angularYLimit = val5;
			((SoftJointLimit)(ref val5)).limit = 45f;
			val4.angularZLimit = val5;
			val4.projectionMode = (JointProjectionMode)1;
			val4.projectionAngle = 20f;
			val4.projectionDistance = 0.2f;
			Collider val6 = (Collider)(((object)speakerInstance.GetComponent<Collider>()) ?? ((object)speakerInstance.AddComponent<BoxCollider>()));
			val6.enabled = true;
			return true;
		}

		public static void Detach(GameObject speakerInstance)
		{
			if (!((Object)(object)speakerInstance == (Object)null))
			{
				ConfigurableJoint component = speakerInstance.GetComponent<ConfigurableJoint>();
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
				Rigidbody component2 = speakerInstance.GetComponent<Rigidbody>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.isKinematic = false;
				}
			}
		}
	}
}
namespace SteelSpeaker.UI
{
	public class EscapeMenuVolumeUI : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass27_0
		{
			public List<YouTubeService.SearchResult> res;

			public EscapeMenuVolumeUI <>4__this;

			public string query;

			public bool done;

			internal void <SearchRoutine>b__0()
			{
				try
				{
					res = <>4__this._yt.Search(query);
				}
				catch
				{
					res = new List<YouTubeService.SearchResult>();
				}
				finally
				{
					done = true;
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass29_0
		{
			public string mediaUrl;

			public EscapeMenuVolumeUI <>4__this;

			public string url;

			public bool resolveDone;

			internal void <QueueRoutine>b__0()
			{
				try
				{
					mediaUrl = <>4__this._yt.ResolveStreamUrl(url);
				}
				catch
				{
					mediaUrl = null;
				}
				finally
				{
					resolveDone = true;
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass29_1
		{
			public string localPath;

			public bool done;

			public <>c__DisplayClass29_0 CS$<>8__locals1;

			internal void <QueueRoutine>b__1()
			{
				localPath = CS$<>8__locals1.<>4__this._yt.EnsureLocalAudio(CS$<>8__locals1.url);
				done = true;
			}
		}

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

			private object <>2__current;

			public EscapeMenuVolumeUI <>4__this;

			public YouTubeService.SearchResult r;

			private <>c__DisplayClass29_0 <>8__1;

			private <>c__DisplayClass29_1 <>8__2;

			private string <finalUrl>5__2;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<>8__2 = null;
				<finalUrl>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				EscapeMenuVolumeUI escapeMenuVolumeUI = <>4__this;
				string text;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass29_0();
					<>8__1.<>4__this = <>4__this;
					<>8__1.url = "https://www.youtube.com/watch?v=" + r.videoId;
					<>8__1.mediaUrl = null;
					<>8__1.resolveDone = false;
					Task.Run(delegate
					{
						try
						{
							<>8__1.mediaUrl = <>8__1.<>4__this._yt.ResolveStreamUrl(<>8__1.url);
						}
						catch
						{
							<>8__1.mediaUrl = null;
						}
						finally
						{
							<>8__1.resolveDone = true;
						}
					});
					goto IL_00ad;
				case 1:
					<>1__state = -1;
					goto IL_00ad;
				case 2:
					{
						<>1__state = -1;
						goto IL_01a5;
					}
					IL_00ad:
					if (!<>8__1.resolveDone)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					if (string.IsNullOrEmpty(<>8__1.mediaUrl))
					{
						Debug.LogError((object)"[SteelSpeaker] Failed to resolve audio stream.");
						escapeMenuVolumeUI._queueInProgress = false;
						return false;
					}
					<finalUrl>5__2 = <>8__1.mediaUrl;
					text = <>8__1.mediaUrl.ToLowerInvariant();
					if (text.EndsWith(".ogg") || text.EndsWith(".mp3") || text.EndsWith(".wav"))
					{
						break;
					}
					if (escapeMenuVolumeUI._yt.HasFfmpeg())
					{
						<>8__2 = new <>c__DisplayClass29_1();
						<>8__2.CS$<>8__locals1 = <>8__1;
						<>8__2.done = false;
						<>8__2.localPath = null;
						Task.Run(delegate
						{
							<>8__2.localPath = <>8__2.CS$<>8__locals1.<>4__this._yt.EnsureLocalAudio(<>8__2.CS$<>8__locals1.url);
							<>8__2.done = true;
						});
						goto IL_01a5;
					}
					Debug.LogWarning((object)"[SteelSpeaker] Stream format may be unsupported by Unity. Place ffmpeg in SteelSpeaker/bin to enable mp3 conversion.");
					break;
					IL_01a5:
					if (!<>8__2.done)
					{
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					if (!string.IsNullOrEmpty(<>8__2.localPath))
					{
						<finalUrl>5__2 = "file://" + <>8__2.localPath.Replace("\\", "/");
					}
					else
					{
						Debug.LogError((object)"[SteelSpeaker] Conversion failed; attempting to play original stream (may fail).");
					}
					<>8__2 = null;
					break;
				}
				YouTubeTrack t = new YouTubeTrack(r.videoId, r.title, <finalUrl>5__2, r.duration);
				escapeMenuVolumeUI._net.EnqueueTrack(t);
				escapeMenuVolumeUI._queueInProgress = false;
				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 <SearchRoutine>d__27 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public EscapeMenuVolumeUI <>4__this;

			public string query;

			private <>c__DisplayClass27_0 <>8__1;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				EscapeMenuVolumeUI escapeMenuVolumeUI = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass27_0();
					<>8__1.<>4__this = <>4__this;
					<>8__1.query = query;
					escapeMenuVolumeUI._isSearching = true;
					escapeMenuVolumeUI._searchStatus = "Searching...";
					<>8__1.res = null;
					<>8__1.done = false;
					Task.Run(delegate
					{
						try
						{
							<>8__1.res = <>8__1.<>4__this._yt.Search(<>8__1.query);
						}
						catch
						{
							<>8__1.res = new List<YouTubeService.SearchResult>();
						}
						finally
						{
							<>8__1.done = true;
						}
					});
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<>8__1.done)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				escapeMenuVolumeUI._results = <>8__1.res ?? new List<YouTubeService.SearchResult>();
				escapeMenuVolumeUI._searchStatus = ((escapeMenuVolumeUI._results.Count == 0) ? "No results" : string.Empty);
				escapeMenuVolumeUI._isSearching = false;
				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();
			}
		}

		private bool _show;

		private string _query = string.Empty;

		private Vector2 _scroll;

		private List<YouTubeService.SearchResult> _results = new List<YouTubeService.SearchResult>();

		private YouTubeService _yt = new YouTubeService();

		private SpeakerNetSync _net;

		private bool? _ytOk;

		private bool? _ffOk;

		private bool _prevCursorVisible;

		private CursorLockMode _prevCursorLock;

		private bool _queueInProgress;

		private bool _isSearching;

		private string _searchStatus = string.Empty;

		private int _volSlider = 50;

		private float _baselineVol = 1f;

		private bool _volInitialized;

		private KeyCode _toggleKey = (KeyCode)291;

		private KeyboardShortcut _toggleShortcut = new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>());

		private const string BuildMark = "MARK_2025-09-01_12-20";

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

		private void Awake()
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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)
			try
			{
				Instance = this;
				_net = Object.FindObjectOfType<SpeakerNetSync>() ?? ((Component)this).gameObject.AddComponent<SpeakerNetSync>();
				try
				{
					KeyboardShortcut toggleShortcut = (KeyboardShortcut)(((??)ModConfig.UIToggleShortcut?.Value) ?? new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>()));
					if ((int)((KeyboardShortcut)(ref toggleShortcut)).MainKey != 0)
					{
						_toggleShortcut = toggleShortcut;
					}
					else
					{
						string value = ModConfig.ToggleKey?.Value ?? "F10";
						if (!Enum.TryParse<KeyCode>(value, ignoreCase: true, out _toggleKey))
						{
							_toggleKey = (KeyCode)291;
						}
					}
				}
				catch
				{
					_toggleKey = (KeyCode)291;
				}
				Debug.Log((object)"[SteelSpeaker] UI ready. Toggle with BackQuote (`) only.");
				Task.Run(delegate
				{
					try
					{
						_ytOk = _yt.HasBinary();
					}
					catch
					{
						_ytOk = false;
					}
				});
				Task.Run(delegate
				{
					try
					{
						_ffOk = _yt.HasFfmpeg();
					}
					catch
					{
						_ffOk = false;
					}
				});
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[SteelSpeaker] UI Awake error: " + ex));
			}
		}

		private void Update()
		{
		}

		private void OnGUI()
		{
			//IL_06c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			if (!_show)
			{
				return;
			}
			float num = 520f;
			float num2 = 420f;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(20f, 20f, num, num2);
			Color color = GUI.color;
			Color backgroundColor = GUI.backgroundColor;
			Color contentColor = GUI.contentColor;
			try
			{
				GUI.color = new Color(0f, 0f, 0f, 0.7f);
				GUI.Box(val, GUIContent.none);
				GUI.color = Color.white;
				GUI.backgroundColor = Color.white;
				GUI.contentColor = Color.white;
				GUILayout.BeginArea(val);
				GUILayout.Label("SteelSpeaker (`)  MARK_2025-09-01_12-20", Array.Empty<GUILayoutOption>());
				SpeakerManager instance = SpeakerManager.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					if (!_volInitialized)
					{
						try
						{
							_baselineVol = Mathf.Clamp01(instance.GetVolume());
						}
						catch
						{
							_baselineVol = 1f;
						}
						_volSlider = 50;
						_volInitialized = true;
					}
					string text = ((instance.Current != null) ? instance.Current.Title : "<none>");
					string text2 = (instance.IsPaused ? "Paused" : (instance.IsPlaying ? "Playing" : "Idle"));
					GUILayout.Label("Now: " + text + "  [" + text2 + "]", Array.Empty<GUILayoutOption>());
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					if (!instance.IsPlaying)
					{
						if (GUILayout.Button("Play", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }))
						{
							try
							{
								if (PhotonNetwork.IsConnected && !PhotonNetwork.IsMasterClient)
								{
									_net.RequestPlay();
								}
								else
								{
									SpeakerManager.Instance?.StartOrResume();
									if (PhotonNetwork.IsConnected)
									{
										_net.BroadcastPause(paused: false);
									}
								}
							}
							catch
							{
								SpeakerManager.Instance?.StartOrResume();
							}
						}
					}
					else if (GUILayout.Button(instance.IsPaused ? "Resume" : "Pause", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }))
					{
						try
						{
							if (PhotonNetwork.IsConnected && !PhotonNetwork.IsMasterClient)
							{
								_net.RequestTogglePause();
							}
							else
							{
								SpeakerManager instance2 = SpeakerManager.Instance;
								instance2?.TogglePause();
								if (PhotonNetwork.IsConnected && (Object)(object)instance2 != (Object)null)
								{
									_net.BroadcastPause(instance2.IsPaused);
								}
							}
						}
						catch
						{
							SpeakerManager.Instance?.TogglePause();
						}
					}
					if (GUILayout.Button("Skip", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
					{
						try
						{
							if (PhotonNetwork.IsConnected && !PhotonNetwork.IsMasterClient)
							{
								_net.RequestSkip();
							}
							else
							{
								SpeakerManager.Instance?.Skip();
							}
						}
						catch
						{
							SpeakerManager.Instance?.Skip();
						}
					}
					if (GUILayout.Button("Clear", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
					{
						_query = string.Empty;
						_results.Clear();
						_searchStatus = string.Empty;
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUI.enabled = !_queueInProgress;
				_query = GUILayout.TextField(_query, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num - 140f) });
				if (GUILayout.Button(_queueInProgress ? "Busy..." : "Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
				{
					DoSearch();
				}
				GUI.enabled = true;
				GUILayout.EndHorizontal();
				if (!string.IsNullOrEmpty(_searchStatus))
				{
					GUILayout.Label(_searchStatus, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Space(6f);
				_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(140f) });
				foreach (YouTubeService.SearchResult result in _results)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label(Truncate(result.title, 48), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num - 180f) });
					GUILayout.Label(FormatDur(result.duration), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
					bool enabled = GUI.enabled;
					GUI.enabled = !_queueInProgress;
					if (GUILayout.Button("Queue", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
					{
						Queue(result);
					}
					GUI.enabled = enabled;
					GUILayout.EndHorizontal();
				}
				GUILayout.EndScrollView();
				GUILayout.Space(6f);
				if ((Object)(object)instance != (Object)null)
				{
					List<YouTubeTrack> queueSnapshot = instance.GetQueueSnapshot();
					GUILayout.Label("Queue:", Array.Empty<GUILayoutOption>());
					if (queueSnapshot.Count == 0)
					{
						GUILayout.Label("<empty>", Array.Empty<GUILayoutOption>());
					}
					for (int i = 0; i < queueSnapshot.Count; i++)
					{
						YouTubeTrack youTubeTrack = queueSnapshot[i];
						GUILayout.Label($"{i + 1}. {Truncate(youTubeTrack.Title, 56)}", Array.Empty<GUILayoutOption>());
					}
					GUILayout.Space(6f);
				}
				if (!_ffOk.HasValue)
				{
					GUILayout.Label("Checking ffmpeg...", Array.Empty<GUILayoutOption>());
				}
				else
				{
					GUILayout.Label(_ffOk.GetValueOrDefault() ? "ffmpeg OK (will convert if needed)" : "ffmpeg not found ? some tracks may not play. Place ffmpeg in SteelSpeaker/bin", Array.Empty<GUILayoutOption>());
				}
				if ((Object)(object)instance != (Object)null)
				{
					if (!_volInitialized)
					{
						try
						{
							_baselineVol = Mathf.Clamp01(instance.GetVolume());
						}
						catch
						{
							_baselineVol = 1f;
						}
						_volSlider = 50;
						_volInitialized = true;
					}
					GUILayout.Space(6f);
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label("Volume (50=baseline)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) });
					int num3 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)_volSlider, 1f, 100f, Array.Empty<GUILayoutOption>()));
					GUILayout.Label(num3.ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(36f) });
					GUILayout.EndHorizontal();
					if (num3 != _volSlider)
					{
						_volSlider = num3;
						float volume = SliderToVolume(_volSlider, _baselineVol);
						try
						{
							instance.SetVolume(volume);
						}
						catch
						{
						}
					}
				}
				GUILayout.EndArea();
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[SteelSpeaker] UI render error: " + ex));
			}
			finally
			{
				GUI.color = color;
				GUI.backgroundColor = backgroundColor;
				GUI.contentColor = contentColor;
			}
		}

		private void DoSearch()
		{
			_results.Clear();
			if (!string.IsNullOrWhiteSpace(_query) && !_isSearching)
			{
				((MonoBehaviour)this).StartCoroutine(SearchRoutine(_query));
			}
		}

		[IteratorStateMachine(typeof(<SearchRoutine>d__27))]
		private IEnumerator SearchRoutine(string query)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SearchRoutine>d__27(0)
			{
				<>4__this = this,
				query = query
			};
		}

		private void Queue(YouTubeService.SearchResult r)
		{
			if (!_queueInProgress)
			{
				_queueInProgress = true;
				((MonoBehaviour)this).StartCoroutine(QueueRoutine(r));
			}
		}

		[IteratorStateMachine(typeof(<QueueRoutine>d__29))]
		private IEnumerator QueueRoutine(YouTubeService.SearchResult r)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <QueueRoutine>d__29(0)
			{
				<>4__this = this,
				r = r
			};
		}

		private static string Truncate(string s, int len)
		{
			if (!string.IsNullOrEmpty(s))
			{
				if (s.Length > len)
				{
					return s.Substring(0, len - 1) + "...";
				}
				return s;
			}
			return s;
		}

		private static string FormatDur(float s)
		{
			if (s <= 0f)
			{
				return "--:--";
			}
			int num = Mathf.FloorToInt(s / 60f);
			int num2 = Mathf.FloorToInt(s % 60f);
			return num.ToString("0") + ":" + num2.ToString("00");
		}

		public void Open()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!_show)
			{
				_show = true;
				_prevCursorVisible = Cursor.visible;
				_prevCursorLock = Cursor.lockState;
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
				_volInitialized = false;
			}
		}

		public void Close()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (_show)
			{
				_show = false;
				Cursor.visible = _prevCursorVisible;
				Cursor.lockState = _prevCursorLock;
			}
		}

		public void Toggle()
		{
			if (_show)
			{
				Close();
			}
			else
			{
				Open();
			}
		}

		private static float SliderToVolume(int s, float baseline)
		{
			s = Mathf.Clamp(s, 1, 100);
			baseline = Mathf.Clamp01(baseline);
			if (s <= 50)
			{
				return Mathf.Clamp01(baseline * ((float)s / 50f));
			}
			float num = ((float)s - 50f) / 50f;
			return Mathf.Clamp01(baseline + (1f - baseline) * num);
		}
	}
	public class HolderUI : MonoBehaviour
	{
	}
	public static class UIHelpers
	{
		public static Rect AlignTopLeft(this Rect r, float x, float y)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return new Rect(x, y, ((Rect)(ref r)).width, ((Rect)(ref r)).height);
		}
	}
	public class UIHotkeyListener : MonoBehaviour
	{
		private void Awake()
		{
			Debug.Log((object)"[SteelSpeaker] Hotkey listener armed: BackQuote (`) only.");
		}

		private void Update()
		{
			try
			{
				if (Input.GetKeyDown((KeyCode)96))
				{
					Debug.Log((object)"[SteelSpeaker] BackQuote pressed; toggling UI.");
					EnsureUI().Toggle();
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[SteelSpeaker] Hotkey listener error: " + ex));
			}
		}

		private EscapeMenuVolumeUI EnsureUI()
		{
			EscapeMenuVolumeUI instance = EscapeMenuVolumeUI.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				return instance;
			}
			instance = ((Component)this).GetComponent<EscapeMenuVolumeUI>();
			if ((Object)(object)instance == (Object)null)
			{
				instance = ((Component)this).gameObject.AddComponent<EscapeMenuVolumeUI>();
			}
			return instance;
		}
	}
}
namespace SteelSpeaker.Prefabs
{
	public static class BundleLoader
	{
		private static AssetBundle? _bundle;

		public static GameObject LoadSpeakerPrefab()
		{
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bundle == (Object)null)
			{
				string text = Path.Combine(Paths.PluginPath, "SteelSpeaker", "AssetBundles");
				string[] array = new string[4] { "speakerbundle", "steelspeaker", "speakerbundle.bundle", "steelspeaker.bundle" };
				string[] array2 = array;
				foreach (string path in array2)
				{
					string text2 = Path.Combine(text, path);
					_bundle = AssetBundle.LoadFromFile(text2);
					if (!((Object)(object)_bundle != (Object)null))
					{
						continue;
					}
					Debug.Log((object)("[SteelSpeaker] Loaded AssetBundle: " + text2));
					try
					{
						ConfigEntry<bool>? debugDumpBundleAssets = ModConfig.DebugDumpBundleAssets;
						if (debugDumpBundleAssets != null && debugDumpBundleAssets.Value)
						{
							string[] allAssetNames = _bundle.GetAllAssetNames();
							Debug.Log((object)("[SteelSpeaker] Bundle assets:" + Environment.NewLine + string.Join("\n - ", allAssetNames)));
						}
					}
					catch
					{
					}
					break;
				}
				if ((Object)(object)_bundle == (Object)null)
				{
					Debug.LogError((object)("[SteelSpeaker] Failed to load AssetBundle. Tried: " + string.Join(", ", array) + " in " + text));
					throw new FileNotFoundException("AssetBundle load failed", Path.Combine(text, array[0]));
				}
			}
			GameObject val = _bundle.LoadAsset<GameObject>("Speaker3D");
			if ((Object)(object)val == (Object)null)
			{
				string[] allAssetNames2 = _bundle.GetAllAssetNames();
				string text3 = null;
				string[] array3 = allAssetNames2;
				foreach (string text4 in array3)
				{
					string text5 = text4.Replace("\\", "/").ToLowerInvariant();
					if (text5.EndsWith("speaker3d.prefab"))
					{
						text3 = text4;
						break;
					}
				}
				if (text3 == null)
				{
					Debug.LogError((object)("[SteelSpeaker] Prefab 'Speaker3D' not found in bundle. Assets: " + string.Join(", ", allAssetNames2)));
					throw new MissingReferenceException("Speaker3D prefab not found");
				}
				Debug.Log((object)("[SteelSpeaker] Using asset '" + text3 + "' from bundle."));
				val = _bundle.LoadAsset<GameObject>(text3);
			}
			return val;
		}
	}
	public class SpeakerBehavior : MonoBehaviour
	{
		public enum AttachTarget
		{
			None,
			LocalPlayer,
			Host
		}

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

			private object <>2__current;

			public float initialDelay;

			public SpeakerBehavior <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Expected O, but got Unknown
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0106: Expected O, but got Unknown
				int num = <>1__state;
				SpeakerBehavior speakerBehavior = <>4__this;
				Transform val;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (initialDelay > 0f)
					{
						Debug.Log((object)$"[SteelSpeaker] Waiting {initialDelay:F1}s before attempting attach...");
						<>2__current = (object)new WaitForSeconds(initialDelay);
						<>1__state = 1;
						return true;
					}
					goto IL_0079;
				case 1:
					<>1__state = -1;
					goto IL_0079;
				case 2:
					<>1__state = -1;
					return false;
				case 3:
					<>1__state = -1;
					goto IL_0079;
				case 4:
					{
						<>1__state = -1;
						goto IL_0079;
					}
					IL_0079:
					if (speakerBehavior.attachMode == AttachTarget.None)
					{
						<>2__current = speakerBehavior.RepositionNearPlayer(speakerBehavior.spawnDistance, speakerBehavior.spawnDelaySeconds, ensureVisual: true);
						<>1__state = 2;
						return true;
					}
					val = null;
					if (speakerBehavior.attachMode == AttachTarget.Host)
					{
						val = speakerBehavior.TryFindHostTransform();
						if ((Object)(object)val == (Object)null)
						{
							val = speakerBehavior.TryFindLocalPlayerTransform();
						}
					}
					else if (speakerBehavior.attachMode == AttachTarget.LocalPlayer)
					{
						val = speakerBehavior.TryFindLocalPlayerTransform();
					}
					if ((Object)(object)val != (Object)null)
					{
						speakerBehavior.EnsureVisual();
						speakerBehavior.AttachToTarget(val);
						<>2__current = (object)new WaitForSeconds(1f);
						<>1__state = 3;
						return true;
					}
					<>2__current = null;
					<>1__state = 4;
					return true;
				}
			}

			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 <RepositionNearPlayer>d__19 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float delaySeconds;

			public float distance;

			public bool ensureVisual;

			public SpeakerBehavior <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Expected O, but got Unknown
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00db: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_0101: Unknown result type (might be due to invalid IL or missing references)
				//IL_0106: Unknown result type (might be due to invalid IL or missing references)
				//IL_010b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0120: Unknown result type (might be due to invalid IL or missing references)
				//IL_015a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0166: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				SpeakerBehavior speakerBehavior = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (delaySeconds > 0f)
					{
						<>2__current = (object)new WaitForSeconds(delaySeconds);
						<>1__state = 1;
						return true;
					}
					<>2__current = null;
					<>1__state = 2;
					return true;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				Camera main = Camera.main;
				Vector3 val = (Vector3)(((Object)(object)main != (Object)null) ? (((Component)main).transform.position + ((Component)main).transform.forward * Mathf.Max(0.1f, distance)) : new Vector3(0f, 2f, 0f));
				RaycastHit val2 = default(RaycastHit);
				if (Physics.Raycast(val + Vector3.up * 2f, Vector3.down, ref val2, 10f, -1, (QueryTriggerInteraction)1))
				{
					val = ((RaycastHit)(ref val2)).point + Vector3.up * 0.02f;
				}
				if (ensureVisual)
				{
					speakerBehavior.EnsureVisual();
				}
				((Component)speakerBehavior).transform.position = val;
				Rigidbody val3 = (((Object)(object)speakerBehavior._visual != (Object)null) ? speakerBehavior._visual.GetComponent<Rigidbody>() : null) ?? ((Component)speakerBehavior).GetComponent<Rigidbody>();
				if ((Object)(object)val3 != (Object)null)
				{
					val3.velocity = Vector3.zero;
					val3.angularVelocity = Vector3.zero;
				}
				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();
			}
		}

		[Header("Spawn Timing")]
		public float spawnDelaySeconds = 5f;

		public float initialAttachDelaySeconds = 15f;

		public float spawnDistance = 10f;

		[Header("Auto Attach")]
		public AttachTarget attachMode = AttachTarget.Host;

		public string mountPath = "";

		public Vector3 mountLocalPos = new Vector3(0.2f, -0.1f, 0.05f);

		public Vector3 mountLocalEuler = new Vector3(0f, 90f, 0f);

		[Tooltip("Path to the ClipAnchor transform inside the speaker prefab")]
		public string clipAnchorPath = "ClipAnchor";

		private AudioManager _audio;

		private GameObject? _visual;

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

		public bool IsPlaying => _audio.IsPlaying;

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Instance = this;
			((Object)((Component)this).gameObject).name = "SteelSpeaker.Speaker";
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			if (ModConfig.InitialAttachDelay != null)
			{
				initialAttachDelaySeconds = ModConfig.InitialAttachDelay.Value;
			}
			_audio = new AudioManager(((Component)this).gameObject);
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			((MonoBehaviour)this).StopAllCoroutines();
			((MonoBehaviour)this).StartCoroutine(EnsureAttachedLoop(initialAttachDelaySeconds));
		}

		private void EnsureVisual()
		{
			//IL_0043: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_visual != (Object)null)
			{
				return;
			}
			try
			{
				GameObject val = BundleLoader.LoadSpeakerPrefab();
				_visual = Object.Instantiate<GameObject>(val, ((Component)this).transform);
				((Object)_visual).name = "SteelSpeaker3D";
				_visual.transform.localPosition = Vector3.zero;
				_visual.transform.localRotation = Quaternion.identity;
				_visual.transform.localScale = Vector3.one;
				AudioSource componentInChildren = _visual.GetComponentInChildren<AudioSource>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.spatialBlend = 1f;
					componentInChildren.rolloffMode = (AudioRolloffMode)0;
					componentInChildren.minDistance = 1f;
					componentInChildren.maxDistance = 20f;
				}
				FixupVisualRenderers(_visual);
				Rigidbody val2 = _visual.GetComponent<Rigidbody>() ?? _visual.AddComponent<Rigidbody>();
				Collider val3 = (Collider)(((object)_visual.GetComponent<Collider>()) ?? ((object)_visual.AddComponent<BoxCollider>()));
				if ((Object)(object)_visual.GetComponent<SpeakerInteractable>() == (Object)null)
				{
					_visual.AddComponent<SpeakerInteractable>();
				}
				LogVisualDiagnostics("EnsureVisual");
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[SteelSpeaker] Failed to spawn speaker visual: " + ex.Message));
			}
		}

		[IteratorStateMachine(typeof(<RepositionNearPlayer>d__19))]
		private IEnumerator RepositionNearPlayer(float distance, float delaySeconds, bool ensureVisual)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RepositionNearPlayer>d__19(0)
			{
				<>4__this = this,
				distance = distance,
				delaySeconds = delaySeconds,
				ensureVisual = ensureVisual
			};
		}

		[IteratorStateMachine(typeof(<EnsureAttachedLoop>d__20))]
		private IEnumerator EnsureAttachedLoop(float initialDelay)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <EnsureAttachedLoop>d__20(0)
			{
				<>4__this = this,
				initialDelay = initialDelay
			};
		}

		private void AttachToTarget(Transform player)
		{
			//IL_0026: 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_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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			if (ModConfig.PosX != null)
			{
				mountLocalPos = new Vector3(ModConfig.PosX.Value, ModConfig.PosY.Value, ModConfig.PosZ.Value);
				mountLocalEuler = new Vector3(ModConfig.RotX.Value, ModConfig.RotY.Value, ModConfig.RotZ.Value);
			}
			Transform val = player;
			Character componentInParent = ((Component)player).GetComponentInParent<Character>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				try
				{
					val = ((Component)componentInParent.GetBodypart((BodypartType)0)).transform;
				}
				catch
				{
				}
			}
			if (!string.IsNullOrEmpty(mountPath))
			{
				Transform val2 = player.Find(mountPath);
				if ((Object)(object)val2 != (Object)null)
				{
					val = val2;
				}
			}
			((Component)this).transform.SetParent(val, false);
			Transform val3 = val.Find("HookAnchor_SteelSpeaker");
			if ((Object)(object)val3 == (Object)null)
			{
				GameObject val4 = new GameObject("HookAnchor_SteelSpeaker");
				val3 = val4.transform;
				val3.SetParent(val, false);
			}
			Vector3 localPosition = mountLocalPos;
			if ((Object)(object)_visual != (Object)null)
			{
				Collider componentInChildren = _visual.GetComponentInChildren<Collider>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					Bounds bounds = componentInChildren.bounds;
					float num = Mathf.Max(((Bounds)(ref bounds)).extents.x, 0.1f) + 0.05f;
					((Vector3)(ref localPosition))..ctor(num, mountLocalPos.y, mountLocalPos.z);
				}
			}
			val3.localPosition = localPosition;
			val3.localRotation = Quaternion.Euler(mountLocalEuler);
			if ((Object)(object)_visual != (Object)null && !SpeakerAttach.AttachToHook(_visual, val3, clipAnchorPath))
			{
				Debug.LogWarning((object)"[SteelSpeaker] Joint attach failed; falling back to fixed mount.");
				_visual.transform.SetParent(((Component)this).transform, false);
				_visual.transform.localPosition = Vector3.zero;
				_visual.transform.localRotation = Quaternion.identity;
				Rigidbody component = _visual.GetComponent<Rigidbody>();
				Collider component2 = _visual.GetComponent<Collider>();
				if ((Object)(object)component != (Object)null)
				{
					component.isKinematic = true;
				}
				if ((Object)(object)component2 != (Object)null)
				{
					component2.enabled = false;
				}
			}
			if ((Object)(object)_visual != (Object)null)
			{
				ConfigEntry<bool>? forceDefaultLayer = ModConfig.ForceDefaultLayer;
				if (forceDefaultLayer != null && forceDefaultLayer.Value)
				{
					SetLayerRecursive(_visual.transform, 0);
					Debug.Log((object)"[SteelSpeaker] Forced visual to Default layer (debug option enabled).");
				}
				else
				{
					SetLayerRecursive(_visual.transform, ((Component)player).gameObject.layer);
				}
			}
			LogVisualDiagnostics("AttachToTarget");
			if ((Object)(object)_visual != (Object)null && _visual.GetComponentsInChildren<Renderer>(true).Length == 0)
			{
				GameObject val5 = GameObject.CreatePrimitive((PrimitiveType)3);
				Collider component3 = val5.GetComponent<Collider>();
				if (Object.op_Implicit((Object)(object)component3))
				{
					Object.Destroy((Object)(object)component3);
				}
				((Object)val5).name = "SteelSpeaker.DebugCube";
				val5.transform.SetParent(((Component)this).transform, false);
				val5.transform.localPosition = Vector3.zero;
				val5.transform.localRotation = Quaternion.identity;
				val5.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
				SetLayerRecursive(val5.transform, ((Component)player).gameObject.layer);
				Debug.LogWarning((object)"[SteelSpeaker] Visual prefab has no renderers; spawned debug cube placeholder.");
			}
			Debug.Log((object)"[SteelSpeaker] Attached speaker to player (joint-based).");
		}

		private void SetLayerRecursive(Transform t, int layer)
		{
			((Component)t).gameObject.layer = layer;
			for (int i = 0; i < t.childCount; i++)
			{
				SetLayerRecursive(t.GetChild(i), layer);
			}
		}

		private void LogVisualDiagnostics(string where)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_visual == (Object)null)
			{
				Debug.Log((object)("[SteelSpeaker] " + where + ": No visual object."));
				return;
			}
			Renderer[] componentsInChildren = _visual.GetComponentsInChildren<Renderer>(true);
			Debug.Log((object)$"[SteelSpeaker] {where}: Visual '{((Object)_visual).name}' active={_visual.activeInHierarchy}, layer={_visual.layer}({LayerMask.LayerToName(_visual.layer)}), renderers={componentsInChildren.Length}, pos={_visual.transform.position}");
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Renderer val = componentsInChildren[i];
				if (!((Object)(object)val == (Object)null))
				{
					Material[] sharedMaterials = val.sharedMaterials;
					string text = "<none>";
					if (sharedMaterials != null && sharedMaterials.Length != 0 && (Object)(object)sharedMaterials[0] != (Object)null && (Object)(object)sharedMaterials[0].shader != (Object)null)
					{
						text = ((Object)sharedMaterials[0].shader).name;
					}
					object[] obj = new object[9]
					{
						where,
						i,
						((Object)((Component)val).gameObject).name,
						val.enabled,
						((Component)val).gameObject.layer,
						LayerMask.LayerToName(((Component)val).gameObject.layer),
						null,
						null,
						null
					};
					Bounds bounds = val.bounds;
					obj[6] = ((Bounds)(ref bounds)).center;
					bounds = val.bounds;
					obj[7] = ((Bounds)(ref bounds)).extents;
					obj[8] = text;
					Debug.Log((object)string.Format("[SteelSpeaker] {0}: Renderer[{1}] '{2}', enabled={3}, layer={4}({5}), bounds.center={6}, extents={7}, shader={8}", obj));
				}
			}
		}

		private void FixupVisualRenderers(GameObject visual)
		{
			Renderer[] componentsInChildren = visual.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				val.enabled = true;
				Material[] sharedMaterials = val.sharedMaterials;
				if (sharedMaterials == null)
				{
					continue;
				}
				foreach (Material val2 in sharedMaterials)
				{
					if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null)
					{
						continue;
					}
					string text = ((Object)val2.shader).name ?? string.Empty;
					if (text.Contains("Universal", StringComparison.OrdinalIgnoreCase) || text.Contains("URP", StringComparison.OrdinalIgnoreCase) || text.Contains("HDRP", StringComparison.OrdinalIgnoreCase))
					{
						Shader val3 = Shader.Find("Standard");
						if ((Object)(object)val3 == (Object)null)
						{
							val3 = Shader.Find("Legacy Shaders/Diffuse");
						}
						if ((Object)(object)val3 != (Object)null)
						{
							val2.shader = val3;
						}
					}
				}
			}
		}

		public void ShowDebugCube()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			if (!((Object)(object)_visual != (Object)null) || _visual.GetComponentsInChildren<Renderer>(true).Length == 0)
			{
				GameObject val = GameObject.CreatePrimitive((PrimitiveType)3);
				Collider component = val.GetComponent<Collider>();
				if (Object.op_Implicit((Object)(object)component))
				{
					Object.Destroy((Object)(object)component);
				}
				((Object)val).name = "SteelSpeaker.DebugCube";
				val.transform.SetParent(((Component)this).transform, false);
				val.transform.localPosition = Vector3.zero;
				val.transform.localRotation = Quaternion.identity;
				val.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
			}
		}

		private Transform? TryFindLocalPlayerTransform()
		{
			try
			{
				if ((Object)(object)Character.localCharacter != (Object)null)
				{
					return ((Component)Character.localCharacter).transform;
				}
			}
			catch
			{
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return null;
			}
			if (!((Object)(object)((Component)main).transform.parent != (Object)null))
			{
				return ((Component)main).transform;
			}
			return ((Component)main).transform.parent;
		}

		private Transform? TryFindHostTransform()
		{
			try
			{
				if (PhotonNetwork.IsMasterClient)
				{
					return TryFindLocalPlayerTransform();
				}
				Character[] array = Object.FindObjectsOfType<Character>();
				Character[] array2 = array;
				foreach (Character val in array2)
				{
					PhotonView component = ((Component)val).GetComponent<PhotonView>();
					if ((Object)(object)component != (Object)null && component.Owner != null && component.Owner.IsMasterClient)
					{
						return ((Component)val).transform;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public void SetVolume(float v)
		{
			_audio.SetVolume(v);
		}

		public void PlayLocalFile(string fullPath)
		{
			_audio.PlayLocalFile((MonoBehaviour)(object)this, fullPath);
		}

		public void Stop()
		{
			_audio.Stop();
		}
	}
}
namespace SteelSpeaker.Networking
{
	[DisallowMultipleComponent]
	public class SpeakerNetSync : MonoBehaviourPun
	{
		private SpeakerManager _speaker;

		private void Awake()
		{
			_speaker = Object.FindObjectOfType<SpeakerManager>() ?? ((Component)this).gameObject.AddComponent<SpeakerManager>();
		}

		public void EnqueueTrack(YouTubeTrack t)
		{
			_speaker.QueueTrack(t);
			if (!PhotonNetwork.IsConnected)
			{
				return;
			}
			try
			{
				if (!PhotonNetwork.IsMasterClient && (Object)(object)((MonoBehaviourPun)this).photonView != (Object)null)
				{
					((MonoBehaviourPun)this).photonView.RPC("RpcEnqueue", (RpcTarget)2, new object[4] { t.VideoId, t.Title, t.Url, t.Duration });
				}
			}
			catch
			{
			}
		}

		[PunRPC]
		private void RpcEnqueue(string videoId, string title, string url, float duration, PhotonMessageInfo info)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				_speaker.QueueTrack(new YouTubeTrack(videoId, title, url, duration));
			}
		}

		public void RequestPlay()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsConnected)
			{
				((MonoBehaviourPun)this).photonView.RPC("RpcRequestPlay", (RpcTarget)2, Array.Empty<object>());
			}
			else
			{
				RpcRequestPlay(default(PhotonMessageInfo));
			}
		}

		[PunRPC]
		private void RpcRequestPlay(PhotonMessageInfo info)
		{
			if (!PhotonNetwork.IsConnected || PhotonNetwork.IsMasterClient)
			{
				SpeakerManager speakerManager = Object.FindObjectOfType<SpeakerManager>();
				if ((Object)(object)speakerManager != (Object)null)
				{
					speakerManager.StartOrResume();
				}
			}
		}

		public void BroadcastPlay(string videoId, string title, string mediaUrl, float duration)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsConnected)
			{
				((MonoBehaviourPun)this).photonView.RPC("RpcPlayNow", (RpcTarget)0, new object[5]
				{
					videoId,
					title,
					mediaUrl,
					duration,
					(float)PhotonNetwork.Time
				});
			}
			else
			{
				RpcPlayNow(videoId, title, mediaUrl, duration, 0f, default(PhotonMessageInfo));
			}
		}

		[PunRPC]
		private void RpcPlayNow(string videoId, string title, string mediaUrl, float duration, float networkTime, PhotonMessageInfo info)
		{
			YouTubeTrack track = new YouTubeTrack(videoId, title, mediaUrl, duration);
			SpeakerManager speakerManager = Object.FindObjectOfType<SpeakerManager>() ?? ((Component)this).gameObject.AddComponent<SpeakerManager>();
			speakerManager.StopPlayback();
			speakerManager.QueueTrack(track);
		}

		public void BroadcastStop()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsConnected)
			{
				((MonoBehaviourPun)this).photonView.RPC("RpcStop", (RpcTarget)0, Array.Empty<object>());
			}
			else
			{
				RpcStop(default(PhotonMessageInfo));
			}
		}

		[PunRPC]
		private void RpcStop(PhotonMessageInfo info)
		{
			SpeakerManager speakerManager = Object.FindObjectOfType<SpeakerManager>();
			if ((Object)(object)speakerManager != (Object)null)
			{
				speakerManager.StopPlayback();
			}
		}

		public void BroadcastPause(bool paused)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsConnected)
			{
				((MonoBehaviourPun)this).photonView.RPC("RpcPause", (RpcTarget)0, new object[1] { paused });
			}
			else
			{
				RpcPause(paused, default(PhotonMessageInfo));
			}
		}

		[PunRPC]
		private void RpcPause(bool paused, PhotonMessageInfo info)
		{
			SpeakerManager speakerManager = Object.FindObjectOfType<SpeakerManager>();
			if ((Object)(object)speakerManager != (Object)null)
			{
				speakerManager.Pause(paused);
			}
		}

		public void RequestSkip()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsConnected)
			{
				((MonoBehaviourPun)this).photonView.RPC("RpcRequestSkip", (RpcTarget)2, Array.Empty<object>());
			}
			else
			{
				RpcRequestSkip(default(PhotonMessageInfo));
			}
		}

		[PunRPC]
		private void RpcRequestSkip(PhotonMessageInfo info)
		{
			if (!PhotonNetwork.IsConnected || PhotonNetwork.IsMasterClient)
			{
				SpeakerManager speakerManager = Object.FindObjectOfType<SpeakerManager>();
				if ((Object)(object)speakerManager != (Object)null)
				{
					speakerManager.Skip();
				}
			}
		}

		public void RequestTogglePause()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsConnected)
			{
				((MonoBehaviourPun)this).photonView.RPC("RpcRequestTogglePause", (RpcTarget)2, Array.Empty<object>());
			}
			else
			{
				RpcRequestTogglePause(default(PhotonMessageInfo));
			}
		}

		[PunRPC]
		private void RpcRequestTogglePause(PhotonMessageInfo info)
		{
			if (PhotonNetwork.IsConnected && !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			SpeakerManager speakerManager = Object.FindObjectOfType<SpeakerManager>();
			if ((Object)(object)speakerManager != (Object)null)
			{
				speakerManager.TogglePause();
				if (PhotonNetwork.IsConnected)
				{
					BroadcastPause(speakerManager.IsPaused);
				}
			}
		}
	}
	public static class SyncMessages
	{
	}
}
namespace SteelSpeaker.Models
{
	public class YouTubeTrack
	{
		public string VideoId { get; set; }

		public string Title { get; set; }

		public string Url { get; set; }

		public float Duration { get; set; }

		public YouTubeTrack(string videoId, string title, string url, float duration)
		{
			VideoId = videoId;
			Title = title;
			Url = url;
			Duration = duration;
		}
	}
}
namespace SteelSpeaker.Managers
{
	public class AudioManager
	{
		private class DummyRunner : MonoBehaviour
		{
			public void Run(IEnumerator e)
			{
				((MonoBehaviour)this).StartCoroutine(e);
			}
		}

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

			private object <>2__current;

			public string url;

			public AudioType type;

			public AudioManager <>4__this;

			private UnityWebRequest <req>5__2;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: 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: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					int num = <>1__state;
					AudioManager audioManager = <>4__this;
					switch (num)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<req>5__2 = UnityWebRequestMultimedia.GetAudioClip(url, type);
						<>1__state = -3;
						<>2__current = <req>5__2.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -3;
						if ((int)<req>5__2.result != 1)
						{
							Debug.LogError((object)$"[SteelSpeaker] Audio load error: {<req>5__2.error} (code {<req>5__2.responseCode}) for {url}");
							result = false;
						}
						else
						{
							AudioClip content = DownloadHandlerAudioClip.GetContent(<req>5__2);
							if (!((Object)(object)content == (Object)null))
							{
								audioManager._audio.clip = content;
								audioManager._audio.Play();
								audioManager.IsPaused = false;
								Debug.Log((object)("[SteelSpeaker] Playing: " + url));
								<>m__Finally1();
								<req>5__2 = null;
								result = false;
								break;
							}
							Debug.LogError((object)"[SteelSpeaker] Null audio clip after load.");
							result = false;
						}
						<>m__Finally1();
						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 (<req>5__2 != null)
				{
					((IDisposable)<req>5__2).Dispose();
				}
			}

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

		private readonly AudioSource _audio;

		public bool IsPlaying
		{
			get
			{
				if ((Object)(object)_audio != (Object)null)
				{
					return _audio.isPlaying;
				}
				return false;
			}
		}

		public bool IsPaused { get; private set; }

		public AudioManager(GameObject host)
		{
			_audio = host.GetComponentInChildren<AudioSource>() ?? host.AddComponent<AudioSource>();
			_audio.playOnAwake = false;
			_audio.loop = false;
			_audio.spatialBlend = 1f;
			_audio.rolloffMode = (AudioRolloffMode)0;
			_audio.minDistance = 1f;
			_audio.maxDistance = 20f;
		}

		public void SetVolume(float v)
		{
			_audio.volume = Mathf.Clamp01(v);
		}

		public float GetVolume()
		{
			if (!((Object)(object)_audio != (Object)null))
			{
				return 1f;
			}
			return _audio.volume;
		}

		public void PlayLocalFile(MonoBehaviour runner, string fullPath)
		{
			//IL_0041: 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_0063: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!File.Exists(fullPath))
			{
				Debug.LogError((object)("[SteelSpeaker] File not found: " + fullPath));
				return;
			}
			string url = "file://" + fullPath.Replace("\\", "/");
			string text = Path.GetExtension(fullPath).ToLowerInvariant();
			AudioType type = (AudioType)0;
			switch (text)
			{
			case ".ogg":
				type = (AudioType)14;
				break;
			case ".wav":
				type = (AudioType)20;
				break;
			case ".mp3":
				type = (AudioType)13;
				break;
			}
			runner.StartCoroutine(LoadAndPlay(url, type));
		}

		public void PlayYouTubeUrl(string url)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			AudioType val = GuessAudioType(url);
			Debug.Log((object)$"[SteelSpeaker] Playing stream: {url} (type {val})");
			DummyRunner dummyRunner = ((Component)_audio).gameObject.GetComponent<DummyRunner>() ?? ((Component)_audio).gameObject.AddComponent<DummyRunner>();
			dummyRunner.Run(LoadAndPlay(url, val));
		}

		public void Stop()
		{
			if (_audio.isPlaying)
			{
				_audio.Stop();
			}
			IsPaused = false;
		}

		[IteratorStateMachine(typeof(<LoadAndPlay>d__13))]
		private IEnumerator LoadAndPlay(string url, AudioType type)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAndPlay>d__13(0)
			{
				<>4__this = this,
				url = url,
				type = type
			};
		}

		public void Pause()
		{
			if (!((Object)(object)_audio == (Object)null))
			{
				_audio.Pause();
				IsPaused = true;
			}
		}

		public void UnPause()
		{
			if (!((Object)(object)_audio == (Object)null))
			{
				_audio.UnPause();
				IsPaused = false;
			}
		}

		public void TogglePause()
		{
			if (IsPaused)
			{
				UnPause();
			}
			else
			{
				Pause();
			}
		}

		private static AudioType GuessAudioType(string url)
		{
			string text = url.ToLowerInvariant();
			if (!text.Contains(".ogg") && !text.Contains(".opus"))
			{
				if (!text.Contains(".mp3"))
				{
					if (!text.Contains(".wav"))
					{
						return (AudioType)13;
					}
					return (AudioType)20;
				}
				return (AudioType)13;
			}
			return (AudioType)14;
		}
	}
	public class SpeakerManager : MonoBehaviour
	{
		public static SpeakerManager Instance;

		private Queue<YouTubeTrack> _queue = new Queue<YouTubeTrack>();

		private AudioManager _audioManager;

		private bool _isPlaying;

		private bool _isPaused;

		private YouTubeTrack? _current;

		private SpeakerNetSync? _net;

		public bool IsPlaying => _isPlaying;

		public bool IsPaused => _isPaused;

		public YouTubeTrack? Current => _current;

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
				_audioManager = new AudioManager(((Component)this).gameObject);
				_net = Object.FindObjectOfType<SpeakerNetSync>();
			}
			else
			{
				Object.Destroy((Object)(object)this);
			}
		}

		public void QueueTrack(YouTubeTrack track)
		{
			_queue.Enqueue(track);
			Debug.Log((object)("[SteelSpeaker] Queued track: " + track.Title));
			if (!_isPlaying)
			{
				PlayNext();
			}
		}

		private void PlayNext()
		{
			if (_queue.Count == 0)
			{
				_isPlaying = false;
				return;
			}
			YouTubeTrack youTubeTrack = _queue.Dequeue();
			_isPlaying = true;
			_isPaused = false;
			_current = youTubeTrack;
			Debug.Log((object)("[SteelSpeaker] Now playing: " + youTubeTrack.Title));
			_audioManager.PlayYouTubeUrl(youTubeTrack.Url);
			try
			{
				if ((Object)(object)_net != (Object)null && PhotonNetwork.IsMasterClient)
				{
					_net.BroadcastPlay(youTubeTrack.VideoId, youTubeTrack.Title, youTubeTrack.Url, youTubeTrack.Duration);
				}
			}
			catch
			{
			}
		}

		public void StartOrResume()
		{
			if (_isPlaying)
			{
				if (_isPaused)
				{
					_audioManager.UnPause();
					_isPaused = false;
				}
			}
			else if (_queue.Count > 0)
			{
				PlayNext();
			}
		}

		public void StopPlayback()
		{
			_audioManager.Stop();
			_isPlaying = false;
			_isPaused = false;
			_current = null;
		}

		public void SetVolume(float volume)
		{
			_audioManager.SetVolume(volume);
		}

		public float GetVolume()
		{
			if (_audioManager == null)
			{
				return 1f;
			}
			return _audioManager.GetVolume();
		}

		private void Update()
		{
			if (_isPlaying && !_audioManager.IsPlaying && !_isPaused)
			{
				if (_queue.Count > 0)
				{
					PlayNext();
				}
				else
				{
					_isPlaying = false;
				}
			}
		}

		public void TogglePause()
		{
			if (_isPlaying)
			{
				if (_isPaused)
				{
					_audioManager.UnPause();
					_isPaused = false;
				}
				else
				{
					_audioManager.Pause();
					_isPaused = true;
				}
			}
		}

		public void Pause(bool paused)
		{
			if (_isPlaying)
			{
				if (paused && !_isPaused)
				{
					_audioManager.Pause();
					_isPaused = true;
				}
				else if (!paused && _isPaused)
				{
					_audioManager.UnPause();
					_isPaused = false;
				}
			}
		}

		public void Skip()
		{
			if (_queue.Count > 0)
			{
				PlayNext();
			}
			else
			{
				StopPlayback();
			}
		}

		public List<YouTubeTrack> GetQueueSnapshot()
		{
			return new List<YouTubeTrack>(_queue);
		}
	}
	public class YouTubeService
	{
		public class SearchResult
		{
			public string videoId = string.Empty;

			public string title = string.Empty;

			public float duration;
		}

		private readonly string _ytDlpPath;

		private readonly string _ffmpegPath;

		private bool? _ffmpegOkCache;

		private bool? _ytOkCache;

		public YouTubeService()
		{
			string path = Path.Combine(Paths.PluginPath, "SteelSpeaker", "bin");
			string text = Path.Combine(path, YtDlpFilename());
			_ytDlpPath = (File.Exists(text) ? text : YtDlpFilename());
			string text2 = Path.Combine(path, FFmpegFilename());
			_ffmpegPath = (File.Exists(text2) ? text2 : FFmpegFilename());
		}

		private static string YtDlpFilename()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			if ((int)Application.platform != 2 && (int)Application.platform != 7)
			{
				return "yt-dlp";
			}
			return "yt-dlp.exe";
		}

		private static string FFmpegFilename()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			if ((int)Application.platform != 2 && (int)Application.platform != 7)
			{
				return "ffmpeg";
			}
			return "ffmpeg.exe";
		}

		public bool HasBinary()
		{
			try
			{
				Process process = StartYtDlpProcess("--version");
				process.WaitForExit(2000);
				return process.ExitCode == 0;
			}
			catch
			{
				return false;
			}
		}

		public Task<bool> HasBinaryAsync()
		{
			return Task.Run(() => HasBinary());
		}

		public bool HasFfmpeg()
		{
			try
			{
				Process process = StartProcess(_ffmpegPath, "-version");
				process.WaitForExit(2000);
				return process.ExitCode == 0;
			}
			catch
			{
				return false;
			}
		}

		public Task<bool> HasFfmpegAsync()
		{
			return Task.Run(() => HasFfmpeg());
		}

		public List<SearchResult> Search(string query, int count = 10)
		{
			List<SearchResult> list = new List<SearchResult>();
			try
			{
				string args = $"ytsearch{Mathf.Clamp(count, 1, 50)}:{EscapeArg(query)} --dump-json --flat-playlist";
				Process process = StartYtDlpProcess(args);
				var (s, text) = ReadToEnd(process);
				if (process.ExitCode != 0)
				{
					Debug.LogError((object)("[SteelSpeaker] yt-dlp search failed: " + text));
					return list;
				}
				using StringReader stringReader = new StringReader(s);
				string jsonLine;
				while ((jsonLine = stringReader.ReadLine()) != null)
				{
					try
					{
						string text2 = ExtractJsonString(jsonLine, "id");
						string text3 = ExtractJsonString(jsonLine, "title");
						string s2 = ExtractJsonNumber(jsonLine, "duration");
						float duration = 0f;
						if (float.TryParse(s2, out var result))
						{
							duration = result;
						}
						if (!string.IsNullOrEmpty(text2))
						{
							list.Add(new SearchResult
							{
								videoId = text2,
								title = (string.IsNullOrEmpty(text3) ? text2 : text3),
								duration = duration
							});
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[SteelSpeaker] Search exception: {arg}");
			}
			return list;
		}

		public Task<List<SearchResult>> SearchAsync(string query, int count = 10)
		{
			string query2 = query;
			return Task.Run(() => Search(query2, count));
		}

		public string? ResolveStreamUrl(string videoIdOrUrl)
		{
			try
			{
				string args = "-f bestaudio -g " + EscapeArg(videoIdOrUrl);
				Process process = StartYtDlpProcess(args);
				var (text, text2) = ReadToEnd(process);
				if (process.ExitCode != 0)
				{
					Debug.LogError((object)("[SteelSpeaker] yt-dlp -g failed: " + text2));
					return null;
				}
				string text3 = text.Trim().Split('\n')[0].Trim();
				return string.IsNullOrWhiteSpace(text3) ? null : text3;
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[SteelSpeaker] ResolveStreamUrl exception: {arg}");
				return null;
			}
		}

		public Task<string?> ResolveStreamUrlAsync(string videoIdOrUrl)
		{
			string videoIdOrUrl2 = videoIdOrUrl;
			return Task.Run(() => ResolveStreamUrl(videoIdOrUrl2));
		}

		public string GetCacheDir()
		{
			string text = Path.Combine(Paths.PluginPath, "SteelSpeaker", "Cache");
			Directory.CreateDirectory(text);
			return text;
		}

		public long GetCacheSizeBytes()
		{
			try
			{
				string cacheDir = GetCacheDir();
				long num = 0L;
				string[] files = Directory.GetFiles(cacheDir, "*.*", SearchOption.TopDirectoryOnly);
				foreach (string fileName in files)
				{
					try
					{
						num += new FileInfo(fileName).Length;
					}
					catch
					{
					}
				}
				return num;
			}
			catch
			{
				return 0L;
			}
		}

		public void ClearCache()
		{
			try
			{
				string cacheDir = GetCacheDir();
				string[] files = Directory.GetFiles(cacheDir, "*.*", SearchOption.TopDirectoryOnly);
				foreach (string path in files)
				{
					try
					{
						File.Delete(path);
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
		}

		public string? EnsureLocalAudio(string videoIdOrUrl)
		{
			try
			{
				string cacheDir = GetCacheDir();
				string text = ((videoIdOrUrl.Contains("youtube.com") || videoIdOrUrl.Length > 11) ? ExtractVideoId(videoIdOrUrl) : videoIdOrUrl);
				string text2 = Path.Combine(cacheDir, text + ".mp3");
				if (File.Exists(text2))
				{
					return text2;
				}
				string args = "-f bestaudio -x --audio-format mp3 -o " + EscapeArg(Path.Combine(cacheDir, "%(id)s.%(ext)s")) + " " + EscapeArg(videoIdOrUrl);
				Process process = StartYtDlpProcess(args);
				var (text3, text4) = ReadToEnd(process);
				if (process.ExitCode != 0)
				{
					Debug.LogError((object)("[SteelSpeaker] yt-dlp download failed: " + text4));
					return null;
				}
				string text5 = ((videoIdOrUrl.Contains("youtube.com") || videoIdOrUrl.Length > 11) ? ExtractVideoId(videoIdOrUrl) : videoIdOrUrl);
				string[] files = Directory.GetFiles(cacheDir, text5 + ".mp3", SearchOption.TopDirectoryOnly);
				if (files.Length != 0)
				{
					return files[0];
				}
				string[] files2 = Directory.GetFiles(cacheDir, "*.mp3");
				if (files2.Length != 0)
				{
					Array.Sort(files2, (string a, string b) => File.GetLastWriteTimeUtc(b).CompareTo(File.GetLastWriteTimeUtc(a)));
					return files2[0];
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[SteelSpeaker] EnsureLocalAudio exception: {arg}");
			}
			return null;
		}

		private static string ExtractVideoId(string url)
		{
			try
			{
				if (url.Contains("v="))
				{
					int num = url.IndexOf("v=");
					string text = url.Substring(num + 2);
					int num2 = text.IndexOf('&');
					return (num2 >= 0) ? text.Substring(0, num2) : text;
				}
				int num3 = url.IndexOf("youtu.be/");
				if (num3 >= 0)
				{
					string text2 = url.Substring(num3 + 9);
					int num4 = text2.IndexOf('?');
					return (num4 >= 0) ? text2.Substring(0, num4) : text2;
				}
			}
			catch
			{
			}
			return url;
		}

		private Process StartYtDlpProcess(string args)
		{
			ProcessStartInfo processStartInfo = new ProcessStartInfo
			{
				FileName = _ytDlpPath,
				Arguments = args,
				UseShellExecute = false,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				CreateNoWindow = true,
				StandardOutputEncoding = Encoding.UTF8,
				StandardErrorEncoding = Encoding.UTF8
			};
			string directoryName = Path.GetDirectoryName(_ffmpegPath);
			if (!string.IsNullOrEmpty(directoryName) && Directory.Exists(directoryName))
			{
				processStartInfo.EnvironmentVariables["PATH"] = directoryName + Path.PathSeparator + (processStartInfo.EnvironmentVariables.ContainsKey("PATH") ? processStartInfo.EnvironmentVariables["PATH"] : string.Empty);
			}
			return Process.Start(processStartInfo);
		}

		private static Process StartProcess(string file, string args)
		{
			ProcessStartInfo startInfo = new ProcessStartInfo
			{
				FileName = file,
				Arguments = args,
				UseShellExecute = false,
				RedirectStandardOutput = true,
				RedirectStandardError = true,
				CreateNoWindow = true
			};
			return Process.Start(startInfo);
		}

		private static (string stdout, string stderr) ReadToEnd(Process p)
		{
			string item = p.StandardOutput.ReadToEnd();
			string item2 = p.StandardError.ReadToEnd();
			p.WaitForExit();
			return (item, item2);
		}

		private static string EscapeArg(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			if (s.Contains('"'))
			{
				s = s.Replace("\"", "\\\"");
			}
			return "\"" + s + "\"";
		}

		private static string ExtractJsonString(string jsonLine, string key)
		{
			string text = "\"" + key + "\":";
			int num = jsonLine.IndexOf(text);
			if (num < 0)
			{
				return string.Empty;
			}
			for (num += text.Length; num < jsonLine.Length && char.IsWhiteSpace(jsonLine[num]); num++)
			{
			}
			if (num >= jsonLine.Length || jsonLine[num] != '"')
			{
				return string.Empty;
			}
			num++;
			StringBuilder stringBuilder = new StringBuilder();
			while (num < jsonLine.Length)
			{
				char c = jsonLine[num++];
				if (c == '"')
				{
					break;
				}
				if (c == '\\' && num < jsonLine.Length)
				{
					char value = jsonLine[num++];
					stringBuilder.Append(value);
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static string ExtractJsonNumber(string jsonLine, string key)
		{
			string text = "\"" + key + "\":";
			int num = jsonLine.IndexOf(text);
			if (num < 0)
			{
				return string.Empty;
			}
			for (num += text.Length; num < jsonLine.Length && char.IsWhiteSpace(jsonLine[num]); num++)
			{
			}
			int num2 = num;
			for (; num < jsonLine.Length && (char.IsDigit(jsonLine[num]) || jsonLine[num] == '.'); num++)
			{
			}
			return jsonLine.Substring(num2, num - num2);
		}
	}
}
namespace SteelSpeaker.Interaction
{
	public class SpeakerInteractable : MonoBehaviour
	{
		[Header("Interact")]
		public KeyCode interactKey = (KeyCode)101;

		public float interactDistance = 2f;

		[Header("Mount")]
		public string mountPath = "";

		public Vector3 mountLocalPos = new Vector3(0.18f, -0.12f, 0.06f);

		public Vector3 mountLocalEuler = new Vector3(10f, 80f, 0f);

		private Rigidbody _rb;

		private Collider _col;

		private Transform? _holder;

		private AudioSource? _audio;

		private void Awake()
		{
			_rb = ((Component)this).GetComponent<Rigidbody>();
			if ((Object)(object)_rb == (Object)null)
			{
				_rb = ((Component)this).gameObject.AddComponent<Rigidbody>();
			}
			_col = ((Component)this).GetComponent<Collider>();
			if ((Object)(object)_col == (Object)null)
			{
				_col = (Collider)(object)((Component)this).gameObject.AddComponent<BoxCollider>();
			}
			_audio = ((Component)this).GetComponentInChildren<AudioSource>();
		}

		private void Update()
		{
			//IL_0021: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)this).GetComponent<ConfigurableJoint>() != (Object)null)
			{
				return;
			}
			Transform val = FindLocalPlayer();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float num = Vector3.Distance(val.position, ((Component)this).transform.position);
			if ((Object)(object)_holder == (Object)null)
			{
				if (num <= interactDistance && Input.GetKeyDown(interactKey))
				{
					Pickup(val);
				}
			}
			else if (Input.GetMouseButtonDown(1) || Input.GetKeyDown((KeyCode)103))
			{
				Drop(val);
			}
		}

		private Transform? FindLocalPlayer()
		{
			Camera main = Camera.main;
			if (!Object.op_Implicit((Object)(object)main))
			{
				return null;
			}
			return ((Component)main).transform;
		}

		private Transform GetMount(Transform player)
		{
			if (!string.IsNullOrEmpty(mountPath))
			{
				Transform val = player.Find(mountPath);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return player;
		}

		private void Pickup(Transform player)
		{
			//IL_003e: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			_holder = GetMount(player);
			_rb.isKinematic = true;
			_col.enabled = false;
			((Component)this).transform.SetParent(_holder, false);
			((Component)this).transform.localPosition = mountLocalPos;
			((Component)this).transform.localRotation = Quaternion.Euler(mountLocalEuler);
			if (Object.op_Implicit((Object)(object)_audio))
			{
				_audio.spatialBlend = 1f;
			}
		}

		private void Drop(Transform player)
		{
			//IL_0026: 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_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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.SetParent((Transform)null, true);
			_rb.isKinematic = false;
			_col.enabled = true;
			Vector3 forward = player.forward;
			_rb.AddForce(forward * 2.5f + Vector3.up * 1f, (ForceMode)1);
			_holder = null;
		}
	}
}
namespace SteelSpeaker.Dev
{
	public class MountOffsetTuner : MonoBehaviour
	{
		private bool _active;

		private float _step = 0.01f;

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)287))
			{
				_active = !_active;
			}
			if (Input.GetKeyDown((KeyCode)288))
			{
				SpeakerBehavior.Instance?.ShowDebugCube();
			}
			if (_active)
			{
				bool flag = false;
				if (Input.GetKey((KeyCode)106))
				{
					ConfigEntry<float>? posX = ModConfig.PosX;
					posX.Value -= _step;
					flag = true;
				}
				if (Input.GetKey((KeyCode)108))
				{
					ConfigEntry<float>? posX2 = ModConfig.PosX;
					posX2.Value += _step;
					flag = true;
				}
				if (Input.GetKey((KeyCode)105))
				{
					ConfigEntry<float>? posZ = ModConfig.PosZ;
					posZ.Value += _step;
					flag = true;
				}
				if (Input.GetKey((KeyCode)107))
				{
					ConfigEntry<float>? posZ2 = ModConfig.PosZ;
					posZ2.Value -= _step;
					flag = true;
				}
				if (Input.GetKey((KeyCode)117))
				{
					ConfigEntry<float>? posY = ModConfig.PosY;
					posY.Value += _step;
					flag = true;
				}
				if (Input.GetKey((KeyCode)111))
				{
					ConfigEntry<float>? posY2 = ModConfig.PosY;
					posY2.Value -= _step;
					flag = true;
				}
				if (Input.GetKey((KeyCode)104))
				{
					ConfigEntry<float>? rotY = ModConfig.RotY;
					rotY.Value -= _step * 50f;
					flag = true;
				}
				if (Input.GetKey((KeyCode)110))
				{
					ConfigEntry<float>? rotY2 = ModConfig.RotY;
					rotY2.Value += _step * 50f;
					flag = true;
				}
				if (Input.GetKey((KeyCode)121))
				{
					ConfigEntry<float>? rotX = ModConfig.RotX;
					rotX.Value -= _step * 50f;
					flag = true;
				}
				if (Input.GetKey((KeyCode)103))
				{
					ConfigEntry<float>? rotX2 = ModConfig.RotX;
					rotX2.Value += _step * 50f;
					flag = true;
				}
				if (Input.GetKey((KeyCode)116))
				{
					ConfigEntry<float>? rotZ = ModConfig.RotZ;
					rotZ.Value -= _step * 50f;
					flag = true;
				}
				if (Input.GetKey((KeyCode)98))
				{
					ConfigEntry<float>? rotZ2 = ModConfig.RotZ;
					rotZ2.Value += _step * 50f;
					flag = true;
				}
				if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)43))
				{
					_step = Mathf.Min(_step * 2f, 0.2f);
				}
				if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)95))
				{
					_step = Mathf.Max(_step * 0.5f, 0.0025f);
				}
				if (Input.GetKeyDown((KeyCode)115))
				{
					ModConfig.Save();
				}
				if (flag)
				{
					ApplyToSpeaker();
				}
			}
		}

		private void ApplyToSpeaker()
		{
			//IL_0034: 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)
			SpeakerBehavior instance = SpeakerBehavior.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				((Component)instance).transform.localPosition = new Vector3(ModConfig.PosX.Value, ModConfig.PosY.Value, ModConfig.PosZ.Value);
				((Component)instance).transform.localRotation = Quaternion.Euler(ModConfig.RotX.Value, ModConfig.RotY.Value, ModConfig.RotZ.Value);
			}
		}

		private void OnGUI()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (_active)
			{
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(12f, 12f, 360f, 140f);
				GUI.color = new Color(0f, 0f, 0f, 0.6f);
				GUI.Box(val, GUIContent.none);
				GUI.color = Color.white;
				GUILayout.BeginArea(val);
				GUILayout.Label("SteelSpeaker Mount Tuner (F6 to toggle)", Array.Empty<GUILayoutOption>());
				GUILayout.Label($"Step: {_step:F3} | Pos X:{ModConfig.PosX.Value:F3} Y:{ModConfig.PosY.Value:F3} Z:{ModConfig.PosZ.Value:F3}", Array.Empty<GUILayoutOption>());
				GUILayout.Label($"Rot X:{ModConfig.RotX.Value:F1} Y:{ModConfig.RotY.Value:F1} Z:{ModConfig.RotZ.Value:F1}", Array.Empty<GUILayoutOption>());
				GUILayout.Label("Move: J/L=X-,X+ | I/K=Z+,Z- | U/O=Y+,Y-", Array.Empty<GUILayoutOption>());
				GUILayout.Label("Rotate: H/N=Yaw | Y/G=Pitch | T/B=Roll | +/- step", Array.Empty<GUILayoutOption>());
				GUILayout.EndArea();
			}
		}
	}
}
namespace SteelSpeaker.Config
{
	public static class ModConfig
	{
		public static ConfigFile? File;

		public static ConfigEntry<float>? PosX;

		public static ConfigEntry<float>? PosY;

		public static ConfigEntry<float>? PosZ;

		public static ConfigEntry<float>? RotX;

		public static ConfigEntry<float>? RotY;

		public static ConfigEntry<float>? RotZ;

		public static ConfigEntry<float>? InitialAttachDelay;

		public static ConfigEntry<string>? ToggleKey;

		public static ConfigEntry<KeyboardShortcut>? UIToggleShortcut;

		public static ConfigEntry<bool>? ForceDefaultLayer;

		public static ConfigEntry<bool>? DebugDumpBundleAssets;

		public static void Init(ConfigFile cfg)
		{
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			File = cfg;
			PosX = cfg.Bind<float>("Mount", "PosX", 0.2f, "Local X offset from hip mount");
			PosY = cfg.Bind<float>("Mount", "PosY", -0.1f, "Local Y offset from hip mount");
			PosZ = cfg.Bind<float>("Mount", "PosZ", 0.05f, "Local Z offset from hip mount");
			RotX = cfg.Bind<float>("Mount", "RotX", 0f, "Local rotation X (pitch) in degrees");
			RotY = cfg.Bind<float>("Mount", "RotY", 90f, "Local rotation Y (yaw) in degrees");
			RotZ = cfg.Bind<float>("Mount", "RotZ", 0f, "Local rotation Z (roll) in degrees");
			InitialAttachDelay = cfg.Bind<float>("General", "InitialAttachDelaySeconds", 15f, "Wait time before first attach after scene load");
			ToggleKey = cfg.Bind<string>("General", "UIToggleKey", "F10", "Deprecated: string key name. Prefer UIToggleShortcut.");
			UIToggleShortcut = cfg.Bind<KeyboardShortcut>("General", "UIToggleShortcut", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Key (with optional modifiers) to toggle SteelSpeaker UI.");
			ForceDefaultLayer = cfg.Bind<bool>("Debug", "ForceDefaultLayer", false, "If true, forces the speaker visual to Unity's Default layer (0) to bypass camera culling masks.");
			DebugDumpBundleAssets = cfg.Bind<bool>("Debug", "DumpBundleAssetsOnLoad", false, "If true, logs all asset names found in the loaded AssetBundle.");
		}

		public static void Save()
		{
			ConfigFile? file = File;
			if (file != null)
			{
				file.Save();
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}