Decompiled source of BigScreen v1.0.4

BepInEx/plugins/BigScreen/BigScreen.dll

Decompiled 4 days ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BigScreen.Dev;
using BigScreen.Net;
using BigScreen.Resolve;
using BigScreen.UI;
using BigScreen.Util;
using BigScreen.Video;
using BigScreen.World;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Mirror;
using Rewired;
using UnityEngine;
using UnityEngine.Bindings;
using UnityEngine.Rendering;
using UnityEngine.Video;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BigScreen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A shared in-world screen for watching YouTube together in Big Walk. Everyone with the mod sees and hears the same video, in sync.")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4+25b00765c6277148e11afe9d111f97cf99e08cc8")]
[assembly: AssemblyProduct("BigScreen")]
[assembly: AssemblyTitle("BigScreen")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte flag)
		{
			NullableFlags = new byte[1] { flag };
		}

		public NullableAttribute(byte[] flags)
		{
			NullableFlags = flags;
		}
	}
	[AttributeUsage(AttributeTargets.Module | 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 flag)
		{
			Flag = flag;
		}
	}
}
namespace BigScreen
{
	public class BigScreenController : MonoBehaviour
	{
		private string _lastError;

		private float _lastErrorAt = -1000f;

		private ControlPanel _panel;

		private bool _panelVisible;

		private CursorLockMode _priorLock = (CursorLockMode)1;

		private bool _priorCursorVisible;

		private ScreenObject _screen;

		private IVideoBackend _video;

		private string _loadedPageUrl;

		private string _resolvingPageUrl;

		private CancellationTokenSource _resolveCts;

		private bool _pendingInitialSeek;

		private float _lastSeekAt = -100f;

		private float _nextDiag;

		private bool _wasInSession;

		private bool _configDirty;

		private Vector3 _lastAimOrigin;

		private float _nextConfigSave;

		private const float ConfigSaveIntervalSeconds = 3f;

		private const float MinSecondsBetweenSeeks = 2.5f;

		private const float ConsoleErrorSeconds = 8f;

		internal static BigScreenController Instance { get; private set; }

		internal SyncSession Session { get; } = new SyncSession();

		internal string StatusLine { get; private set; } = "Idle.";

		internal string LastError
		{
			get
			{
				return _lastError;
			}
			private set
			{
				_lastError = value;
				_lastErrorAt = Time.unscaledTime;
			}
		}

		internal double LastDrift { get; private set; }

		internal double LocalVideoTime
		{
			get
			{
				if (_video == null || !_video.IsReady)
				{
					return 0.0;
				}
				return _video.Time;
			}
		}

		internal double LocalVideoDuration
		{
			get
			{
				if (_video == null || !_video.IsReady)
				{
					return 0.0;
				}
				return _video.Duration;
			}
		}

		internal bool CanControl
		{
			get
			{
				if (!Session.IsHost)
				{
					if (Session.IsConnectedClient)
					{
						return Session.State.GuestsCanControl;
					}
					return false;
				}
				return true;
			}
		}

		public BigScreenController(IntPtr ptr)
			: base(ptr)
		{
		}//IL_0023: Unknown result type (might be due to invalid IL or missing references)


		private void Awake()
		{
			Instance = this;
			_panel = new ControlPanel(this);
			Session.StateChanged += OnStateChanged;
			Session.RequestReceived += OnGuestRequest;
		}

		private void Update()
		{
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			MainThread.Drain();
			bool flag2 = default(bool);
			try
			{
				HandleInput();
				Session.Tick();
				AutoStart.Tick(this);
				bool flag = NetworkServer.active || NetworkClient.active;
				if (_wasInSession && !flag)
				{
					ResetSession("left lobby");
				}
				_wasInSession = flag;
				if (flag)
				{
					ReconcileScreen();
					ReconcileVideo();
					FollowTimeline();
					Vector3 screenPosition = ((_screen != null) ? _screen.Root.transform.position : Vector3.zero);
					SleepGuard.Tick(screenPosition, _screen != null, Session.State.Playing);
					CrosshairGuard.Tick(screenPosition, _screen != null, Session.State.Playing);
				}
				FlushConfigIfDue();
				if (Plugin.Diagnostics.Value && Time.unscaledTime >= _nextDiag)
				{
					_nextDiag = Time.unscaledTime + 2f;
					ManualLogSource log = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(126, 18, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[diag] host=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Session.IsHost);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" client=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(NetworkClient.isConnected);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" peers=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Session.ModdedPeerCount);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("rev=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Session.State.Revision);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" screen=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(_screen != null);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" url=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Session.State.VideoUrl);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("playing=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Session.State.Playing);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ready=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool?>(_video?.IsReady);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" t=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(LocalVideoTime, "F1");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" drift=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(LastDrift, "F2");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("nettime=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(SafeNetTime(), "F1");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" conv_failed=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(MirrorChannel.ConversionFailed);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("console=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_screen?.Console?.DescribeAim(_lastAimOrigin) ?? "none");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("awake=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(SleepGuard.Suppressing);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" xhair=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(CrosshairGuard.Hidden ? "hidden" : "shown");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("idle=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(CrosshairGuard.SecondsIdle, "F0");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(CrosshairGuard.DelaySeconds, "F0");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s(");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(CrosshairGuard.DelaySource);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
					}
					log.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(15, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Update failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val2);
			}
		}

		private void OnGUI()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (!_panelVisible)
			{
				return;
			}
			try
			{
				_panel.Draw();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(19, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Panel draw failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		private void HandleInput()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(Plugin.ToggleUiKey.Value))
			{
				SetPanelVisible(!_panelVisible);
			}
			if (_panelVisible)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		internal void SetPanelVisible(bool visible)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (visible != _panelVisible)
			{
				_panelVisible = visible;
				if (visible)
				{
					_priorLock = Cursor.lockState;
					_priorCursorVisible = Cursor.visible;
				}
				else
				{
					Cursor.lockState = _priorLock;
					Cursor.visible = _priorCursorVisible;
				}
			}
		}

		internal void UserPlaceScreen()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_00e7: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_003a: 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)
			//IL_0072: 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_00aa: 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)
			if (!TryGetLocalPlayerPose(out var position, out var forward))
			{
				LastError = "Could not find your character.";
				return;
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 6, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Your position: (");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(position.x, "F2");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(position.y, "F2");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(position.z, "F2");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")  facing (");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(forward.x, "F2");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(forward.y, "F2");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(forward.z, "F2");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
			}
			log.LogInfo(val);
			Vector3 val2 = new Vector3(forward.x, 0f, forward.z);
			Quaternion val3 = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up);
			float y = ((Quaternion)(ref val3)).eulerAngles.y;
			PlaceScreenForViewer(position, y);
		}

