Decompiled source of DrivingRangeTheater v0.1.2

DrivingRangeTheater.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FMOD;
using FMODUnity;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Localization;
using UnityEngine.UI;
using UnityEngine.Video;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DrivingRangeTheater")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DrivingRangeTheater")]
[assembly: AssemblyTitle("DrivingRangeTheater")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DrivingRangeTheater
{
	public class DrivingRangeBackCameraButton : MonoBehaviour, IInteractable
	{
		public Entity AsEntity { get; private set; }

		public bool IsInteractionEnabled => DrivingRangeStaticCameraManager.IsCycleNextButtonEnabled;

		public LocalizedString InteractString => UI.SPECTATOR_Prompt_Previous_Ref;

		public void LocalPlayerInteract()
		{
			if (NetworkClient.active)
			{
				TheaterCycleMsg theaterCycleMsg = default(TheaterCycleMsg);
				theaterCycleMsg.direction = -1;
				NetworkClient.Send<TheaterCycleMsg>(theaterCycleMsg, 0);
			}
		}

		private void Awake()
		{
			AsEntity = ((Component)this).GetComponent<Entity>();
		}
	}
	internal static class BackButtonInstaller
	{
		private const float OffsetMeters = 0.2508f;

		private static bool _installed;

		public static void ResetForNewScene()
		{
			_installed = false;
		}

		public static void TryInstall(DrivingRangeStaticCameraManager mgr)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			if (_installed)
			{
				return;
			}
			DrivingRangeNextCameraButton val = Traverse.Create((object)mgr).Field<DrivingRangeNextCameraButton>("nextCameraButton").Value;
			if ((Object)(object)val == (Object)null)
			{
				val = Object.FindObjectOfType<DrivingRangeNextCameraButton>();
			}
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Back button: no DrivingRangeNextCameraButton found yet — will retry.");
				}
				return;
			}
			if ((Object)(object)((Component)val).transform.parent != (Object)null && (Object)(object)((Component)val).transform.parent.Find("SBG-BackCameraButton") != (Object)null)
			{
				_installed = true;
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
			((Object)val2).name = "SBG-BackCameraButton";
			Vector3 val3 = Vector3.right * 0.2508f;
			Vector3 val4 = ((Component)val).transform.TransformVector(val3);
			val2.transform.localPosition = ((Component)val).transform.localPosition + val3;
			val2.transform.localRotation = ((Component)val).transform.localRotation;
			val2.transform.localScale = ((Component)val).transform.localScale;
			DrivingRangeNextCameraButton component = val2.GetComponent<DrivingRangeNextCameraButton>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			val2.AddComponent<DrivingRangeBackCameraButton>();
			Entity component2 = ((Component)val).GetComponent<Entity>();
			Entity component3 = val2.GetComponent<Entity>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null && (Object)(object)component2.TargetReticlePosition != (Object)null && (Object)(object)component3.TargetReticlePosition != (Object)null)
			{
				((Component)component3.TargetReticlePosition).transform.position = ((Component)component2.TargetReticlePosition).transform.position + val4;
			}
			_installed = true;
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"Back button installed at {val2.transform.position}.");
			}
		}
	}
	public struct TheaterCycleMsg : NetworkMessage
	{
		public int direction;
	}
	[BepInPlugin("cray.drivingrangetheater", "DrivingRangeTheater", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(DrivingRangeStaticCameraManager), "OnStartServer")]
		internal static class Patch_Manager_OnStartServer
		{
			private static void Postfix()
			{
				NetworkServer.ReplaceHandler<TheaterCycleMsg>((Action<NetworkConnectionToClient, TheaterCycleMsg>)OnClientCycle, true);
				Log.LogInfo((object)"Registered TheaterCycleMsg server handler.");
			}
		}

		[HarmonyPatch(typeof(DrivingRangeStaticCameraManager), "ApplyCurrentCameraIndex")]
		internal static class Patch_Manager_ApplyCurrentCameraIndex
		{
			private static bool Prefix(DrivingRangeStaticCameraManager __instance)
			{
				Renderer value = Traverse.Create((object)__instance).Field<Renderer>("screenRenderer").Value;
				if ((Object)(object)value == (Object)null)
				{
					return true;
				}
				if ((Object)(object)TheaterController.Current == (Object)null)
				{
					((Component)value).gameObject.AddComponent<TheaterController>().Initialize(value, __instance);
				}
				if (VideoLibrary.Videos.Count == 0)
				{
					TheaterController.Current.ShowNoVideos();
					return false;
				}
				TheaterController.Current.ApplyIndex(__instance.NetworkcurrentCameraIndex);
				BackButtonInstaller.TryInstall(__instance);
				return false;
			}
		}

		public const string ModGuid = "cray.drivingrangetheater";

		public const string ModName = "DrivingRangeTheater";

		public const string ModVersion = "0.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> VolumeConfig;

		internal static ConfigEntry<float> OverscanCompensationConfig;

		internal static ConfigEntry<int> ScreenResolutionConfig;

		private static float _lastServerCycleTime;

		private void Awake()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			VolumeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Theater", "Volume", 0.5f, new ConfigDescription("Client-local master volume for the driving-range theater (0.0 - 1.0).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ScreenResolutionConfig = ((BaseUnityPlugin)this).Config.Bind<int>("Theater", "ScreenResolution", 1024, new ConfigDescription("Client-local theater screen RT resolution. Accepted values: 1024, 1536, 2048.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[3] { 1024, 1536, 2048 }), Array.Empty<object>()));
			OverscanCompensationConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Theater", "OverscanCompensation", 0f, new ConfigDescription("Shrinks the displayed video inside the theater screen RT to compensate for screen overscan/cropping (0.0 - 0.25).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.25f), Array.Empty<object>()));
			VolumeConfig.SettingChanged += delegate
			{
				TheaterController.Current?.SetVolume(VolumeConfig.Value);
			};
			ScreenResolutionConfig.SettingChanged += delegate
			{
				TheaterController.Current?.ApplyConfiguredScreenResolution();
			};
			OverscanCompensationConfig.SettingChanged += delegate
			{
				TheaterController.Current?.RefreshDisplayComposition();
			};
			PauseMenu.Paused += VolumeSliderUi.HandlePauseShown;
			PauseMenu.Unpaused += VolumeSliderUi.HandlePauseHidden;
			VideoLibrary.ScanAll(Paths.PluginPath, Log);
			new Harmony("cray.drivingrangetheater").PatchAll();
			NetworkClient.OnConnectedEvent = (Action)Delegate.Combine(NetworkClient.OnConnectedEvent, new Action(RegisterClientHandlers));
			Log.LogInfo((object)string.Format("{0} v{1} loaded ({2} video(s)).", "DrivingRangeTheater", "0.1.0", VideoLibrary.Videos.Count));
		}

		internal static int GetConfiguredScreenResolution()
		{
			int num = ((ScreenResolutionConfig != null) ? ScreenResolutionConfig.Value : 1024);
			if (num != 1536 && num != 2048)
			{
				return 1024;
			}
			return num;
		}

		private static void RegisterClientHandlers()
		{
		}

		internal static void OnClientCycle(NetworkConnectionToClient conn, TheaterCycleMsg msg)
		{
			if (Time.realtimeSinceStartup - _lastServerCycleTime < 0.2f)
			{
				return;
			}
			_lastServerCycleTime = Time.realtimeSinceStartup;
			DrivingRangeStaticCameraManager instance = SingletonNetworkBehaviour<DrivingRangeStaticCameraManager>.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				int num = Mathf.Max(VideoLibrary.Videos.Count, 1);
				int num2 = ((msg.direction >= 0) ? 1 : (-1));
				int num3 = instance.NetworkcurrentCameraIndex;
				if (num3 < 0)
				{
					num3 = 0;
				}
				int networkcurrentCameraIndex = ((num3 + num2) % num + num) % num;
				instance.NetworkcurrentCameraIndex = networkcurrentCameraIndex;
			}
		}
	}
	internal class TheaterController : MonoBehaviour
	{
		private struct ScreenTextureBinding
		{
			public string Name;

			public Texture Texture;

			public Vector2 Scale;

			public Vector2 Offset;
		}

		private sealed class Slot
		{
			public string Label;

			public VideoPlayer Player;

			public RenderTexture RenderTexture;

			public int VideoIndex = -1;

			public bool Prepared;
		}

		public static TheaterController Current;

		private Slot[] _slots;

		private int _activeSlot;

		private Renderer _screenRenderer;

		private Material _screenMaterial;

		private ScreenTextureBinding[] _screenBindings = Array.Empty<ScreenTextureBinding>();

		private RenderTexture _screenRenderTexture;

		private TextMeshPro _statusText;

		private DrivingRangeStaticCameraManager _vanillaManager;

		private Sound[] _sounds;

		private Channel _activeChannel;

		private bool _activeChannelValid;

		private float _driftCheckTimer;

		private const float DriftCheckInterval = 2f;

		private const int DriftToleranceMs = 250;

		private Vector3 _lastAudioWorldPos;

		private const float AudioMinDistance = 6f;

		private const float AudioMaxDistance = 45f;

		private int _activeAudioIndex = -1;

		private string[] _screenTextureSlots = Array.Empty<string>();

		public void Initialize(Renderer screenRenderer, DrivingRangeStaticCameraManager vanillaMgr)
		{
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Invalid comparison between Unknown and I4
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			Current = this;
			_screenRenderer = screenRenderer;
			_screenMaterial = screenRenderer.material;
			_vanillaManager = vanillaMgr;
			try
			{
				if (Traverse.Create((object)vanillaMgr).Field("cameras").GetValue() is DrivingRangeStaticCamera[] array && array.Length != 0)
				{
					object value = Traverse.Create((object)array[0]).Field("thisCamera").GetValue();
					Camera val = (Camera)((value is Camera) ? value : null);
					if ((Object)(object)val != (Object)null && (Object)(object)val.targetTexture != (Object)null)
					{
						_screenRenderTexture = val.targetTexture;
						ApplyConfiguredScreenResolution();
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)$"Theater RT sized from vanilla camera: {((Texture)_screenRenderTexture).width}x{((Texture)_screenRenderTexture).height} ({((Object)_screenRenderTexture).name})");
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("RT size probe failed: " + ex.Message));
				}
			}
			_slots = new Slot[3];
			for (int i = 0; i < _slots.Length; i++)
			{
				_slots[i] = CreateSlot("SBG-TheaterSlot-" + i, 1920, 1080);
			}
			Shader shader = _screenMaterial.shader;
			int propertyCount = shader.GetPropertyCount();
			List<string> list = new List<string>();
			for (int j = 0; j < propertyCount; j++)
			{
				if ((int)shader.GetPropertyType(j) == 4)
				{
					string propertyName = shader.GetPropertyName(j);
					string text = propertyName.ToLowerInvariant();
					if (text.Contains("maintex") || text.Contains("basemap") || text.Contains("emission"))
					{
						list.Add(propertyName);
					}
				}
			}
			if (list.Count == 0)
			{
				if (_screenMaterial.HasProperty("_MainTex"))
				{
					list.Add("_MainTex");
				}
				if (_screenMaterial.HasProperty("_BaseMap"))
				{
					list.Add("_BaseMap");
				}
				if (_screenMaterial.HasProperty("_EmissionMap"))
				{
					list.Add("_EmissionMap");
				}
			}
			_screenTextureSlots = list.ToArray();
			_screenBindings = new ScreenTextureBinding[_screenTextureSlots.Length];
			for (int k = 0; k < _screenTextureSlots.Length; k++)
			{
				string text2 = _screenTextureSlots[k];
				_screenBindings[k] = new ScreenTextureBinding
				{
					Name = text2,
					Texture = _screenMaterial.GetTexture(text2),
					Scale = _screenMaterial.GetTextureScale(text2),
					Offset = _screenMaterial.GetTextureOffset(text2)
				};
				_screenMaterial.SetTextureScale(text2, Vector2.one);
				_screenMaterial.SetTextureOffset(text2, Vector2.zero);
			}
			if (_screenMaterial.HasProperty("_EmissionColor"))
			{
				_screenMaterial.SetColor("_EmissionColor", Color.white * 1.2f);
			}
			_screenMaterial.EnableKeyword("_EMISSION");
			CreateStatusText();
			_sounds = (Sound[])(object)new Sound[VideoLibrary.Entries.Count];
		}

		private Slot CreateSlot(string label, int rtW, int rtH)
		{
			//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_0033: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			RenderTexture val = new RenderTexture(rtW, rtH, 0, (RenderTextureFormat)0)
			{
				name = label + "-RT",
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1,
				useMipMap = false
			};
			val.Create();
			GameObject val2 = new GameObject(label);
			val2.transform.SetParent(((Component)this).transform, false);
			VideoPlayer val3 = val2.AddComponent<VideoPlayer>();
			val3.playOnAwake = false;
			val3.waitForFirstFrame = true;
			val3.isLooping = true;
			val3.renderMode = (VideoRenderMode)2;
			val3.targetTexture = val;
			val3.source = (VideoSource)1;
			val3.audioOutputMode = (VideoAudioOutputMode)0;
			val3.aspectRatio = (VideoAspectRatio)5;
			Slot slot = new Slot
			{
				Label = label,
				Player = val3,
				RenderTexture = val
			};
			val3.errorReceived += (ErrorEventHandler)delegate(VideoPlayer v, string msg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("[" + label + "] " + msg));
				}
			};
			val3.prepareCompleted += (EventHandler)delegate
			{
				HandleSlotPrepared(slot);
			};
			val3.started += (EventHandler)delegate
			{
				HandleSlotStarted(slot);
			};
			return slot;
		}

		public void ApplyIndex(int index)
		{
			if (VideoLibrary.Entries.Count != 0)
			{
				index = Wrap(index, VideoLibrary.Entries.Count);
				StopActiveChannel();
				int num = FindSlotFor(index);
				if (num < 0)
				{
					num = _activeSlot;
					BindSlotToVideo(_slots[num], index);
				}
				_activeSlot = num;
				AssignRenderTargets(_activeSlot);
				Slot slot = _slots[_activeSlot];
				if (slot.Player.url != BuildUrl(index))
				{
					BindSlotToVideo(slot, index);
				}
				ShowStatus("Loading...");
				slot.Player.Prepare();
				slot.Player.Play();
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Theater playing [{index}] {Path.GetFileName(VideoLibrary.Entries[index].VideoPath)} (slot {_activeSlot})");
				}
				PreloadNeighbors(index);
			}
		}

		private void HandleSlotPrepared(Slot slot)
		{
			slot.Prepared = true;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"[{slot.Label}] prepared: {Path.GetFileName(slot.Player.url)} ({slot.Player.width}x{slot.Player.height}x{slot.Player.frameRate:F1}fps)");
			}
			if (_slots != null && _slots[_activeSlot] == slot)
			{
				AssignRenderTargets(_activeSlot);
				CompositeToScreen(slot.RenderTexture);
			}
		}

		private void HandleSlotStarted(Slot slot)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("[" + slot.Label + "] started: " + Path.GetFileName(slot.Player.url)));
			}
			if (_slots != null && _slots[_activeSlot] == slot)
			{
				AssignRenderTargets(_activeSlot);
				CompositeToScreen(slot.RenderTexture);
				HideStatus();
				if (slot.VideoIndex >= 0 && slot.VideoIndex != _activeAudioIndex)
				{
					StartAudioFor(slot.VideoIndex);
				}
			}
		}

		private void PreloadNeighbors(int centerIndex)
		{
			int count = VideoLibrary.Entries.Count;
			if (count <= 1)
			{
				return;
			}
			int num = Wrap(centerIndex + 1, count);
			int num2 = Wrap(centerIndex - 1, count);
			for (int i = 0; i < _slots.Length; i++)
			{
				if (i != _activeSlot)
				{
					int num3 = ((num != centerIndex && FindSlotFor(num) < 0) ? num : ((num2 != centerIndex && FindSlotFor(num2) < 0) ? num2 : (-1)));
					if (num3 < 0)
					{
						break;
					}
					BindSlotToVideo(_slots[i], num3);
					_slots[i].Player.Prepare();
				}
			}
		}

		private void BindSlotToVideo(Slot slot, int videoIndex)
		{
			if (slot.VideoIndex != videoIndex)
			{
				slot.Player.Stop();
				slot.Player.url = VideoLibrary.Entries[videoIndex].VideoPath;
				slot.VideoIndex = videoIndex;
				slot.Prepared = false;
			}
		}

		private int FindSlotFor(int videoIndex)
		{
			for (int i = 0; i < _slots.Length; i++)
			{
				if (_slots[i].VideoIndex == videoIndex)
				{
					return i;
				}
			}
			return -1;
		}

		private void BindScreenTo(RenderTexture rt)
		{
			for (int i = 0; i < _screenTextureSlots.Length; i++)
			{
				_screenMaterial.SetTexture(_screenTextureSlots[i], (Texture)(object)rt);
			}
			_screenMaterial.mainTexture = (Texture)(object)rt;
		}

		private static void UpgradeVanillaRenderTextureInPlace(DrivingRangeStaticCameraManager vanillaMgr, RenderTexture sharedTarget, int desiredSize)
		{
			if ((Object)(object)sharedTarget == (Object)null || desiredSize <= 0 || (((Texture)sharedTarget).width == desiredSize && ((Texture)sharedTarget).height == desiredSize))
			{
				return;
			}
			try
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Upgrading shared theater RT in place: '{((Object)sharedTarget).name}' {((Texture)sharedTarget).width}x{((Texture)sharedTarget).height} -> {desiredSize}x{desiredSize}");
				}
				sharedTarget.Release();
				((Texture)sharedTarget).width = desiredSize;
				((Texture)sharedTarget).height = desiredSize;
				sharedTarget.Create();
				if (!(Traverse.Create((object)vanillaMgr).Field("cameras").GetValue() is DrivingRangeStaticCamera[] array))
				{
					return;
				}
				foreach (DrivingRangeStaticCamera val in array)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Traverse val2 = Traverse.Create((object)val);
					object value = val2.Field("thisCamera").GetValue();
					Camera val3 = (Camera)((value is Camera) ? value : null);
					if (!((Object)(object)val3 == (Object)null))
					{
						val3.targetTexture = sharedTarget;
						val3.RemoveAllCommandBuffers();
						object value2 = val2.Field("staticRenderTexture").GetValue();
						RenderTexture val4 = (RenderTexture)((value2 is RenderTexture) ? value2 : null);
						if ((Object)(object)val4 != (Object)null)
						{
							val4.Release();
							Object.Destroy((Object)(object)val4);
						}
						object value3 = val2.Field("staticDepthTexture").GetValue();
						RenderTexture val5 = (RenderTexture)((value3 is RenderTexture) ? value3 : null);
						if ((Object)(object)val5 != (Object)null)
						{
							val5.Release();
							Object.Destroy((Object)(object)val5);
						}
						val2.Field("staticRenderTexture").SetValue((object)null);
						val2.Field("staticDepthTexture").SetValue((object)null);
						val2.Field("hasTextures").SetValue((object)false);
						val.RenderStaticTexture();
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("In-place theater RT upgrade failed: " + ex.Message));
				}
			}
		}

		public void ApplyConfiguredScreenResolution()
		{
			if (!((Object)(object)_screenRenderTexture == (Object)null) && !((Object)(object)_vanillaManager == (Object)null))
			{
				UpgradeVanillaRenderTextureInPlace(_vanillaManager, _screenRenderTexture, Plugin.GetConfiguredScreenResolution());
				RefreshDisplayComposition();
			}
		}

		private void AssignRenderTargets(int activeSlot)
		{
			for (int i = 0; i < _slots.Length; i++)
			{
				if ((Object)(object)_slots[i].Player.targetTexture != (Object)(object)_slots[i].RenderTexture)
				{
					_slots[i].Player.targetTexture = _slots[i].RenderTexture;
				}
			}
			if ((Object)(object)_screenRenderTexture == (Object)null)
			{
				BindScreenTo(_slots[activeSlot].RenderTexture);
			}
			else
			{
				BindScreenTo(_screenRenderTexture);
			}
		}

		private void CompositeToScreen(RenderTexture source)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_screenRenderTexture == (Object)null) && !((Object)(object)source == (Object)null))
			{
				float num = ((Plugin.OverscanCompensationConfig != null) ? Mathf.Clamp01(Plugin.OverscanCompensationConfig.Value) : 0.12f);
				float num2 = ((Texture)_screenRenderTexture).width;
				float num3 = ((Texture)_screenRenderTexture).height;
				float num4 = num2 * (1f - num * 2f);
				float num5 = num3 * (1f - num * 2f);
				float num6 = ((((Texture)source).height > 0) ? ((float)((Texture)source).width / (float)((Texture)source).height) : 1.7777778f);
				float num7 = ((num5 > 0f) ? (num4 / num5) : num6);
				float num8 = num4;
				float num9 = num5;
				if (num7 > num6)
				{
					num8 = num9 * num6;
				}
				else
				{
					num9 = num8 / num6;
				}
				float num10 = (num2 - num8) * 0.5f;
				float num11 = (num3 - num9) * 0.5f;
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = _screenRenderTexture;
				GL.PushMatrix();
				GL.LoadPixelMatrix(0f, num2, num3, 0f);
				GL.Clear(true, true, Color.black);
				Graphics.DrawTexture(new Rect(num10, num11, num8, num9), (Texture)(object)source);
				GL.PopMatrix();
				RenderTexture.active = active;
			}
		}

		private string BuildUrl(int index)
		{
			return VideoLibrary.Entries[index].VideoPath;
		}

		private void StartAudioFor(int index)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			VideoEntry videoEntry = VideoLibrary.Entries[index];
			if (string.IsNullOrEmpty(videoEntry.AudioPath))
			{
				return;
			}
			if (_sounds[index].handle == IntPtr.Zero)
			{
				System coreSystem = RuntimeManager.CoreSystem;
				RESULT val = ((System)(ref coreSystem)).createSound(videoEntry.AudioPath, (MODE)2097298, ref _sounds[index]);
				if ((int)val != 0)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogError((object)$"FMOD createSound failed for {videoEntry.AudioPath}: {val}");
					}
					return;
				}
			}
			System coreSystem2 = RuntimeManager.CoreSystem;
			RESULT val2 = ((System)(ref coreSystem2)).playSound(_sounds[index], default(ChannelGroup), false, ref _activeChannel);
			if ((int)val2 != 0)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"FMOD playSound failed: {val2}");
				}
			}
			else
			{
				((Channel)(ref _activeChannel)).setMode((MODE)2097168);
				((Channel)(ref _activeChannel)).set3DMinMaxDistance(6f, 45f);
				((Channel)(ref _activeChannel)).setVolume(Plugin.VolumeConfig.Value);
				_activeChannelValid = true;
				_activeAudioIndex = index;
				_driftCheckTimer = 2f;
				UpdateAudioSpatialization(force: true);
			}
		}

		private void StopActiveChannel()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (_activeChannelValid)
			{
				((Channel)(ref _activeChannel)).stop();
				_activeChannelValid = false;
				_activeAudioIndex = -1;
			}
		}

		public void SetVolume(float v)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			v = Mathf.Clamp01(v);
			if (_activeChannelValid)
			{
				((Channel)(ref _activeChannel)).setVolume(v);
			}
		}

		public void RefreshDisplayComposition()
		{
			if (_slots != null && _activeSlot >= 0 && _activeSlot < _slots.Length)
			{
				VideoPlayer player = _slots[_activeSlot].Player;
				if ((Object)(object)_screenRenderTexture != (Object)null && (Object)(object)player != (Object)null && (player.isPlaying || player.isPrepared))
				{
					CompositeToScreen(_slots[_activeSlot].RenderTexture);
				}
			}
		}

		public void ShowNoVideos()
		{
			StopActiveChannel();
			ShowStatus("No video files added");
		}

		private void CreateStatusText()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_statusText != (Object)null) && !((Object)(object)_screenRenderer == (Object)null))
			{
				GameObject val = new GameObject("SBG-TheaterStatus");
				val.transform.SetParent(((Component)this).transform, false);
				_statusText = val.AddComponent<TextMeshPro>();
				((TMP_Text)_statusText).text = string.Empty;
				((TMP_Text)_statusText).fontSize = 8f;
				((TMP_Text)_statusText).alignment = (TextAlignmentOptions)514;
				((Graphic)_statusText).color = Color.white;
				((TMP_Text)_statusText).textWrappingMode = (TextWrappingModes)1;
				((TMP_Text)_statusText).outlineWidth = 0.2f;
				((TMP_Text)_statusText).rectTransform.sizeDelta = new Vector2(12f, 4f);
				((Component)_statusText).gameObject.SetActive(false);
				UpdateStatusTransform();
			}
		}

		private void UpdateStatusTransform()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_statusText == (Object)null) && !((Object)(object)_screenRenderer == (Object)null))
			{
				Transform transform = _statusText.transform;
				Bounds bounds = _screenRenderer.bounds;
				transform.position = ((Bounds)(ref bounds)).center + ((Component)_screenRenderer).transform.forward * 0.03f;
				transform.rotation = ((Component)_screenRenderer).transform.rotation * Quaternion.Euler(0f, 180f, 0f);
				transform.localScale = Vector3.one * 0.45f;
			}
		}

		private void ShowStatus(string text)
		{
			if ((Object)(object)_statusText == (Object)null)
			{
				CreateStatusText();
			}
			if (!((Object)(object)_statusText == (Object)null))
			{
				UpdateStatusTransform();
				((TMP_Text)_statusText).text = text;
				((Component)_statusText).gameObject.SetActive(true);
			}
		}

		private void HideStatus()
		{
			if ((Object)(object)_statusText != (Object)null)
			{
				((Component)_statusText).gameObject.SetActive(false);
			}
		}

		private Vector3 GetAudioWorldPosition()
		{
			//IL_0028: 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)
			//IL_0019: 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)
			if ((Object)(object)_screenRenderer != (Object)null)
			{
				Bounds bounds = _screenRenderer.bounds;
				return ((Bounds)(ref bounds)).center;
			}
			return ((Component)this).transform.position;
		}

		private void UpdateAudioSpatialization(bool force = false)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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)
			//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_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!_activeChannelValid)
			{
				return;
			}
			Vector3 audioWorldPosition = GetAudioWorldPosition();
			if (!force)
			{
				Vector3 val = audioWorldPosition - _lastAudioWorldPos;
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
				{
					return;
				}
			}
			VECTOR val2 = RuntimeUtils.ToFMODVector(audioWorldPosition);
			VECTOR val3 = RuntimeUtils.ToFMODVector(Vector3.zero);
			((Channel)(ref _activeChannel)).set3DAttributes(ref val2, ref val3);
			_lastAudioWorldPos = audioWorldPosition;
		}

		private void Update()
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			VideoPlayer val = ((_slots != null && _activeSlot >= 0 && _activeSlot < _slots.Length) ? _slots[_activeSlot].Player : null);
			if ((Object)(object)_screenRenderTexture != (Object)null && (Object)(object)val != (Object)null && (val.isPlaying || val.isPrepared))
			{
				CompositeToScreen(_slots[_activeSlot].RenderTexture);
			}
			if ((Object)(object)_statusText != (Object)null && ((Component)_statusText).gameObject.activeSelf)
			{
				UpdateStatusTransform();
			}
			if (!_activeChannelValid)
			{
				return;
			}
			UpdateAudioSpatialization();
			_driftCheckTimer -= Time.unscaledDeltaTime;
			if (_driftCheckTimer > 0f)
			{
				return;
			}
			_driftCheckTimer = 2f;
			if ((Object)(object)val == (Object)null || !val.isPlaying)
			{
				return;
			}
			uint num = default(uint);
			((Channel)(ref _activeChannel)).getPosition(ref num, (TIMEUNIT)1);
			double num2 = val.time * 1000.0;
			double num3 = num2 - (double)num;
			if (Math.Abs(num3) > 250.0)
			{
				((Channel)(ref _activeChannel)).setPosition((uint)num2, (TIMEUNIT)1);
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogDebug((object)$"Theater drift correction: {num3:F1}ms → setPosition({num2:F0})");
				}
			}
		}

		private void OnDestroy()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Current == (Object)(object)this)
			{
				Current = null;
			}
			StopActiveChannel();
			if ((Object)(object)_screenMaterial != (Object)null)
			{
				for (int i = 0; i < _screenBindings.Length; i++)
				{
					_screenMaterial.SetTexture(_screenBindings[i].Name, _screenBindings[i].Texture);
					_screenMaterial.SetTextureScale(_screenBindings[i].Name, _screenBindings[i].Scale);
					_screenMaterial.SetTextureOffset(_screenBindings[i].Name, _screenBindings[i].Offset);
				}
			}
			if (_slots != null)
			{
				for (int j = 0; j < _slots.Length; j++)
				{
					VideoPlayer player = _slots[j].Player;
					if (player != null)
					{
						player.Stop();
					}
					if ((Object)(object)_slots[j].RenderTexture != (Object)null)
					{
						_slots[j].RenderTexture.Release();
						Object.Destroy((Object)(object)_slots[j].RenderTexture);
					}
				}
			}
			if (_sounds == null)
			{
				return;
			}
			for (int k = 0; k < _sounds.Length; k++)
			{
				if (_sounds[k].handle != IntPtr.Zero)
				{
					((Sound)(ref _sounds[k])).release();
				}
			}
		}

		private static int Wrap(int v, int n)
		{
			return (v % n + n) % n;
		}
	}
	internal sealed class VideoEntry
	{
		public string VideoPath;

		public string AudioPath;

		public string Name => Path.GetFileName(VideoPath);
	}
	internal static class VideoLibrary
	{
		private static readonly string[] VideoExtensions = new string[6] { ".mp4", ".webm", ".mov", ".ogv", ".mkv", ".m4v" };

		private static readonly string[] AudioExtensions = new string[6] { ".ogg", ".wav", ".mp3", ".m4a", ".aac", ".flac" };

		private static readonly string[] DedicatedSubfolders = new string[3] { "Videos", "Video", "video" };

		public static List<VideoEntry> Entries { get; private set; } = new List<VideoEntry>();


		public static List<string> Videos => Entries.ConvertAll((VideoEntry e) => e.VideoPath);

		public static void ScanAll(string pluginsRoot, ManualLogSource log)
		{
			Entries.Clear();
			if (!Directory.Exists(pluginsRoot))
			{
				log.LogWarning((object)("Plugins root '" + pluginsRoot + "' does not exist."));
				return;
			}
			HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			string[] directories = Directory.GetDirectories(pluginsRoot);
			foreach (string text in directories)
			{
				string[] dedicatedSubfolders = DedicatedSubfolders;
				foreach (string path in dedicatedSubfolders)
				{
					string path2 = Path.Combine(text, path);
					if (!Directory.Exists(path2))
					{
						continue;
					}
					string[] files = Directory.GetFiles(path2);
					foreach (string text2 in files)
					{
						if (IsVideoFile(text2))
						{
							AddEntry(text2, requireSidecar: false, seen, log);
						}
					}
				}
				dedicatedSubfolders = Directory.GetFiles(text);
				foreach (string text3 in dedicatedSubfolders)
				{
					if (IsVideoFile(text3))
					{
						AddEntry(text3, requireSidecar: true, seen, log);
					}
				}
			}
			Entries = Entries.OrderBy<VideoEntry, string>((VideoEntry e) => Path.GetFileName(e.VideoPath), StringComparer.OrdinalIgnoreCase).ToList();
			if (Entries.Count == 0)
			{
				log.LogInfo((object)"No video files found (looked in plugin Videos/, Video/, and plugin roots with sidecar audio).");
				return;
			}
			int num = Entries.Count((VideoEntry e) => e.AudioPath != null);
			log.LogInfo((object)$"Theater loaded {Entries.Count} video(s) ({num} with sidecar audio):");
			foreach (VideoEntry entry in Entries)
			{
				string text4 = ((entry.AudioPath != null) ? (" + " + Path.GetFileName(entry.AudioPath)) : "  (silent — no sidecar)");
				log.LogInfo((object)("  - " + entry.Name + text4));
			}
		}

		private static void AddEntry(string file, bool requireSidecar, HashSet<string> seen, ManualLogSource log)
		{
			if (seen.Add(Path.GetFullPath(file)))
			{
				string text = FindSidecarAudio(file);
				if (!requireSidecar || text != null)
				{
					Entries.Add(new VideoEntry
					{
						VideoPath = file,
						AudioPath = text
					});
				}
			}
		}

		private static bool IsVideoFile(string path)
		{
			return Array.IndexOf(VideoExtensions, Path.GetExtension(path).ToLowerInvariant()) >= 0;
		}

		private static string FindSidecarAudio(string videoPath)
		{
			string directoryName = Path.GetDirectoryName(videoPath);
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(videoPath);
			string[] audioExtensions = AudioExtensions;
			foreach (string text in audioExtensions)
			{
				string text2 = Path.Combine(directoryName, fileNameWithoutExtension + text);
				if (File.Exists(text2))
				{
					return text2;
				}
			}
			return null;
		}
	}
	internal class VolumeSliderUi : MonoBehaviour
	{
		private static readonly int[] ScreenResolutionOptions = new int[3] { 1024, 1536, 2048 };

		public static VolumeSliderUi Instance;

		private Slider _resolutionSlider;

		private TextMeshProUGUI _resolutionValueLabel;

		private Slider _volumeSlider;

		private Slider _overscanSlider;

		public static void EnsureExists(PauseMenu pauseMenu)
		{
			//IL_003e: 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)
			if (!((Object)(object)Instance != (Object)null) && !((Object)(object)pauseMenu == (Object)null) && !((Object)(object)pauseMenu.menuContainer == (Object)null))
			{
				GameObject val = new GameObject("SBG-TheaterVolumeSlider", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent(pauseMenu.menuContainer.transform, false);
				Instance = val.AddComponent<VolumeSliderUi>();
			}
		}

		public static void HandlePauseShown()
		{
			EnsureExists(SingletonBehaviour<PauseMenu>.Instance);
			if (!((Object)(object)Instance == (Object)null))
			{
				Instance.SyncFromConfig();
				Instance.SetVisible((Object)(object)TheaterController.Current != (Object)null);
			}
		}

		public static void HandlePauseHidden()
		{
			Instance?.SetVisible(visible: false);
		}

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)((Component)this).transform;
			val.anchorMin = new Vector2(0.5f, 0f);
			val.anchorMax = new Vector2(0.5f, 0f);
			val.pivot = new Vector2(0.5f, 0f);
			val.anchoredPosition = new Vector2(0f, 64f);
			val.sizeDelta = new Vector2(420f, 144f);
			GameObject val2 = new GameObject("Panel", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val2.transform.SetParent(((Component)this).transform, false);
			RectTransform component = val2.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			((Graphic)val2.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.65f);
			(Slider, TextMeshProUGUI) tuple = CreateDiscreteSliderRow(val2.transform, "Screen res", 48f, ScreenResolutionOptions, Plugin.GetConfiguredScreenResolution(), delegate(int v)
			{
				Plugin.ScreenResolutionConfig.Value = v;
				TheaterController.Current?.ApplyConfiguredScreenResolution();
			});
			_resolutionSlider = tuple.Item1;
			_resolutionValueLabel = tuple.Item2;
			_volumeSlider = CreateSliderRow(val2.transform, "Theater volume", 0f, 0f, 1f, Plugin.VolumeConfig.Value, delegate(float v)
			{
				Plugin.VolumeConfig.Value = v;
				TheaterController.Current?.SetVolume(v);
			});
			_overscanSlider = CreateSliderRow(val2.transform, "Screen fit", -48f, 0f, 0.25f, Plugin.OverscanCompensationConfig.Value, delegate(float v)
			{
				Plugin.OverscanCompensationConfig.Value = v;
				TheaterController.Current?.RefreshDisplayComposition();
			});
			SetVisible(visible: false);
		}

		private static Slider CreateSliderRow(Transform parent, string labelTextValue, float y, float min, float max, float value, UnityAction<float> onChanged)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_0104: Expected O, but got Unknown
			//IL_0122: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: 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)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Expected O, but got Unknown
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(labelTextValue + " Label", new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 0.5f);
			component.anchorMax = new Vector2(0f, 0.5f);
			component.pivot = new Vector2(0f, 0.5f);
			component.anchoredPosition = new Vector2(14f, y);
			component.sizeDelta = new Vector2(120f, 24f);
			TextMeshProUGUI component2 = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component2).text = labelTextValue;
			((TMP_Text)component2).fontSize = 16f;
			((TMP_Text)component2).alignment = (TextAlignmentOptions)4097;
			((Graphic)component2).color = Color.white;
			GameObject val2 = new GameObject(labelTextValue + " Slider", new Type[2]
			{
				typeof(RectTransform),
				typeof(Slider)
			});
			val2.transform.SetParent(parent, false);
			RectTransform component3 = val2.GetComponent<RectTransform>();
			component3.anchorMin = new Vector2(0f, 0.5f);
			component3.anchorMax = new Vector2(1f, 0.5f);
			component3.pivot = new Vector2(0f, 0.5f);
			component3.anchoredPosition = new Vector2(140f, y);
			component3.sizeDelta = new Vector2(-160f, 16f);
			Slider component4 = val2.GetComponent<Slider>();
			component4.minValue = min;
			component4.maxValue = max;
			component4.value = value;
			GameObject val3 = new GameObject("Bg", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val3.transform.SetParent(val2.transform, false);
			RectTransform component5 = val3.GetComponent<RectTransform>();
			component5.anchorMin = new Vector2(0f, 0.25f);
			component5.anchorMax = new Vector2(1f, 0.75f);
			component5.sizeDelta = Vector2.zero;
			((Graphic)val3.GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.2f);
			GameObject val4 = new GameObject("Fill Area", new Type[1] { typeof(RectTransform) });
			val4.transform.SetParent(val2.transform, false);
			RectTransform component6 = val4.GetComponent<RectTransform>();
			component6.anchorMin = new Vector2(0f, 0.25f);
			component6.anchorMax = new Vector2(1f, 0.75f);
			component6.sizeDelta = new Vector2(-20f, 0f);
			component6.anchoredPosition = new Vector2(-5f, 0f);
			GameObject val5 = new GameObject("Fill", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val5.transform.SetParent(val4.transform, false);
			RectTransform component7 = val5.GetComponent<RectTransform>();
			component7.sizeDelta = Vector2.zero;
			((Graphic)val5.GetComponent<Image>()).color = new Color(0.4f, 0.85f, 1f, 1f);
			GameObject val6 = new GameObject("Handle Slide Area", new Type[1] { typeof(RectTransform) });
			val6.transform.SetParent(val2.transform, false);
			RectTransform component8 = val6.GetComponent<RectTransform>();
			component8.anchorMin = new Vector2(0f, 0f);
			component8.anchorMax = new Vector2(1f, 1f);
			component8.sizeDelta = new Vector2(-20f, 0f);
			component8.anchoredPosition = new Vector2(-5f, 0f);
			GameObject val7 = new GameObject("Handle", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val7.transform.SetParent(val6.transform, false);
			RectTransform component9 = val7.GetComponent<RectTransform>();
			component9.sizeDelta = new Vector2(20f, 20f);
			Image component10 = val7.GetComponent<Image>();
			((Graphic)component10).color = Color.white;
			((Selectable)component4).targetGraphic = (Graphic)(object)component10;
			component4.fillRect = component7;
			component4.handleRect = component9;
			component4.direction = (Direction)0;
			((UnityEvent<float>)(object)component4.onValueChanged).AddListener(onChanged);
			return component4;
		}

		private static (Slider Slider, TextMeshProUGUI ValueLabel) CreateDiscreteSliderRow(Transform parent, string labelTextValue, float y, int[] options, int selectedValue, Action<int> onChanged)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			Slider slider = CreateSliderRow(parent, labelTextValue, y, 0f, options.Length - 1, 0f, delegate
			{
			});
			slider.wholeNumbers = true;
			GameObject val = new GameObject(labelTextValue + " Value", new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 0.5f);
			component.anchorMax = new Vector2(1f, 0.5f);
			component.pivot = new Vector2(1f, 0.5f);
			component.anchoredPosition = new Vector2(-12f, y);
			component.sizeDelta = new Vector2(60f, 24f);
			TextMeshProUGUI valueText = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)valueText).fontSize = 16f;
			((TMP_Text)valueText).alignment = (TextAlignmentOptions)4100;
			((Graphic)valueText).color = Color.white;
			int num = 0;
			for (int i = 0; i < options.Length; i++)
			{
				if (options[i] == selectedValue)
				{
					num = i;
					break;
				}
			}
			slider.SetValueWithoutNotify((float)num);
			((TMP_Text)valueText).text = options[num].ToString();
			((UnityEventBase)slider.onValueChanged).RemoveAllListeners();
			((UnityEvent<float>)(object)slider.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				int num2 = Mathf.Clamp(Mathf.RoundToInt(v), 0, options.Length - 1);
				slider.SetValueWithoutNotify((float)num2);
				((TMP_Text)valueText).text = options[num2].ToString();
				onChanged(options[num2]);
			});
			return (slider, valueText);
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void SyncFromConfig()
		{
			if ((Object)(object)_resolutionSlider != (Object)null)
			{
				int configuredScreenResolution = Plugin.GetConfiguredScreenResolution();
				int num = 0;
				for (int i = 0; i < ScreenResolutionOptions.Length; i++)
				{
					if (ScreenResolutionOptions[i] == configuredScreenResolution)
					{
						num = i;
						break;
					}
				}
				_resolutionSlider.SetValueWithoutNotify((float)num);
				if ((Object)(object)_resolutionValueLabel != (Object)null)
				{
					((TMP_Text)_resolutionValueLabel).text = ScreenResolutionOptions[num].ToString();
				}
			}
			Slider volumeSlider = _volumeSlider;
			if (volumeSlider != null)
			{
				volumeSlider.SetValueWithoutNotify(Plugin.VolumeConfig.Value);
			}
			Slider overscanSlider = _overscanSlider;
			if (overscanSlider != null)
			{
				overscanSlider.SetValueWithoutNotify(Plugin.OverscanCompensationConfig.Value);
			}
		}

		public void SetVisible(bool visible)
		{
			((Component)this).gameObject.SetActive(visible);
		}
	}
}