Decompiled source of BetterReadyUp v1.1.1

BetterReadyUp.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using On.RoR2;
using On.RoR2.UI;
using RoR2;
using RoR2.UI;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BetterReadyUp
{
	[BepInPlugin("com.jectu.betterreadyup", "Better Ready Up", "1.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class BetterReadyUpPlugin : BaseUnityPlugin
	{
		private Texture2D optionsIconTexture;

		private Sprite optionsIconSprite;

		private ConfigEntry<int> multiplayerCountdown;

		private ConfigEntry<int> singleplayerCountdown;

		private VoteController vote;

		private readonly Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);

		private Button forceReadyButton;

		private RectTransform forceReadyRect;

		private RectTransform forceReadyCanvasRect;

		private CharacterSelectController forceReadyController;

		private TextMeshProUGUI forceReadyLabel;

		private CharacterSelectController styledController;

		private bool? lastReadyState;

		private ColorBlock originalColors;

		private Sprite originalSprite;

		private Color originalImageColor;

		private TextMeshProUGUI readyLabel;

		private string originalLabel;

		private Image readyImage;

		private TextMeshProUGUI soloTimerLabel;

		private GameObject soloTimerPanel;

		private CharacterSelectController soloTimerController;

		private Image soloVoteIcon;

		private Sprite soloUnreadySprite;

		private Sprite soloReadySprite;

		private int lastSoloTimerSecond = -1;

		private bool soloTimerHasStarted;

		private void Awake()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			multiplayerCountdown = ((BaseUnityPlugin)this).Config.Bind<int>("Multiplayer", "Ready Countdown Seconds", 5, new ConfigDescription("Multiplayer: seconds after everyone readies before launch (host setting).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 60), Array.Empty<object>()));
			singleplayerCountdown = ((BaseUnityPlugin)this).Config.Bind<int>("Singleplayer", "Ready Countdown Seconds", 5, new ConfigDescription("Single-player: seconds after pressing Ready before launch. Press Unready to cancel. Set to 0 to restore vanilla instant-start behaviour.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 60), Array.Empty<object>()));
			LoadTranslations();
			TryRegisterOptionalRiskOfOptions();
			PreGameController.OnEnable += new hook_OnEnable(PreGameEnabled);
			PreGameController.OnDisable += new hook_OnDisable(PreGameDisabled);
			CharacterSelectController.ClientSetReady += new hook_ClientSetReady(ClientSetReadyToggle);
			CharacterSelectController.Update += new hook_Update(CharacterSelectUpdate);
		}

		private void OnDestroy()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			DestroyForceReadyButton();
			DestroySoloTimer();
			PreGameController.OnEnable -= new hook_OnEnable(PreGameEnabled);
			PreGameController.OnDisable -= new hook_OnDisable(PreGameDisabled);
			CharacterSelectController.ClientSetReady -= new hook_ClientSetReady(ClientSetReadyToggle);
			CharacterSelectController.Update -= new hook_Update(CharacterSelectUpdate);
		}

		private void LoadTranslations()
		{
			string directoryName = Path.GetDirectoryName(((object)this).GetType().Assembly.Location);
			string text = Path.Combine(directoryName, "translations.txt");
			if (!File.Exists(text))
			{
				text = Path.Combine(Path.GetDirectoryName(directoryName), "translations.txt");
			}
			if (!File.Exists(text))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU LANGUAGE] translations.txt missing, using English.");
				return;
			}
			try
			{
				string text2 = null;
				string[] array = File.ReadAllLines(text);
				for (int i = 0; i < array.Length; i++)
				{
					string text3 = array[i].Trim();
					if (text3.Length == 0 || text3.StartsWith("#") || text3.StartsWith(";"))
					{
						continue;
					}
					if (text3.StartsWith("[") && text3.EndsWith("]"))
					{
						text2 = text3.Substring(1, text3.Length - 2).Trim();
						if (!translations.ContainsKey(text2))
						{
							translations[text2] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
						}
						continue;
					}
					int num = text3.IndexOf('=');
					if (text2 != null && num >= 1)
					{
						string key = text3.Substring(0, num).Trim();
						string text4 = text3.Substring(num + 1).Trim();
						if (text4.Length > 0)
						{
							translations[text2][key] = text4;
						}
					}
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[BRU LANGUAGE] Loaded translations.txt (" + translations.Count + " language sections) from " + text));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[BRU LANGUAGE] Couldn't read translations.txt: " + ex.Message));
			}
		}

		private string GetTranslatedText(string key)
		{
			string currentLanguageName = Language.currentLanguageName;
			if (!string.IsNullOrEmpty(currentLanguageName) && translations.TryGetValue(currentLanguageName, out var value) && value.TryGetValue(key, out var value2))
			{
				return value2;
			}
			if (translations.TryGetValue("en", out value) && value.TryGetValue(key, out value2))
			{
				return value2;
			}
			if (!(key == "Unready"))
			{
				if (key == "ForceReady")
				{
					return "Force Ready (ALL)";
				}
				return key;
			}
			return "Unready";
		}

		private void TryRegisterOptionalRiskOfOptions()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
				{
					return;
				}
				TryRegisterOptionalCountdownSliders();
				string directoryName = Path.GetDirectoryName(((object)this).GetType().Assembly.Location);
				string path = Path.Combine(directoryName, "icon.png");
				if (!File.Exists(path))
				{
					path = Path.Combine(Path.GetDirectoryName(directoryName), "icon.png");
				}
				if (!File.Exists(path))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU OPTIONS] Risk of Options installed, but icon.png was not found beside BetterReadyUp.dll or one directory above it.");
					return;
				}
				byte[] array = File.ReadAllBytes(path);
				optionsIconTexture = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(optionsIconTexture, array, false))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU OPTIONS] icon.png is not a valid PNG image.");
					Object.Destroy((Object)(object)optionsIconTexture);
					optionsIconTexture = null;
					return;
				}
				((Object)optionsIconTexture).name = "BetterReadyUpOptionsIconTexture";
				optionsIconSprite = Sprite.Create(optionsIconTexture, new Rect(0f, 0f, (float)((Texture)optionsIconTexture).width, (float)((Texture)optionsIconTexture).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)optionsIconSprite).name = "BetterReadyUpOptionsIcon";
				Type type = Type.GetType("RiskOfOptions.ModSettingsManager, RiskOfOptions", throwOnError: false);
				if (type == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU OPTIONS] Risk of Options is installed, but its ModSettingsManager API wasn't found.");
					return;
				}
				MethodInfo method = type.GetMethod("SetModIcon", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
				{
					typeof(Sprite),
					typeof(string),
					typeof(string)
				}, null);
				if (method == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU OPTIONS] Risk of Options does not expose the expected SetModIcon(Sprite, string, string) API.");
					return;
				}
				method.Invoke(null, new object[3] { optionsIconSprite, "com.jectu.betterreadyup", "Better Ready Up" });
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[BRU OPTIONS] Skipping optional icon integration: " + ex));
			}
		}

		private void TryRegisterOptionalCountdownSliders()
		{
			try
			{
				Type type = Type.GetType("RiskOfOptions.ModSettingsManager, RiskOfOptions", throwOnError: false);
				Type type2 = Type.GetType("RiskOfOptions.Options.IntSliderOption, RiskOfOptions", throwOnError: false);
				Type type3 = Type.GetType("RiskOfOptions.OptionConfigs.IntSliderConfig, RiskOfOptions", throwOnError: false);
				Type type4 = Type.GetType("RiskOfOptions.Options.BaseOption, RiskOfOptions", throwOnError: false);
				if (type == null || type2 == null || type3 == null || type4 == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU OPTIONS] Native slider API not available; icon integration can still work.");
					return;
				}
				MethodInfo method = type.GetMethod("AddOption", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
				{
					type4,
					typeof(string),
					typeof(string)
				}, null);
				if (method == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU OPTIONS] AddOption(BaseOption, string, string) API not found.");
					return;
				}
				ConstructorInfo constructor = type2.GetConstructor(new Type[2]
				{
					typeof(ConfigEntry<int>),
					type3
				});
				if (constructor == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU OPTIONS] IntSliderOption(ConfigEntry<int>, IntSliderConfig) constructor not found.");
					return;
				}
				object obj = Activator.CreateInstance(type3);
				object obj2 = Activator.CreateInstance(type3);
				SetSliderBounds(type3, obj);
				SetSliderBounds(type3, obj2);
				object obj3 = constructor.Invoke(new object[2] { multiplayerCountdown, obj });
				object obj4 = constructor.Invoke(new object[2] { singleplayerCountdown, obj2 });
				object[] array = new object[3] { null, "com.jectu.betterreadyup", "Better Ready Up" };
				array[0] = obj3;
				method.Invoke(null, array);
				array[0] = obj4;
				method.Invoke(null, array);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[BRU OPTIONS] Native slider registration skipped: " + ex));
			}
		}

		private static void SetSliderBounds(Type configType, object config)
		{
			string[] array = new string[2] { "min", "max" };
			foreach (string text in array)
			{
				int num = ((!(text == "min")) ? 60 : 0);
				FieldInfo field = configType.GetField(text, BindingFlags.Instance | BindingFlags.Public);
				if (field != null)
				{
					field.SetValue(config, num);
					continue;
				}
				PropertyInfo property = configType.GetProperty(text, BindingFlags.Instance | BindingFlags.Public);
				if (property == null || !property.CanWrite)
				{
					throw new MissingMemberException(configType.FullName, text);
				}
				property.SetValue(config, num, null);
			}
		}

		private void PreGameEnabled(orig_OnEnable orig, PreGameController self)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			vote = ((Component)self).GetComponent<VoteController>();
			if (Object.op_Implicit((Object)(object)vote) && NetworkServer.active)
			{
				vote.timerStartCondition = (TimerStartCondition)3;
				int num = (RoR2Application.isInSinglePlayer ? singleplayerCountdown.Value : multiplayerCountdown.Value);
				vote.timeoutDuration = Mathf.Clamp(num, 0, 60);
				vote.canChangeVote = true;
				vote.canRevokeVote = true;
				vote.mustTimeOut = true;
				vote.minimumTimeBeforeProcessing = 0f;
			}
		}

		private void PreGameDisabled(orig_OnDisable orig, PreGameController self)
		{
			if (Object.op_Implicit((Object)(object)vote) && (Object)(object)((Component)vote).gameObject == (Object)(object)((Component)self).gameObject)
			{
				vote = null;
			}
			RestoreReadyAppearance();
			DestroyForceReadyButton();
			DestroySoloTimer();
			orig.Invoke(self);
		}

		private void ClientSetReadyToggle(orig_ClientSetReady orig, CharacterSelectController self)
		{
			if (!Object.op_Implicit((Object)(object)PreGameController.instance))
			{
				orig.Invoke(self);
			}
			else if (self.IsClientReady())
			{
				self.ClientSetUnready();
			}
			else
			{
				orig.Invoke(self);
			}
		}

		private void CharacterSelectUpdate(orig_Update orig, CharacterSelectController self)
		{
			orig.Invoke(self);
			if (Object.op_Implicit((Object)(object)PreGameController.instance) && Object.op_Implicit((Object)(object)vote) && ((Behaviour)vote).enabled && Object.op_Implicit((Object)(object)self.readyButton))
			{
				if (!((Component)self.readyButton).gameObject.activeSelf)
				{
					((Component)self.readyButton).gameObject.SetActive(true);
				}
				if (Object.op_Implicit((Object)(object)self.unreadyButton) && (Object)(object)((Component)self.unreadyButton).gameObject != (Object)(object)((Component)self.readyButton).gameObject && ((Component)self.unreadyButton).gameObject.activeSelf)
				{
					((Component)self.unreadyButton).gameObject.SetActive(false);
				}
				bool num = RoR2Application.isInSinglePlayer && singleplayerCountdown.Value == 0;
				bool flag = self.IsClientReady();
				bool flag2 = !(num && flag);
				if (((Selectable)self.readyButton).interactable != flag2)
				{
					((Selectable)self.readyButton).interactable = flag2;
				}
				bool isReady = self.IsClientReady();
				UpdateReadyAppearance(self, isReady);
				if (RoR2Application.isInSinglePlayer)
				{
					DestroyForceReadyButton();
					UpdateSoloTimer(self, isReady);
				}
				else
				{
					DestroySoloTimer();
					UpdateForceReadyButton(self);
				}
			}
		}

		private void RestoreReadyAppearance()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)styledController) && Object.op_Implicit((Object)(object)styledController.readyButton))
			{
				((Selectable)styledController.readyButton).colors = originalColors;
				if (Object.op_Implicit((Object)(object)readyImage))
				{
					readyImage.sprite = originalSprite;
					((Graphic)readyImage).color = originalImageColor;
				}
				if (Object.op_Implicit((Object)(object)readyLabel))
				{
					((TMP_Text)readyLabel).SetText(originalLabel, true);
				}
			}
			styledController = null;
			lastReadyState = null;
			readyLabel = null;
			readyImage = null;
		}

		private void UpdateReadyAppearance(CharacterSelectController self, bool isReady)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0092: 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_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: 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_0296: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)styledController != (Object)(object)self)
			{
				RestoreReadyAppearance();
				styledController = self;
				originalColors = ((Selectable)self.readyButton).colors;
				ref Image reference = ref readyImage;
				Graphic targetGraphic = ((Selectable)self.readyButton).targetGraphic;
				reference = (Image)(object)((targetGraphic is Image) ? targetGraphic : null);
				if (!Object.op_Implicit((Object)(object)readyImage))
				{
					readyImage = ((Component)self.readyButton).GetComponent<Image>();
				}
				originalSprite = (Object.op_Implicit((Object)(object)readyImage) ? readyImage.sprite : null);
				originalImageColor = (Object.op_Implicit((Object)(object)readyImage) ? ((Graphic)readyImage).color : Color.white);
				TextMeshProUGUI[] componentsInChildren = ((Component)self.readyButton).GetComponentsInChildren<TextMeshProUGUI>(true);
				readyLabel = null;
				TextMeshProUGUI[] array = componentsInChildren;
				foreach (TextMeshProUGUI val in array)
				{
					if (Object.op_Implicit((Object)(object)val) && ((TMP_Text)val).text != null && ((TMP_Text)val).text.Trim().Equals("READY", StringComparison.OrdinalIgnoreCase))
					{
						readyLabel = val;
						break;
					}
				}
				if (!Object.op_Implicit((Object)(object)readyLabel) && componentsInChildren.Length != 0)
				{
					readyLabel = componentsInChildren[0];
				}
				originalLabel = (Object.op_Implicit((Object)(object)readyLabel) ? ((TMP_Text)readyLabel).text : null);
			}
			bool flag = RoR2Application.isInSinglePlayer && singleplayerCountdown.Value == 0;
			string text = (isReady ? GetTranslatedText("Unready") : originalLabel);
			if (Object.op_Implicit((Object)(object)readyLabel) && !(flag && isReady) && ((TMP_Text)readyLabel).text != text)
			{
				((TMP_Text)readyLabel).SetText(text, true);
			}
			if (lastReadyState.HasValue && lastReadyState.Value == isReady)
			{
				return;
			}
			lastReadyState = isReady;
			MPButton readyButton = self.readyButton;
			if (isReady && !flag)
			{
				if (Object.op_Implicit((Object)(object)self.unreadyButton))
				{
					((Selectable)readyButton).colors = ((Selectable)self.unreadyButton).colors;
				}
				Image val2 = null;
				if (Object.op_Implicit((Object)(object)self.unreadyButton))
				{
					Graphic targetGraphic2 = ((Selectable)self.unreadyButton).targetGraphic;
					val2 = (Image)(object)((targetGraphic2 is Image) ? targetGraphic2 : null);
					if (!Object.op_Implicit((Object)(object)val2))
					{
						val2 = ((Component)self.unreadyButton).GetComponent<Image>();
					}
				}
				if (Object.op_Implicit((Object)(object)readyImage))
				{
					if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.sprite))
					{
						readyImage.sprite = val2.sprite;
					}
					((Graphic)readyImage).color = new Color(0.85f, 0.22f, 0.22f, originalImageColor.a);
				}
			}
			else
			{
				((Selectable)readyButton).colors = originalColors;
				if (Object.op_Implicit((Object)(object)readyImage))
				{
					readyImage.sprite = originalSprite;
					((Graphic)readyImage).color = originalImageColor;
				}
				if (Object.op_Implicit((Object)(object)readyLabel) && !(flag && isReady))
				{
					((TMP_Text)readyLabel).SetText(text, true);
				}
			}
		}

		private void DestroySoloTimer()
		{
			if (Object.op_Implicit((Object)(object)soloTimerPanel))
			{
				Object.Destroy((Object)(object)soloTimerPanel);
			}
			soloTimerPanel = null;
			soloTimerLabel = null;
			soloTimerController = null;
			soloVoteIcon = null;
			soloUnreadySprite = null;
			soloReadySprite = null;
			lastSoloTimerSecond = -1;
			soloTimerHasStarted = false;
		}

		private void UpdateSoloTimer(CharacterSelectController controller, bool isReady)
		{
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)vote) || !((Behaviour)vote).enabled || !Object.op_Implicit((Object)(object)controller.readyButton) || singleplayerCountdown.Value == 0)
			{
				DestroySoloTimer();
				return;
			}
			if ((Object)(object)soloTimerController != (Object)(object)controller || !Object.op_Implicit((Object)(object)soloTimerPanel))
			{
				DestroySoloTimer();
				Transform val = ((Component)controller).transform.Find("SafeArea/ReadyPanel/VerticalLayoutGroup/VoteInfoPanel");
				if (!Object.op_Implicit((Object)(object)val))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU SOLO UI] Native VoteInfoPanel not found in solo prefab.");
					return;
				}
				soloTimerPanel = Object.Instantiate<GameObject>(((Component)val).gameObject, val.parent, false);
				((Object)soloTimerPanel).name = "BetterReadyUp Native Solo VoteInfoPanel";
				soloTimerPanel.transform.SetSiblingIndex(val.GetSiblingIndex() + 1);
				VoteInfoPanelController component = soloTimerPanel.GetComponent<VoteInfoPanelController>();
				if (Object.op_Implicit((Object)(object)component))
				{
					((Behaviour)component).enabled = false;
				}
				Transform val2 = soloTimerPanel.transform.Find("TimerPanel/TimerLabel");
				soloTimerLabel = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<TextMeshProUGUI>() : null);
				Transform val3 = soloTimerPanel.transform.Find("IndicatorContainer");
				Transform val4 = soloTimerPanel.transform.Find("Indicator");
				if (Object.op_Implicit((Object)(object)val3))
				{
					((Component)val3).gameObject.SetActive(true);
				}
				if (Object.op_Implicit((Object)(object)val4))
				{
					((Component)val4).gameObject.SetActive(true);
				}
				if (Object.op_Implicit((Object)(object)val4))
				{
					Image[] componentsInChildren = ((Component)val4).GetComponentsInChildren<Image>(true);
					foreach (Image val5 in componentsInChildren)
					{
						if (Object.op_Implicit((Object)(object)val5.sprite))
						{
							soloVoteIcon = val5;
							((Component)val5).gameObject.SetActive(true);
							break;
						}
					}
				}
				if (Object.op_Implicit((Object)(object)soloVoteIcon))
				{
					soloUnreadySprite = soloVoteIcon.sprite;
					Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
					foreach (Sprite val6 in array)
					{
						if (((Object)val6).name == "texPlayerVoteStatus_1")
						{
							soloReadySprite = val6;
							break;
						}
					}
					if (!Object.op_Implicit((Object)(object)soloReadySprite))
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU SOLO UI] Native ready-state sprite texPlayerVoteStatus_1 was not found.");
					}
				}
				if (!Object.op_Implicit((Object)(object)soloVoteIcon))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU SOLO UI] Native indicator contains no Image with a sprite; its icon may be generated dynamically by VoteInfoPanelController.");
				}
				if (!Object.op_Implicit((Object)(object)soloTimerLabel))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[BRU SOLO UI] Native timer label not found.");
					DestroySoloTimer();
					return;
				}
				Graphic[] componentsInChildren2 = soloTimerPanel.GetComponentsInChildren<Graphic>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].raycastTarget = false;
				}
				GraphicRaycaster[] componentsInChildren3 = soloTimerPanel.GetComponentsInChildren<GraphicRaycaster>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					((Behaviour)componentsInChildren3[i]).enabled = false;
				}
				Selectable[] componentsInChildren4 = soloTimerPanel.GetComponentsInChildren<Selectable>(true);
				for (int i = 0; i < componentsInChildren4.Length; i++)
				{
					((Behaviour)componentsInChildren4[i]).enabled = false;
				}
				soloTimerPanel.SetActive(true);
				soloTimerController = controller;
			}
			if (!soloTimerPanel.activeSelf)
			{
				soloTimerPanel.SetActive(true);
			}
			if (!isReady)
			{
				soloTimerHasStarted = false;
			}
			if (isReady && vote.timerIsActive)
			{
				soloTimerHasStarted = true;
			}
			int num = ((!isReady) ? singleplayerCountdown.Value : ((vote.timerIsActive || !soloTimerHasStarted) ? ((!vote.timerIsActive) ? singleplayerCountdown.Value : Mathf.Max(0, Mathf.CeilToInt(vote.timer - 0.05f))) : 0));
			if (num != lastSoloTimerSecond)
			{
				lastSoloTimerSecond = num;
				((TMP_Text)soloTimerLabel).SetText("0:" + num.ToString("00"), true);
			}
			if (Object.op_Implicit((Object)(object)soloVoteIcon))
			{
				soloVoteIcon.sprite = ((isReady && Object.op_Implicit((Object)(object)soloReadySprite)) ? soloReadySprite : soloUnreadySprite);
				((Graphic)soloVoteIcon).color = Color.white;
			}
		}

		private void ForceEveryoneReady()
		{
			//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_0033: 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)
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)vote) || !((Behaviour)vote).enabled)
			{
				return;
			}
			for (int i = 0; i < vote.GetVoteCount(); i++)
			{
				UserVote val = vote.GetVote(i);
				if (Object.op_Implicit((Object)(object)val.networkUserObject) && !((UserVote)(ref val)).receivedVote)
				{
					NetworkUser component = val.networkUserObject.GetComponent<NetworkUser>();
					if (Object.op_Implicit((Object)(object)component))
					{
						vote.ReceiveUserVote(component, 0);
					}
				}
			}
		}

		private void DestroyForceReadyButton()
		{
			if (Object.op_Implicit((Object)(object)forceReadyButton))
			{
				Object.Destroy((Object)(object)((Component)forceReadyButton).gameObject);
			}
			forceReadyButton = null;
			forceReadyRect = null;
			forceReadyCanvasRect = null;
			forceReadyController = null;
			forceReadyLabel = null;
		}

		private static TextMeshProUGUI FindButtonLabel(Button button, string label)
		{
			TextMeshProUGUI[] componentsInChildren = ((Component)button).GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val) && string.Equals(((TMP_Text)val).text?.Trim(), label, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private void UpdateForceReadyButton(CharacterSelectController controller)
		{
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Unknown result type (might be due to invalid IL or missing references)
			//IL_043d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_0447: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_0459: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0463: Unknown result type (might be due to invalid IL or missing references)
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_049b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Expected O, but got Unknown
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Expected O, but got Unknown
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || Application.isBatchMode || !Object.op_Implicit((Object)(object)vote) || !((Behaviour)vote).enabled || RoR2Application.isInSinglePlayer)
			{
				DestroyForceReadyButton();
				return;
			}
			if ((Object)(object)forceReadyController != (Object)(object)controller || !Object.op_Implicit((Object)(object)forceReadyButton))
			{
				DestroyForceReadyButton();
				Canvas componentInParent = ((Component)controller.readyButton).GetComponentInParent<Canvas>();
				if (!Object.op_Implicit((Object)(object)componentInParent))
				{
					return;
				}
				componentInParent = componentInParent.rootCanvas;
				ref RectTransform reference = ref forceReadyCanvasRect;
				Transform transform = ((Component)componentInParent).transform;
				reference = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				if (!Object.op_Implicit((Object)(object)forceReadyCanvasRect))
				{
					return;
				}
				Button val = null;
				Button[] array = Resources.FindObjectsOfTypeAll<Button>();
				LanguageTextMeshController[] componentsInChildren;
				foreach (Button val2 in array)
				{
					if (!Object.op_Implicit((Object)(object)val2) || !((Component)val2).gameObject.activeInHierarchy || (Object)(object)val2 == (Object)(object)controller.readyButton || !Object.op_Implicit((Object)(object)((Component)val2).GetComponentInParent<Canvas>()))
					{
						continue;
					}
					bool flag = ((Object)val2).name.IndexOf("Back", StringComparison.OrdinalIgnoreCase) >= 0 || Object.op_Implicit((Object)(object)FindButtonLabel(val2, "Back"));
					if (!flag)
					{
						componentsInChildren = ((Component)val2).GetComponentsInChildren<LanguageTextMeshController>(true);
						foreach (LanguageTextMeshController val3 in componentsInChildren)
						{
							string text = (Object.op_Implicit((Object)(object)val3) ? val3.token : null);
							if (!string.IsNullOrEmpty(text) && (text.Equals("BACK", StringComparison.OrdinalIgnoreCase) || text.EndsWith("_BACK", StringComparison.OrdinalIgnoreCase) || text.StartsWith("BACK_", StringComparison.OrdinalIgnoreCase)))
							{
								flag = true;
								break;
							}
						}
					}
					if (flag)
					{
						val = val2;
						break;
					}
				}
				if (!Object.op_Implicit((Object)(object)val))
				{
					return;
				}
				GameObject val4 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)forceReadyCanvasRect, false);
				((Object)val4).name = "BetterReadyUp Force Ready (ALL)";
				forceReadyButton = val4.GetComponent<Button>();
				ref RectTransform reference2 = ref forceReadyRect;
				Transform transform2 = val4.transform;
				reference2 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
				forceReadyController = controller;
				if (!Object.op_Implicit((Object)(object)forceReadyButton) || !Object.op_Implicit((Object)(object)forceReadyRect))
				{
					Object.Destroy((Object)(object)val4);
					DestroyForceReadyButton();
					return;
				}
				forceReadyButton.onClick = new ButtonClickedEvent();
				((UnityEvent)forceReadyButton.onClick).AddListener(new UnityAction(ForceEveryoneReady));
				((Selectable)forceReadyButton).interactable = true;
				Button obj = forceReadyButton;
				Navigation navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)0;
				((Selectable)obj).navigation = navigation;
				forceReadyLabel = ((Component)forceReadyButton).GetComponentInChildren<TextMeshProUGUI>(true);
				if (!Object.op_Implicit((Object)(object)forceReadyLabel))
				{
					TextMeshProUGUI[] componentsInChildren2 = val4.GetComponentsInChildren<TextMeshProUGUI>(true);
					if (componentsInChildren2.Length != 0)
					{
						forceReadyLabel = componentsInChildren2[0];
					}
				}
				componentsInChildren = val4.GetComponentsInChildren<LanguageTextMeshController>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Object.Destroy((Object)(object)componentsInChildren[i]);
				}
				if (Object.op_Implicit((Object)(object)forceReadyLabel))
				{
					((TMP_Text)forceReadyLabel).SetText(GetTranslatedText("ForceReady"), true);
				}
				RectTransform obj2 = forceReadyRect;
				RectTransform obj3 = forceReadyRect;
				Vector2 val5 = default(Vector2);
				((Vector2)(ref val5))..ctor(0.5f, 0.5f);
				obj3.anchorMax = val5;
				obj2.anchorMin = val5;
				forceReadyRect.pivot = new Vector2(0.5f, 0.5f);
				((Transform)forceReadyRect).localScale = Vector3.one;
				((Transform)forceReadyRect).localRotation = Quaternion.identity;
				val4.SetActive(true);
				((Transform)forceReadyRect).SetAsLastSibling();
			}
			if (Object.op_Implicit((Object)(object)forceReadyRect) && Object.op_Implicit((Object)(object)forceReadyCanvasRect) && Object.op_Implicit((Object)(object)controller.readyButton))
			{
				string translatedText = GetTranslatedText("ForceReady");
				if (Object.op_Implicit((Object)(object)forceReadyLabel) && ((TMP_Text)forceReadyLabel).text != translatedText)
				{
					((TMP_Text)forceReadyLabel).SetText(translatedText, true);
				}
				Transform transform3 = ((Component)controller.readyButton).transform;
				RectTransform val6 = (RectTransform)(object)((transform3 is RectTransform) ? transform3 : null);
				if (Object.op_Implicit((Object)(object)val6))
				{
					Vector3[] array2 = (Vector3[])(object)new Vector3[4];
					val6.GetWorldCorners(array2);
					Vector3 val7 = (array2[0] + array2[3]) * 0.5f;
					Vector3 val8 = array2[1] - array2[0];
					Vector3 val9 = array2[3] - array2[0];
					Vector3 val10 = val7 - val8 * 1.21f;
					Vector3 val11 = ((Transform)forceReadyCanvasRect).InverseTransformPoint(val10);
					Vector3 val12 = ((Transform)forceReadyCanvasRect).InverseTransformVector(val9);
					Vector3 val13 = ((Transform)forceReadyCanvasRect).InverseTransformVector(val8);
					forceReadyRect.anchoredPosition = new Vector2(val11.x, val11.y);
					forceReadyRect.SetSizeWithCurrentAnchors((Axis)0, Mathf.Abs(val12.x));
					forceReadyRect.SetSizeWithCurrentAnchors((Axis)1, Mathf.Abs(val13.y) * 0.72f);
				}
			}
		}
	}
}