		internal void PlaceScreenForViewer(Vector3 viewerPosition, float viewerYaw)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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)
			Vector3 val = Quaternion.Euler(0f, viewerYaw, 0f) * Vector3.forward;
			PlaceScreenAt(viewerPosition + val * 4f, viewerYaw);
		}

		internal void PlaceScreenAt(Vector3 position, float yaw)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			Apply(new Request
			{
				Action = Protocol.Action.Place,
				Position = position,
				Yaw = yaw
			});
		}

		internal void UserRemoveScreen()
		{
			Apply(new Request
			{
				Action = Protocol.Action.Remove
			});
		}

		internal void UserNudgeScreen(float rightMeters, float forwardMeters)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			SyncState state = Session.State;
			if (!state.HasScreen)
			{
				LastError = "There is no screen to move.";
				return;
			}
			Vector3 val = Quaternion.Euler(0f, state.ScreenYaw, 0f) * new Vector3(rightMeters, 0f, forwardMeters);
			PlaceScreenAt(state.ScreenPosition + val, state.ScreenYaw);
		}

		internal void UserNudgeScreenHeight(float deltaMeters)
		{
			if (!Session.IsHost)
			{
				StatusLine = "The host sets the screen height.";
				return;
			}
			float value = Mathf.Clamp(Plugin.ScreenGroundClearance.Value + deltaMeters, -2f, 5f);
			Plugin.ScreenGroundClearance.Value = value;
			_configDirty = true;
			StatusLine = $"Screen height {value:F2} m.";
		}

		internal void UserSetSpawnHere()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetLocalPlayerPose(out var position, out var forward))
			{
				LastError = "Could not find your character.";
				return;
			}
			Quaternion val = Quaternion.LookRotation(forward, Vector3.up);
			float y = ((Quaternion)(ref val)).eulerAngles.y;
			string text = string.Format(CultureInfo.InvariantCulture, "{0:F2},{1:F2},{2:F2},{3:F1}", position.x, position.y, position.z, y);
			Plugin.SpawnPosition.Value = text;
			_configDirty = true;
			StatusLine = "Spawn set to " + text;
			Plugin.Log.LogInfo((object)("Spawn set to " + text));
		}

		internal void UserLoad(string pageUrl)
		{
			Trace.Write("UserLoad enter: " + pageUrl);
			pageUrl = (pageUrl ?? "").Trim();
			if (!YtDlp.LooksLikeUrl(pageUrl))
			{
				LastError = "Enter a full URL starting with https://";
				return;
			}
			LastError = null;
			if (!Session.State.HasScreen)
			{
				UserPlaceScreen();
			}
			Trace.Write("UserLoad: about to Apply");
			Apply(new Request
			{
				Action = Protocol.Action.Load,
				Text = pageUrl
			});
			Trace.Write("UserLoad: Apply returned");
		}

		internal void UserTogglePlay()
		{
			Apply(new Request
			{
				Action = (Session.State.Playing ? Protocol.Action.Pause : Protocol.Action.Play)
			});
		}

		internal void UserSeekRelative(double delta)
		{
			Apply(new Request
			{
				Action = Protocol.Action.SeekTo,
				Value = Session.State.ExpectedVideoTime(SafeNetTime()) + delta
			});
		}

		internal void UserSeekTo(double seconds)
		{
			Apply(new Request
			{
				Action = Protocol.Action.SeekTo,
				Value = seconds
			});
		}

		internal void UserStop()
		{
			Apply(new Request
			{
				Action = Protocol.Action.Stop
			});
		}

		internal void UserUpdateYtDlp()
		{
			StatusLine = "Updating yt-dlp...";
			RunOffThread("BigScreen-ytdlp-update", delegate
			{
				string msg = YtDlp.Update(CancellationToken.None);
				MainThread.Post(delegate
				{
					StatusLine = "yt-dlp: " + msg;
					Plugin.Log.LogInfo((object)("yt-dlp update: " + msg));
				});
			});
		}

		internal void ApplyLocalAudioConfig()
		{
			_screen?.ApplyAudioConfig();
			_video?.SetVolume(Plugin.Volume.Value);
		}

		private void Apply(Request req)
		{
			if (Session.IsHost)
			{
				ApplyOnHost(req);
			}
			else if (Session.IsConnectedClient)
			{
				if (!Session.State.GuestsCanControl)
				{
					LastError = "The host has not enabled guest control.";
				}
				else if (!Session.SendRequest(req))
				{
					LastError = "Could not send the request to the host.";
				}
			}
		}

		private void ApplyOnHost(Request req)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			double now = SafeNetTime();
			switch (req.Action)
			{
			case Protocol.Action.Place:
				Session.Mutate(delegate(SyncState s)
				{
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					s.HasScreen = true;
					s.ScreenPosition = req.Position;
					s.ScreenYaw = req.Yaw;
				});
				RememberScreenPose(req.Position, req.Yaw);
				break;
			case Protocol.Action.Remove:
				Session.Mutate(delegate(SyncState s)
				{
					s.HasScreen = false;
					s.VideoUrl = "";
					s.Title = "";
					s.Playing = false;
					s.AnchorVideoTime = 0.0;
				});
				break;
			case Protocol.Action.Load:
				Session.Mutate(delegate(SyncState s)
				{
					s.VideoUrl = req.Text;
					s.Title = "";
					s.Playing = false;
					s.AnchorVideoTime = 0.0;
					s.AnchorNetTime = now;
				});
				break;
			case Protocol.Action.Play:
				if (!string.IsNullOrEmpty(Session.State.VideoUrl))
				{
					Session.Mutate(delegate(SyncState s)
					{
						s.AnchorVideoTime = s.ExpectedVideoTime(now);
						s.AnchorNetTime = now;
						s.Playing = true;
					});
				}
				break;
			case Protocol.Action.Pause:
				Session.Mutate(delegate(SyncState s)
				{
					s.AnchorVideoTime = s.ExpectedVideoTime(now);
					s.AnchorNetTime = now;
					s.Playing = false;
				});
				break;
			case Protocol.Action.SeekTo:
				Session.Mutate(delegate(SyncState s)
				{
					double num = Math.Max(0.0, req.Value);
					double localVideoDuration = LocalVideoDuration;
					if (localVideoDuration > 0.0 && num > localVideoDuration - 0.5)
					{
						num = Math.Max(0.0, localVideoDuration - 0.5);
					}
					s.AnchorVideoTime = num;
					s.AnchorNetTime = now;
				});
				break;
			case Protocol.Action.Stop:
				Session.Mutate(delegate(SyncState s)
				{
					s.VideoUrl = "";
					s.Title = "";
					s.Playing = false;
					s.AnchorVideoTime = 0.0;
				});
				break;
			}
		}

		private void RememberScreenPose(Vector3 position, float yaw)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			Plugin.ScreenPose.Value = string.Format(CultureInfo.InvariantCulture, "{0:F2},{1:F2},{2:F2},{3:F1}", position.x, position.y, position.z, yaw);
			_configDirty = true;
		}

		private void FlushConfigIfDue()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			if (!_configDirty || Time.unscaledTime < _nextConfigSave)
			{
				return;
			}
			_configDirty = false;
			_nextConfigSave = Time.unscaledTime + 3f;
			try
			{
				((BasePlugin)Plugin.Instance).Config.Save();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Saving the config failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
		}

		private bool OnGuestRequest(Request req, NetworkConnectionToClient from)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(18, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Guest ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int?>((from != null) ? new int?(((NetworkConnection)from).connectionId) : ((int?)null));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" requested ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Protocol.Action>(req.Action);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
			}
			log.LogInfo(val);
			ApplyOnHost(req);
			return true;
		}

		private void OnStateChanged(SyncState s)
		{
			_lastSeekAt = -100f;
		}

		private void ReconcileScreen()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: 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_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			SyncState state = Session.State;
			if (state.HasScreen && _screen == null)
			{
				try
				{
					_screen = ScreenObject.Create(state.ScreenPosition, state.ScreenYaw, state.ScreenWidth, Plugin.RenderWidth.Value, Plugin.RenderHeight.Value);
					_video = new UnityVideoBackend(_screen.Root, _screen.Audio, _screen.Texture);
					_video.SetVolume(Plugin.Volume.Value);
					_loadedPageUrl = null;
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(18, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Screen placed at ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Vector3>(state.ScreenPosition);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log.LogInfo(val);
				}
				catch (Exception ex)
				{
					LastError = "Could not create the screen: " + ex.Message;
					Plugin.Log.LogError((object)(LastError + "\n" + ex));
					_screen?.Dispose();
					_screen = null;
					if (Session.IsHost)
					{
						Session.Mutate(delegate(SyncState x)
						{
							x.HasScreen = false;
						});
					}
				}
			}
			else if (!state.HasScreen && _screen != null)
			{
				TearDownScreen();
			}
			else if (_screen != null && (Object)(object)_screen.Root != (Object)null)
			{
				Vector3 val2 = _screen.Root.transform.position - state.ScreenPosition;
				if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f || Mathf.Abs(Mathf.DeltaAngle(_screen.Root.transform.eulerAngles.y, state.ScreenYaw)) > 0.1f)
				{
					_screen.MoveTo(state.ScreenPosition, state.ScreenYaw);
				}
			}
			_screen?.ApplyLayout(state.ScreenClearance);
			TickConsole();
		}

		private void TickConsole()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			ControlConsole controlConsole = _screen?.Console;
			if (controlConsole == null)
			{
				return;
			}
			Vector3 origin;
			Vector3 direction;
			bool flag = TryGetAimRay(out origin, out direction);
			_lastAimOrigin = (flag ? origin : Vector3.zero);
			KeyCode value = Plugin.InteractKey.Value;
			bool flag2 = (int)value != 0 && Input.GetKeyDown(value);
			bool flag3 = Input.GetMouseButtonDown(0) || GameInput.InteractPressed();
			if (Plugin.Diagnostics.Value && Input.anyKeyDown)
			{
				ManualLogSource log = Plugin.Log;
				bool flag4 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(57, 4, ref flag4);
				if (flag4)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Input: anyKeyDown  interact(");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<KeyCode>(Plugin.InteractKey.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("click/interact=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag3);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" panelOpen=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(_panelVisible);
				}
				log.LogInfo(val);
			}
			bool pressed = (flag2 || flag3) && !_panelVisible;
			if ((flag2 || flag3) && _panelVisible)
			{
				Plugin.Log.LogInfo((object)"Console: press ignored because the F8 panel is open.");
			}
			controlConsole.Tick(this, flag, origin, direction, Session.State.Playing, ConsoleStatus(), Plugin.ConsoleReach.Value, pressed);
		}

		private ControlConsole.Status ConsoleStatus()
		{
			if (!string.IsNullOrEmpty(LastError) && Time.unscaledTime - _lastErrorAt < 8f)
			{
				return ControlConsole.Status.Error;
			}
			if (string.IsNullOrEmpty(Session.State.VideoUrl))
			{
				return ControlConsole.Status.Idle;
			}
			if (_video == null || !_video.IsReady)
			{
				return ControlConsole.Status.Working;
			}
			return ControlConsole.Status.Ready;
		}

		private static bool TryGetAimRay(out Vector3 origin, out Vector3 direction)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			origin = Vector3.zero;
			direction = Vector3.forward;
			try
			{
				PlayerCharacter localPlayerCharacter = WorldManager.localPlayerCharacter;
				if ((Object)(object)localPlayerCharacter == (Object)null)
				{
					return false;
				}
				Transform cameraTransform = localPlayerCharacter.cameraTransform;
				if ((Object)(object)cameraTransform == (Object)null)
				{
					return false;
				}
				origin = cameraTransform.position;
				direction = cameraTransform.forward;
				return true;
			}
			catch
			{
				return false;
			}
		}

		internal void ReportConsoleError(string message)
		{
			LastError = message;
			Plugin.Log.LogWarning((object)("Console: " + message));
		}

		private void ReconcileVideo()
		{
			SyncState state = Session.State;
			if (_video == null)
			{
				return;
			}
			string text = state.VideoUrl ?? "";
			if (text.Length == 0)
			{
				if (_loadedPageUrl != null || _resolvingPageUrl != null)
				{
					CancelResolve();
					_video.Stop();
					_screen?.ClearToIdle();
					_loadedPageUrl = null;
					StatusLine = "Screen idle.";
				}
				_video.Tick();
			}
			else
			{
				if (text != _loadedPageUrl && text != _resolvingPageUrl)
				{
					StartResolve(text);
				}
				_video.Tick();
				if (_video.Error != null && LastError != _video.Error)
				{
					LastError = _video.Error;
				}
			}
		}

		private void StartResolve(string pageUrl)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			Trace.Write("StartResolve enter");
			CancelResolve();
			_resolvingPageUrl = pageUrl;
			_resolveCts = new CancellationTokenSource();
			CancellationToken ct = _resolveCts.Token;
			LastError = null;
			string text = Plugin.DevDirectUrl.Value;
			if (string.IsNullOrWhiteSpace(text) && YtDlp.LooksLikeDirectMedia(pageUrl))
			{
				text = pageUrl;
			}
			if (!string.IsNullOrWhiteSpace(text))
			{
				StatusLine = "Loading direct URL (yt-dlp skipped)...";
				Trace.Write("StartResolve: direct media, calling Complete: " + text.Trim());
				Complete(new YtDlp.Result
				{
					Ok = true,
					Title = "Direct URL",
					DirectUrl = text.Trim()
				});
				return;
			}
			StatusLine = "Resolving stream with yt-dlp...";
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Resolving ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pageUrl);
			}
			log.LogInfo(val);
			RunOffThread("BigScreen-resolve", delegate
			{
				Complete(YtDlp.Resolve(pageUrl, ct));
			});
			void Complete(YtDlp.Result r)
			{
				MainThread.Post(delegate
				{
					//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
					//IL_00fa: Expected O, but got Unknown
					//IL_00be: Unknown result type (might be due to invalid IL or missing references)
					//IL_00c4: Expected O, but got Unknown
					if (!ct.IsCancellationRequested && !(_resolvingPageUrl != pageUrl))
					{
						_resolvingPageUrl = null;
						if (_video != null)
						{
							bool flag2 = default(bool);
							if (!r.Ok)
							{
								LastError = r.Error;
								StatusLine = "Could not load video.";
								_loadedPageUrl = pageUrl;
								ManualLogSource log2 = Plugin.Log;
								BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(16, 1, ref flag2);
								if (flag2)
								{
									((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Resolve failed: ");
									((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(r.Error);
								}
								log2.LogWarning(val2);
							}
							else
							{
								ManualLogSource log3 = Plugin.Log;
								BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(16, 2, ref flag2);
								if (flag2)
								{
									((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Resolved '");
									((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(r.Title);
									((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' (");
									((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<double>(r.Duration, "F0");
									((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("s).");
								}
								log3.LogInfo(val3);
								Plugin.Log.LogInfo((object)("Stream: " + DescribeStreamUrl(r.DirectUrl)));
								StatusLine = "Loading '" + r.Title + "'...";
								_loadedPageUrl = pageUrl;
								_pendingInitialSeek = true;
								_video.Load(r.DirectUrl, r.Duration);
								if (Session.IsHost && Session.State.VideoUrl == pageUrl && Session.State.Title != r.Title)
								{
									Session.Mutate(delegate(SyncState x)
									{
										x.Title = r.Title;
									});
								}
							}
						}
					}
				});
			}
		}

		private static void RunOffThread(string name, Action work)
		{
			Thread thread = new Thread((ThreadStart)delegate
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Expected O, but got Unknown
				try
				{
					work();
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(9, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			});
			thread.IsBackground = true;
			thread.Name = name;
			thread.Start();
		}

		private void CancelResolve()
		{
			try
			{
				_resolveCts?.Cancel();
			}
			catch
			{
			}
			_resolveCts = null;
			_resolvingPageUrl = null;
		}

		private void FollowTimeline()
		{
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Expected O, but got Unknown
			SyncState state = Session.State;
			if (_video == null || !_video.IsLoaded || string.IsNullOrEmpty(state.VideoUrl))
			{
				return;
			}
			if (!_video.IsReady)
			{
				if (_video.Error == null)
				{
					StatusLine = "Buffering...";
				}
				return;
			}
			double now = SafeNetTime();
			double num = state.ExpectedVideoTime(now);
			double len = _video.Duration;
			bool flag = len > 0.0 && num >= len - 0.3;
			if (_pendingInitialSeek)
			{
				_pendingInitialSeek = false;
				_video.Seek(num);
				_lastSeekAt = Time.unscaledTime;
				if (Session.IsHost && !state.Playing && Plugin.AutoPlay.Value && state.AnchorVideoTime <= 0.01 && !flag)
				{
					ApplyOnHost(new Request
					{
						Action = Protocol.Action.Play
					});
				}
			}
			if (flag)
			{
				if (_video.IsPlaying)
				{
					_video.Pause();
				}
				if (Session.IsHost && state.Playing)
				{
					Session.Mutate(delegate(SyncState x)
					{
						x.Playing = false;
						x.AnchorVideoTime = Math.Max(0.0, len - 0.3);
						x.AnchorNetTime = now;
					});
				}
				StatusLine = "Ended.";
				LastDrift = 0.0;
				return;
			}
			double num2 = (LastDrift = _video.Time - num);
			if (Math.Abs(num2) > (double)Plugin.DriftTolerance.Value && Time.unscaledTime - _lastSeekAt > 2.5f)
			{
				_video.Seek(num);
				_lastSeekAt = Time.unscaledTime;
				ManualLogSource log = Plugin.Log;
				bool flag2 = default(bool);
				BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(23, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Re-synced: drift was ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(num2, "F2");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s.");
				}
				log.LogDebug(val);
			}
			if (state.Playing && !_video.IsPlaying)
			{
				_video.Play();
			}
			else if (!state.Playing && _video.IsPlaying)
			{
				_video.Pause();
			}
			StatusLine = (state.Playing ? "Playing." : "Paused.");
		}

		private static string DescribeStreamUrl(string url)
		{
			if (string.IsNullOrWhiteSpace(url))
			{
				return "(none)";
			}
			try
			{
				Uri uri = new Uri(url);
				List<string> list = new List<string>
				{
					uri.Host,
					$"{url.Length} chars"
				};
				string[] array = uri.Query.TrimStart('?').Split('&');
				foreach (string text in array)
				{
					int num = text.IndexOf('=');
					if (num > 0)
					{
						string text2 = text.Substring(0, num);
						bool flag;
						switch (text2)
						{
						case "itag":
						case "mime":
						case "dur":
							flag = true;
							break;
						default:
							flag = false;
							break;
						}
						if (flag)
						{
							list.Add(text2 + "=" + Uri.UnescapeDataString(text.Substring(num + 1)));
						}
					}
				}
				return string.Join("  ", list);
			}
			catch
			{
				return $"({url.Length} chars, unparseable)";
			}
		}

		private static double SafeNetTime()
		{
			try
			{
				return NetworkTime.time;
			}
			catch
			{
				return Time.unscaledTimeAsDouble;
			}
		}

		internal static bool TryGetLocalPlayer(out PlayerCharacter player)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			player = null;
			try
			{
				PlayerCharacter val = WorldManager.localPlayerCharacter;
				if ((Object)(object)val == (Object)null)
				{
					List<PlayerCharacter> allPlayerCharacters = PlayerCharacter.allPlayerCharacters;
					if (allPlayerCharacters != null)
					{
						for (int i = 0; i < allPlayerCharacters.Count; i++)
						{
							PlayerCharacter val2 = allPlayerCharacters[i];
							if ((Object)(object)val2 != (Object)null && (Object)(object)val2.playerNetworking != (Object)null && ((NetworkBehaviour)val2.playerNetworking).isLocalPlayer)
							{
								val = val2;
								break;
							}
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				player = val;
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(28, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Local player lookup failed: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val3);
				return false;
			}
		}

		private static bool TryGetLocalPlayerPose(out Vector3 position, out Vector3 forward)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_002d: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			forward = Vector3.forward;
			try
			{
				if (!TryGetLocalPlayer(out var player))
				{
					return false;
				}
				position = ((Component)player).transform.position;
				Transform val = (((Object)(object)player.cameraTransform != (Object)null) ? player.cameraTransform : ((Component)player).transform);
				forward = val.forward;
				forward.y = 0f;
				if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
				{
					forward = ((Component)player).transform.forward;
				}
				((Vector3)(ref forward)).Normalize();
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(28, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Local player lookup failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val2);
				return false;
			}
		}

		private void TearDownScreen()
		{
			CancelResolve();
			try
			{
				_video?.Dispose();
			}
			catch
			{
			}
			_video = null;
			try
			{
				_screen?.Dispose();
			}
			catch
			{
			}
			_screen = null;
			_loadedPageUrl = null;
			_pendingInitialSeek = false;
		}

		internal void ResetSession(string reason)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(9, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Reset (");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
			}
			log.LogInfo(val);
			_nextConfigSave = 0f;
			FlushConfigIfDue();
			TearDownScreen();
			Session.Reset();
			SleepGuard.Reset();
			CrosshairGuard.Reset();
			StatusLine = "Idle.";
			LastError = null;
			LastDrift = 0.0;
		}
	}
	[BepInPlugin("dev.h223chen.bigscreen", "BigScreen", "1.0.4")]
	public class Plugin : BasePlugin
	{
		public const string Guid = "dev.h223chen.bigscreen";

		public const string Name = "BigScreen";

		public const string Version = "1.0.4";

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyCode> ToggleUiKey;

		internal static ConfigEntry<int> UiFontSize;

		internal static ConfigEntry<float> Volume;

		internal static ConfigEntry<float> AudioMaxDistance;

		internal static ConfigEntry<float> AudioFullVolumeRadius;

		internal static ConfigEntry<float> ScreenWidthMeters;

		internal static ConfigEntry<float> ScreenGroundClearance;

		internal static ConfigEntry<bool> ShowConsole;

		internal static ConfigEntry<float> ConsoleOffset;

		internal static ConfigEntry<float> ConsoleHeight;

		internal static ConfigEntry<float> ConsoleReach;

		internal static ConfigEntry<KeyCode> InteractKey;

		internal static ConfigEntry<string> RewiredAction;

		internal static ConfigEntry<int> RenderWidth;

		internal static ConfigEntry<int> RenderHeight;

		internal static ConfigEntry<string> YtDlpPath;

		internal static ConfigEntry<bool> YtDlpAutoDownload;

		internal static ConfigEntry<string> FormatSelector;

		internal static ConfigEntry<string> ExtractorArgs;

		internal static ConfigEntry<string> CookiesFromBrowser;

		internal static ConfigEntry<float> DriftTolerance;

		internal static ConfigEntry<bool> GuestsCanControl;

		internal static ConfigEntry<bool> AutoPlay;

		internal static ConfigEntry<ComfortMode> KeepAwake;

		internal static ConfigEntry<float> KeepAwakeRadius;

		internal static ConfigEntry<ComfortMode> HideCrosshair;

		internal static ConfigEntry<float> HideCrosshairDelay;

		internal static ConfigEntry<bool> Diagnostics;

		internal static ConfigEntry<bool> AutoHost;

		internal static ConfigEntry<string> AutoHostSaveSlot;

		internal static ConfigEntry<int> AutoHostPlayerCount;

		internal static ConfigEntry<float> AutoHostDelay;

		internal static ConfigEntry<string> AutoLoadUrl;

		internal static ConfigEntry<float> AutoLoadDelay;

		internal static ConfigEntry<string> DevDirectUrl;

		internal static ConfigEntry<bool> AutoDismissMenus;

		internal static ConfigEntry<string> SpawnPosition;

		internal static ConfigEntry<string> ScreenPose;

		internal static ConfigEntry<bool> ShowDevTools;

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		public override void Load()
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Expected O, but got Unknown
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Expected O, but got Unknown
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Expected O, but got Unknown
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Expected O, but got Unknown
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Expected O, but got Unknown
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Expected O, but got Unknown
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Expected O, but got Unknown
			//IL_057f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0589: Expected O, but got Unknown
			//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c6: Expected O, but got Unknown
			//IL_06c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d3: Expected O, but got Unknown
			//IL_06e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f5: Expected O, but got Unknown
			//IL_0701: Unknown result type (might be due to invalid IL or missing references)
			//IL_070b: Expected O, but got Unknown
			//IL_0749: Unknown result type (might be due to invalid IL or missing references)
			//IL_074f: Expected O, but got Unknown
			//IL_0784: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BasePlugin)this).Log;
			ToggleUiKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keys", "ToggleUI", (KeyCode)289, "Opens/closes the BigScreen control panel.");
			InteractKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keys", "Interact", (KeyCode)0, "Optional extra key for pressing the console button you are looking at. Left click always works and is the game's own interact button, so this is off by default. Avoid E: Big Walk uses it to raise the player's right arm.");
			RewiredAction = ((BasePlugin)this).Config.Bind<string>("Keys", "RewiredInteractAction", "", "Name of the game's own interact action, used so the console responds to a controller as well as the mouse. Empty auto-detects it; the log lists every action the game defines on the first attempt if the guess is wrong.");
			UiFontSize = ((BasePlugin)this).Config.Bind<int>("UI", "FontSize", 16, new ConfigDescription("Font size for the control panel. The panel picks up a change the next time it is drawn, so you can edit this while the game runs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 40), Array.Empty<object>()));
			Volume = ((BasePlugin)this).Config.Bind<float>("Audio", "Volume", 0.8f, new ConfigDescription("Local playback volume for the screen's audio (0-1). Only affects you.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			AudioMaxDistance = ((BasePlugin)this).Config.Bind<float>("Audio", "MaxDistance", 25f, new ConfigDescription("Distance in meters at which the screen's audio fades to silence.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			AudioFullVolumeRadius = ((BasePlugin)this).Config.Bind<float>("Audio", "FullVolumeRadius", 1.5f, new ConfigDescription("Distance in meters within which the screen plays at full volume. This is the main control over how local the sound feels: beyond it the volume falls off as 1/distance, so halving this roughly halves the volume you hear at any given spot. At the default 1.5 m you hear about a third of full volume standing 4 m back. Raise it to fill more of the area.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
			KeepAwake = ((BasePlugin)this).Config.Bind<ComfortMode>("Comfort", "KeepAwake", ComfortMode.WhileWatching, new ConfigDescription("Stop the game sending you to sleep - the slow dimming that happens when you stand still too long - while you are watching something. WhileWatching only holds it off when a video is playing and you are within KeepAwakeRadius of the screen, so sleep still works normally everywhere else. Always holds it off for the whole lobby. Off leaves the game alone. Only affects you; other players still see you sleep if they walk away from their own keyboards.", (AcceptableValueBase)null, Array.Empty<object>()));
			KeepAwakeRadius = ((BasePlugin)this).Config.Bind<float>("Comfort", "KeepAwakeRadius", 15f, new ConfigDescription("How close to the screen you have to be for KeepAwake=WhileWatching to hold sleep off, in meters. Measured to the middle of the screen, in every direction, so standing off to one side still counts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			HideCrosshair = ((BasePlugin)this).Config.Bind<ComfortMode>("Comfort", "HideCrosshair", ComfortMode.WhileWatching, new ConfigDescription("Hide the crosshair once you have stood still long enough, and bring it back the moment you move or look around. A dot in the middle of the picture is most annoying exactly when you are standing still watching something. WhileWatching only does it near a playing screen; Always does it anywhere in a lobby; Off leaves the crosshair alone.", (AcceptableValueBase)null, Array.Empty<object>()));
			HideCrosshairDelay = ((BasePlugin)this).Config.Bind<float>("Comfort", "HideCrosshairDelaySeconds", 5f, new ConfigDescription("How long you have to stand still before the crosshair goes, in seconds. Short is fine here because it only applies right in front of a playing screen, and the crosshair comes back the moment you move - so losing it early costs nothing. 0 follows the game's own sleep delay instead, which is around half a minute and long enough that a twitch of the mouse keeps resetting it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
			ScreenWidthMeters = ((BasePlugin)this).Config.Bind<float>("Screen", "WidthMeters", 4f, new ConfigDescription("Physical width of the screen in the world (16:9, so height follows).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			ScreenGroundClearance = ((BasePlugin)this).Config.Bind<float>("Screen", "GroundClearance", -0.3f, new ConfigDescription("How high the bottom edge of the picture sits above the spot the screen was placed at, in meters. Lower this to bring the screen down; 0 puts it on the ground and negative values sink it. The stand hides itself when there is no gap left for it. Editing this file mid-game does nothing - BepInEx does not re-read it - so use the panel's Raise/Lower buttons, which write the value back here.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 5f), Array.Empty<object>()));
			ShowConsole = ((BasePlugin)this).Config.Bind<bool>("Screen", "ShowConsole", true, "Put a control podium beside the screen with skip, play/pause and paste buttons. Turn it off to keep just the screen; the F8 panel always works either way.");
			ConsoleOffset = ((BasePlugin)this).Config.Bind<float>("Screen", "ConsoleOffsetMeters", 2.8f, new ConfigDescription("How far to the right of the screen's centre the console stands. Negative puts it on the left. The default clears a 4 m screen.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-15f, 15f), Array.Empty<object>()));
			ConsoleHeight = ((BasePlugin)this).Config.Bind<float>("Screen", "ConsoleHeightMeters", 0.5f, new ConfigDescription("Height of the console's panel above the BOTTOM EDGE of the screen, so the controls follow the screen when it is raised or lowered. It never drops below 0.35 m off the ground, so sinking the screen does not bury it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			ConsoleReach = ((BasePlugin)this).Config.Bind<float>("Screen", "ConsoleReachMeters", 4f, new ConfigDescription("How close you must be for the console's buttons to respond to your aim.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			RenderWidth = ((BasePlugin)this).Config.Bind<int>("Screen", "RenderWidth", 1280, "Width of the texture the video is decoded into. 1280x720 is plenty for a 4 m screen.");
			RenderHeight = ((BasePlugin)this).Config.Bind<int>("Screen", "RenderHeight", 720, "Height of the texture the video is decoded into.");
			YtDlpPath = ((BasePlugin)this).Config.Bind<string>("YtDlp", "Path", "", "Full path to yt-dlp.exe. Leave empty to use BepInEx\\plugins\\BigScreen\\yt-dlp.exe (downloaded automatically when AutoDownload is on).");
			YtDlpAutoDownload = ((BasePlugin)this).Config.Bind<bool>("YtDlp", "AutoDownload", true, "Download yt-dlp.exe from its official GitHub releases the first time it is needed.");
			FormatSelector = ((BasePlugin)this).Config.Bind<string>("YtDlp", "FormatSelector", "best[ext=mp4][vcodec^=avc1][acodec!=none][height<=720]/best[ext=mp4][acodec!=none]/18/best[acodec!=none][protocol^=http]", "yt-dlp -f expression. Unity's VideoPlayer needs a single progressive MP4 (H.264+AAC) that already contains audio, so the default only picks muxed formats. Change with care.");
			ExtractorArgs = ((BasePlugin)this).Config.Bind<string>("YtDlp", "ExtractorArgs", "youtube:player_client=android", "Passed to yt-dlp as --extractor-args. YouTube's default player clients currently return no playable formats at all (only storyboard images), which surfaces as 'Requested format is not available'. The android client still serves format 18, the muxed H.264+AAC MP4 that Unity's VideoPlayer needs. If YouTube blocks this client too, try tv / ios / web_safari / mweb, or clear this to use yt-dlp's own defaults.");
			CookiesFromBrowser = ((BasePlugin)this).Config.Bind<string>("YtDlp", "CookiesFromBrowser", "", "Passed to yt-dlp as --cookies-from-browser. Leave empty to request anonymously. YouTube blocks repeated anonymous requests from one address with 'Sign in to confirm you're not a bot'; naming the browser you watch YouTube in (chrome, firefox, edge, brave, vivaldi, opera, safari, chromium) lets yt-dlp reuse your signed-in session and clears that. yt-dlp reads that browser's cookie database directly; nothing is sent anywhere except to YouTube, exactly as your browser would.");
			DriftTolerance = ((BasePlugin)this).Config.Bind<float>("Sync", "DriftToleranceSeconds", 1f, new ConfigDescription("How far your playback may drift from the host's timeline before we re-seek.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			GuestsCanControl = ((BasePlugin)this).Config.Bind<bool>("Sync", "GuestsCanControl", true, "Host only: let guests with the mod load videos, play/pause, seek and move the screen. On by default: watching together is the point, and only players who also have the mod can send anything at all.");
			AutoPlay = ((BasePlugin)this).Config.Bind<bool>("Sync", "AutoPlay", true, "Host only: start playing as soon as a loaded video is ready.");
			Diagnostics = ((BasePlugin)this).Config.Bind<bool>("Debug", "Diagnostics", false, "Write a verbose status line to the BepInEx log every couple of seconds.");
			AutoHost = ((BasePlugin)this).Config.Bind<bool>("Dev", "AutoHost", false, "Host a save slot straight from the main menu, skipping Host Game / slot / player count. Development convenience; it drives the game's own menu code and may break on a game update.");
			AutoHostSaveSlot = ((BasePlugin)this).Config.Bind<string>("Dev", "AutoHostSaveSlot", "", "Name of the save slot to host. Empty means the most recently played one. If the name does not match, the log lists the slots that were found.");
			AutoHostPlayerCount = ((BasePlugin)this).Config.Bind<int>("Dev", "AutoHostPlayerCount", 3, new ConfigDescription("Player count for the hosted session.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 4), Array.Empty<object>()));
			AutoHostDelay = ((BasePlugin)this).Config.Bind<float>("Dev", "AutoHostDelaySeconds", 3f, new ConfigDescription("How long to wait after the main menu appears before hosting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			AutoLoadUrl = ((BasePlugin)this).Config.Bind<string>("Dev", "AutoLoadUrl", "", "Placed and loaded automatically once you are hosting. Empty disables it.");
			AutoDismissMenus = ((BasePlugin)this).Config.Bind<bool>("Dev", "AutoDismissMenus", false, "Click through the splash and mic-check screens and open the host menu automatically. Needed for an unattended test run; nothing else can get past those screens.");
			SpawnPosition = ((BasePlugin)this).Config.Bind<string>("Dev", "SpawnPosition", "", "Teleport to this pose once after entering a session, as \"x,y,z\" or \"x,y,z,yaw\". Empty disables it. Use the panel's 'Set spawn here' button to fill this in from where you are standing and which way you are looking. The yaw matters: the screen is auto-placed in front of you, so without one it lands somewhere different on every run.");
			ShowDevTools = ((BasePlugin)this).Config.Bind<bool>("Dev", "ShowDevTools", false, "Show development-only controls in the F8 panel, such as 'Set spawn here'. These write to the [Dev] settings above and are of no use in normal play, so they are hidden.");
			ScreenPose = ((BasePlugin)this).Config.Bind<string>("Dev", "ScreenPose", "", "Place the screen at this exact pose on an automated run, as \"x,y,z,yaw\". Empty means '4 m in front of wherever the player is looking', which lands somewhere different every run. Fill it in to pin the screen to a spot you chose.");
			DevDirectUrl = ((BasePlugin)this).Config.Bind<string>("Dev", "DirectUrl", "", "Skip yt-dlp and hand this URL straight to the VideoPlayer. Must be a progressive MP4 (H.264 + AAC). Use it to test video playback on its own, without running yt-dlp.");
			AutoLoadDelay = ((BasePlugin)this).Config.Bind<float>("Dev", "AutoLoadDelaySeconds", 6f, new ConfigDescription("How long to wait after entering the world before placing the screen and loading.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
			ClassInjector.RegisterTypeInIl2Cpp<BigScreenController>();
			GameObject val = new GameObject("BigScreen")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<BigScreenController>();
			_harmony = new Harmony("dev.h223chen.bigscreen");
			TryPatchPostfix(typeof(HouseNetworkManager), "OnStopHost", "NetworkStoppedPostfix");
			TryPatchPostfix(typeof(HouseNetworkManager), "OnStopClient", "NetworkStoppedPostfix");
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(47, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("BigScreen");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.4");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded. Press ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<KeyCode>(ToggleUiKey.Value);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" in a lobby to open the panel.");
			}
			log.LogInfo(val2);
		}

		private void TryPatchPostfix(Type type, string method, string postfixName)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				MethodInfo methodInfo = AccessTools.Method(type, method, Type.EmptyTypes, (Type[])null);
				if (methodInfo == null)
				{
					ManualLogSource log = Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(66, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not find ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(method);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" to patch (game update?). Falling back to polling.");
					}
					log.LogWarning(val);
				}
				else
				{
					_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), postfixName, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Log;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(45, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Patch of ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(method);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(". Falling back to polling.");
				}
				log2.LogWarning(val);
			}
		}

		public override bool Unload()
		{
			BigScreenController.Instance?.ResetSession("plugin unload");
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return true;
		}
	}
	internal static class Patches
	{
		internal static void NetworkStoppedPostfix()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			try
			{
				BigScreenController.Instance?.ResetSession("network stopped");
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(30, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Reset on network stop failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
		}
	}
}
namespace BigScreen.World
{
	internal enum ComfortMode
	{
		Off,
		WhileWatching,
		Always
	}
	internal sealed class ControlConsole : IDisposable
	{
		public enum Status
		{
			Idle,
			Working,
			Ready,
			Error
		}

		private sealed class Button
		{
			public string Name;

			public Rect Area;

			public Action<BigScreenController> Press;

			public readonly List<Material> Materials = new List<Material>();

			public Color Idle;

			public Color Hover;

			public float FlashUntil;

			public Color FlashColor;
		}

		private GameObject _face;

		private float _offsetMeters;

		private readonly List<Button> _buttons = new List<Button>();

		private Button _hovered;

		private GameObject _playTriangle;

		private GameObject _pauseBars;

		private bool _showingPause;

		private Material _lamp;

		private Status _status;

		private bool _planeHit;

		private Vector2 _planeLocal;

		private static readonly Color BodyColor = new Color(0.1f, 0.1f, 0.12f, 1f);

		private static readonly Color ButtonIdle = new Color(0.2f, 0.21f, 0.25f, 1f);

		private static readonly Color ButtonHover = new Color(0.4f, 0.62f, 0.95f, 1f);

		private static readonly Color PasteIdle = new Color(0.22f, 0.24f, 0.3f, 1f);

		private static readonly Color PasteHover = new Color(0.4f, 0.62f, 0.95f, 1f);

		private static readonly Color PasteInvite = new Color(0.3f, 0.44f, 0.6f, 1f);

		private static readonly Color LampIdle = new Color(0.24f, 0.25f, 0.28f, 1f);

		private static readonly Color LampWorking = new Color(0.95f, 0.65f, 0.2f, 1f);

		private static readonly Color LampReady = new Color(0.35f, 0.85f, 0.45f, 1f);

		private static readonly Color LampError = new Color(0.9f, 0.3f, 0.25f, 1f);

		private static readonly Color SymbolColor = new Color(0.92f, 0.93f, 0.96f, 1f);

		private static readonly Color OkFlash = new Color(0.45f, 0.95f, 0.5f, 1f);

		private static readonly Color BadFlash = new Color(0.95f, 0.55f, 0.2f, 1f);

		private const float TiltDegrees = 30f;

		private const float FlashSeconds = 1.2f;

		private const float PanelWidth = 1.4f;

		private const float PanelHeight = 0.62f;

		private const int LayerBody = 0;

		private const int LayerFace = 1;

		private const int LayerSymbol = 2;

		private const float FaceZ = -0.01f;

		private const float SymbolZ = -0.02f;

		public GameObject Root { get; private set; }

		public bool IsAimed => _hovered != null;

		public static ControlConsole Create(Transform parent, float offsetMeters, float heightMeters)
		{
			ControlConsole controlConsole = new ControlConsole();
			controlConsole.Build(parent, offsetMeters, heightMeters);
			return controlConsole;
		}

		private void Build(Transform parent, float offsetMeters, float heightMeters)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			Root = new GameObject("BigScreen.Console");
			Root.transform.SetParent(parent, false);
			_offsetMeters = offsetMeters;
			Root.transform.localPosition = new Vector3(offsetMeters, heightMeters, 0f);
			_face = new GameObject("ConsoleFace");
			_face.transform.SetParent(Root.transform, false);
			_face.transform.localRotation = Quaternion.Euler(30f, 0f, 0f);
			GameObject obj = Primitives.MakeQuad("ConsoleBody", 1.4f, 0.62f, Vector3.zero);
			obj.transform.SetParent(_face.transform, false);
			Material val = Primitives.MakeMaterial(null, BodyColor);
			Primitives.SetDrawOrder(val, 0);
			((Renderer)obj.GetComponent<MeshRenderer>()).material = val;
			float num = 0.12f;
			float size = 0.26f;
			float num2 = 0.32f;
			AddTransport("Back10", new Vector2(0f - num2, num), size, pointsRight: false, doubled: true, delegate(BigScreenController c)
			{
				c.UserSeekRelative(-10.0);
			});
			AddPlayPause(new Vector2(0f, num), size);
			AddTransport("Forward10", new Vector2(num2, num), size, pointsRight: true, doubled: true, delegate(BigScreenController c)
			{
				c.UserSeekRelative(10.0);
			});
			AddPasteBar(new Vector2(0f, -0.18f), 1.24f, 0.2f);
			AddStatusLamp(new Vector2(0f, 0.26f), 1.24f, 0.045f);
			Vector3 position = Root.transform.position;
			string text = (((int)Plugin.InteractKey.Value == 0) ? "use the game's interact button" : $"press {Plugin.InteractKey.Value} or interact");
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(43, 5, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Console built at (");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(position.x, "F2");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(position.y, "F2");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(position.z, "F2");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("); ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("aim within ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(Plugin.ConsoleReach.Value, "F0");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("m and ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
			}
			log.LogInfo(val2);
		}

		private void AddTransport(string name, Vector2 centre, float size, bool pointsRight, bool doubled, Action<BigScreenController> press)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			Button button = NewButton(name, centre, size, size, ButtonIdle, ButtonHover, press);
			float num = size * 0.4f;
			if (doubled)
			{
				AddSymbol(button, Primitives.MakeTriangle(name + "A", num, num, new Vector3(centre.x - num * 0.3f, centre.y, -0.02f), pointsRight));
				AddSymbol(button, Primitives.MakeTriangle(name + "B", num, num, new Vector3(centre.x + num * 0.3f, centre.y, -0.02f), pointsRight));
			}
			else
			{
				AddSymbol(button, Primitives.MakeTriangle(name + "A", num, num, new Vector3(centre.x, centre.y, -0.02f), pointsRight));
			}
		}

		private void AddPlayPause(Vector2 centre, float size)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			Button button = NewButton("PlayPause", centre, size, size, ButtonIdle, ButtonHover, delegate(BigScreenController c)
			{
				c.UserTogglePlay();
			});
			float num = size * 0.45f;
			_playTriangle = Primitives.MakeTriangle("PlaySymbol", num, num, new Vector3(centre.x, centre.y, -0.02f), pointsRight: true);
			AddSymbol(button, _playTriangle);
			_pauseBars = new GameObject("PauseSymbol");
			_pauseBars.transform.SetParent(_face.transform, false);
			_pauseBars.transform.localPosition = Vector3.zero;
			float width = num * 0.28f;
			float[] array = new float[2]
			{
				(0f - num) * 0.26f,
				num * 0.26f
			};
			foreach (float num3 in array)
			{
				GameObject obj = Primitives.MakeQuad("PauseBar", width, num, new Vector3(centre.x + num3, centre.y, -0.02f));
				obj.transform.SetParent(_pauseBars.transform, false);
				Material val = Primitives.MakeMaterial(null, SymbolColor);
				Primitives.SetDrawOrder(val, 2);
				((Renderer)obj.GetComponent<MeshRenderer>()).material = val;
				button.Materials.Add(val);
			}
			_pauseBars.SetActive(false);
		}

		private void AddPasteBar(Vector2 centre, float width, float height)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			Button button = NewButton("Paste", centre, width, height, PasteIdle, PasteHover, PressPaste);
			GameObject symbol = Primitives.MakeQuad("PasteStem", 0.03f, 0.07f, new Vector3(centre.x, centre.y + 0.04f, -0.02f));
			AddSymbol(button, symbol);
			GameObject val = Primitives.MakeTriangle("PasteHead", 0.06f, 0.11f, new Vector3(centre.x, centre.y - 0.012f, -0.02f), pointsRight: true);
			AddSymbol(button, val);
			val.transform.localRotation = Quaternion.Euler(0f, 0f, -90f);
			GameObject symbol2 = Primitives.MakeQuad("PasteTray", 0.19f, 0.022f, new Vector3(centre.x, centre.y - 0.068f, -0.02f));
			AddSymbol(button, symbol2);
		}

		private void AddStatusLamp(Vector2 centre, float width, float height)
		{
			//IL_0007: 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_0018: 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)
			GameObject obj = Primitives.MakeQuad("StatusLamp", width, height, new Vector3(centre.x, centre.y, -0.02f));
			obj.transform.SetParent(_face.transform, false);
			_lamp = Primitives.MakeMaterial(null, LampIdle);
			Primitives.SetDrawOrder(_lamp, 2);
			((Renderer)obj.GetComponent<MeshRenderer>()).material = _lamp;
		}

		private Button NewButton(string name, Vector2 centre, float width, float height, Color idle, Color hover, Action<BigScreenController> press)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Primitives.MakeQuad(name, width, height, new Vector3(centre.x, centre.y, -0.01f));
			obj.transform.SetParent(_face.transform, false);
			Material val = Primitives.MakeMaterial(null, idle);
			Primitives.SetDrawOrder(val, 1);
			((Renderer)obj.GetComponent<MeshRenderer>()).material = val;
			Button button = new Button
			{
				Name = name,
				Area = new Rect(centre.x - width * 0.5f, centre.y - height * 0.5f, width, height),
				Press = press,
				Idle = idle,
				Hover = hover
			};
			button.Materials.Add(val);
			_buttons.Add(button);
			return button;
		}

		private void AddSymbol(Button button, GameObject symbol)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			symbol.transform.SetParent(_face.transform, false);
			Material val = Primitives.MakeMaterial(null, SymbolColor);
			Primitives.SetDrawOrder(val, 2);
			((Renderer)symbol.GetComponent<MeshRenderer>()).material = val;
			button.Materials.Add(val);
		}

		private void PressPaste(BigScreenController controller)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			bool flag = default(bool);
			string systemCopyBuffer;
			try
			{
				systemCopyBuffer = GUIUtility.systemCopyBuffer;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(30, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not read the clipboard: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
				Flash("Paste", BadFlash);
				return;
			}
			systemCopyBuffer = (systemCopyBuffer ?? "").Trim();
			if (!YtDlp.LooksLikeUrl(systemCopyBuffer))
			{
				controller.ReportConsoleError(string.IsNullOrEmpty(systemCopyBuffer) ? "Clipboard is empty. Copy a YouTube link first, then press paste." : "Clipboard does not hold a link (it must start with http:// or https://).");
				Flash("Paste", BadFlash);
				return;
			}
			ManualLogSource log2 = Plugin.Log;
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(17, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Console: pasting ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(systemCopyBuffer);
			}
			log2.LogInfo(val2);
			Flash("Paste", OkFlash);
			controller.UserLoad(systemCopyBuffer);
		}

		private void Flash(string buttonName, Color color)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			foreach (Button button in _buttons)
			{
				if (!(button.Name != buttonName))
				{
					button.FlashUntil = Time.unscaledTime + 1.2f;
					button.FlashColor = color;
				}
			}
		}

		public void Tick(BigScreenController controller, bool aimValid, Vector3 aimOrigin, Vector3 aimDirection, bool playing, Status status, float reachMeters, bool pressed)
		{
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Expected O, but got Unknown
			//IL_002c: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Root == (Object)null)
			{
				return;
			}
			_status = status;
			ShowPauseSymbol(playing);
			UpdateLamp();
			Button button = (aimValid ? ButtonUnderAim(aimOrigin, aimDirection, reachMeters) : null);
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (button != _hovered)
			{
				_hovered = button;
				if (button != null)
				{
					ManualLogSource log = Plugin.Log;
					val = new BepInExInfoLogInterpolatedStringHandler(20, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Console: aiming at ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(button.Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log.LogInfo(val);
				}
			}
			foreach (Button button2 in _buttons)
			{
				Repaint(button2);
			}
			if (!pressed)
			{
				return;
			}
			if (_hovered == null)
			{
				ManualLogSource log2 = Plugin.Log;
				val = new BepInExInfoLogInterpolatedStringHandler(45, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Console: interact pressed, nothing aimed at. ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(DescribeAim(aimOrigin));
				}
				log2.LogInfo(val);
				return;
			}
			Button hovered = _hovered;
			ManualLogSource log3 = Plugin.Log;
			val = new BepInExInfoLogInterpolatedStringHandler(18, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Console: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(hovered.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" pressed.");
			}
			log3.LogInfo(val);
			if (hovered.Name != "Paste")
			{
				Flash(hovered.Name, OkFlash);
			}
			try
			{
				hovered.Press(controller);
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(24, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Console button ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(hovered.Name);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log4.LogError(val2);
			}
		}

		public void SetHeight(float localY)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			if (!((Object)(object)Root == (Object)null))
			{
				Vector3 localPosition = Root.transform.localPosition;
				if (!Mathf.Approximately(localPosition.y, localY))
				{
					Root.transform.localPosition = new Vector3(_offsetMeters, localY, localPosition.z);
				}
			}
		}

		public string DescribeAim(Vector3 aimOrigin)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Root == (Object)null)
			{
				return "none";
			}
			float value = Vector3.Distance(aimOrigin, Root.transform.position);
			string value2 = (_planeHit ? $"panel({_planeLocal.x:F2},{_planeLocal.y:F2})" : "off-panel");
			return $"{value:F1}m {value2} {((_hovered != null) ? _hovered.Name : "-")}";
		}

		private void UpdateLamp()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_lamp == (Object)null))
			{
				Color val = (Color)(_status switch
				{
					Status.Working => LampWorking, 
					Status.Ready => LampReady, 
					Status.Error => LampError, 
					_ => LampIdle, 
				});
				if (_status == Status.Working)
				{
					val = Color.Lerp(val * 0.45f, val, Mathf.PingPong(Time.unscaledTime * 1.6f, 1f));
				}
				Primitives.SetTint(_lamp, val);
			}
		}

		private void Repaint(Button b)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			Color val = b.Idle;
			if (Time.unscaledTime < b.FlashUntil)
			{
				val = b.FlashColor;
			}
			else if (b == _hovered)
			{
				val = b.Hover;
			}
			else if (b.Name == "Paste" && _status == Status.Idle)
			{
				val = Color.Lerp(PasteIdle, PasteInvite, Mathf.PingPong(Time.unscaledTime * 0.8f, 1f));
			}
			for (int i = 0; i < b.Materials.Count; i++)
			{
				bool flag = i == 0;
				Color tint = ((Time.unscaledTime < b.FlashUntil) ? val : (flag ? val : SymbolColor));
				Primitives.SetTint(b.Materials[i], tint);
			}
		}

		private void ShowPauseSymbol(bool playing)
		{
			if (playing != _showingPause)
			{
				_showingPause = playing;
				if ((Object)(object)_playTriangle != (Object)null)
				{
					_playTriangle.SetActive(!playing);
				}
				if ((Object)(object)_pauseBars != (Object)null)
				{
					_pauseBars.SetActive(playing);
				}
			}
		}

		private Button ButtonUnderAim(Vector3 origin, Vector3 direction, float reachMeters)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_0037: 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_0055: 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)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			_planeHit = false;
			Transform transform = _face.transform;
			Vector3 val = -transform.forward;
			float num = Vector3.Dot(direction, val);
			if (num >= -0.0001f)
			{
				return null;
			}
			float num2 = Vector3.Dot(transform.position - origin, val) / num;
			if (num2 < 0f || num2 > reachMeters)
			{
				return null;
			}
			Vector3 val2 = transform.InverseTransformPoint(origin + direction * num2);
			_planeLocal = new Vector2(val2.x, val2.y);
			_planeHit = Mathf.Abs(val2.x) <= 0.7f && Mathf.Abs(val2.y) <= 0.31f;
			foreach (Button button in _buttons)
			{
				if (((Rect)(ref button.Area)).Contains(_planeLocal))
				{
					return button;
				}
			}
			return null;
		}

		public void Dispose()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			try
			{
				if ((Object)(object)Root != (Object)null)
				{
					Object.Destroy((Object)(object)Root);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(17, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Console dispose: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogDebug(val);
			}
			Root = null;
			_face = null;
			_buttons.Clear();
			_hovered = null;
			_playTriangle = null;
			_pauseBars = null;
		}
	}
	internal static class CrosshairGuard
	{
		private static string _delaySource = "?";

		private const float MovedMeters = 0.03f;

		private const float LookedDegrees = 0.15f;

		private const float FallbackDelaySeconds = 30f;

		private static Vector3 _lastPosition;

		private static Vector3 _lastForward;

		private static bool _havePose;

		private static float _lastMoveAt = -1f;

		private static bool _hiddenByUs;

		private static bool _warned;

		private static bool _described;

		internal static bool Hidden { get; private set; }

		internal static float DelaySeconds
		{
			get
			{
				try
				{
					return HideDelay();
				}
				catch
				{
					return -1f;
				}
			}
		}

		internal static string DelaySource => _delaySource;

		internal static float SecondsIdle
		{
			get
			{
				if (!(_lastMoveAt < 0f))
				{
					return Time.unscaledTime - _lastMoveAt;
				}
				return 0f;
			}
		}

		internal static void Reset()
		{
			try
			{
				Show();
			}
			catch
			{
			}
			Hidden = false;
			_hiddenByUs = false;
			_havePose = false;
			_lastMoveAt = -1f;
		}

		internal static void Tick(Vector3 screenPosition, bool haveScreen, bool playing)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ComfortMode value = Plugin.HideCrosshair.Value;
				if (value == ComfortMode.Off || (value == ComfortMode.WhileWatching && !SleepGuard.IsWatching(screenPosition, haveScreen, playing)))
				{
					Show();
				}
				else if (PlayerMoved())
				{
					_lastMoveAt = Time.unscaledTime;
					Show();
				}
				else if (_lastMoveAt < 0f)
				{
					_lastMoveAt = Time.unscaledTime;
				}
				else if (Time.unscaledTime - _lastMoveAt >= HideDelay())
				{
					Hide();
				}
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(52, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Crosshair hiding disabled; it could not be reached: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
			}
		}

		private static bool PlayerMoved()
		{
			//IL_0011: 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)
			//IL_0033: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result