Decompiled source of SplitWithFriends v1.0.2

BepInEx\plugins\SplitWithFriends\SplitWithFriends.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Extensions;
using FMODUnity;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using SplitWithFriends.Net;
using SplitWithFriends.Patches;
using SplitWithFriends.UI;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
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: AssemblyCompany("SplitWithFriends")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SplitWithFriends")]
[assembly: AssemblyTitle("SplitWithFriends")]
[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 SplitWithFriends
{
	[BepInPlugin("com.splitwithfriends.mod", "SplitWithFriends", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.splitwithfriends.mod";

		public const string NAME = "SplitWithFriends";

		public const string VERSION = "1.0.0";

		internal static Plugin Instance;

		internal static ManualLogSource Logger;

		internal static ConfigEntry<bool> ConfigDebugLogServerInvocations;

		internal static ConfigEntry<string> ConfigSplitKeybind;

		internal static ConfigEntry<bool> ConfigShowOverlay;

		internal static ConfigEntry<float> ConfigSplitHandOffsetX;

		internal static ConfigEntry<float> ConfigSplitHandOffsetY;

		internal static ConfigEntry<float> ConfigSplitHandOffsetZ;

		internal static ConfigEntry<float> Config3DButtonOffsetX;

		internal static ConfigEntry<float> ConfigSMDisplayOffset;

		internal static ConfigEntry<float> ConfigSMDisplayScale;

		internal static ConfigEntry<float> ConfigSMDisplayOffsetY;

		internal static ConfigEntry<float> ConfigSMDisplayScaleY;

		internal static ConfigEntry<bool> ConfigEnableLiveTuner;

		internal static ConfigEntry<float> ConfigHand1StowX;

		internal static ConfigEntry<float> ConfigHand1StowY;

		internal static ConfigEntry<float> ConfigHand1StowZ;

		internal static ConfigEntry<float> ConfigHand2StowX;

		internal static ConfigEntry<float> ConfigHand2StowY;

		internal static ConfigEntry<float> ConfigHand2StowZ;

		internal static ConfigEntry<float> Config3DButtonFallbackX;

		internal static ConfigEntry<float> Config3DButtonFallbackY;

		internal static ConfigEntry<float> Config3DButtonFallbackZ;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			ConfigDebugLogServerInvocations = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogServerInvocations", false, "Log a line on the server every time PlayerSplit is invoked.");
			ConfigSplitKeybind = ((BaseUnityPlugin)this).Config.Bind<string>("Hotkeys", "SplitKey", "P", "Keyboard key to trigger Split. Use Unity InputSystem Key names (e.g., P, Q, Slash).");
			ConfigShowOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowHandIndicator", true, "Show the 'HAND 1 of 2' on-screen indicator while a split round is in progress.");
			ConfigSplitHandOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("SplitHandPosition", "OffsetX", 0.85f, "Local X-offset of the split hand's card area relative to the main hand. Vanilla default is 2.0 (off the table); 0.45 was too cramped (overlapping); 0.85 gives breathing room while staying on the table.");
			ConfigSplitHandOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("SplitHandPosition", "OffsetY", 0f, "Local Y-offset of the split hand's card area.");
			ConfigSplitHandOffsetZ = ((BaseUnityPlugin)this).Config.Bind<float>("SplitHandPosition", "OffsetZ", 0f, "Local Z-offset of the split hand's card area.");
			Config3DButtonOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Table3DButton", "OffsetXFromHit", 0.18f, "Local X offset for the 3D SPLIT button relative to the cloned HIT button. Positive moves it further from STAND in the buttons' row.");
			ConfigSMDisplayOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Holder", "SMDisplayOffset", 0.14f, "How far (in world X and Z, applied diagonally) to shift the SM_Display holder mesh toward SPLIT after scaling. 0.14 is the user-tuned default — fits all 5 buttons cleanly with PLAY not at the edge.");
			ConfigSMDisplayScale = ((BaseUnityPlugin)this).Config.Bind<float>("Holder", "SMDisplayScale", 1.3f, "Scale factor applied to SM_Display's X and Z. 1.0 = no growth. 1.30 is the user-tuned default — comfortable padding around all 5 buttons.");
			ConfigSMDisplayOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Holder", "SMDisplayOffsetY", 0f, "Vertical offset applied to SM_Display worldPos. Positive = up. 0.01 step via Numpad+/-.");
			ConfigSMDisplayScaleY = ((BaseUnityPlugin)this).Config.Bind<float>("Holder", "SMDisplayScaleY", 1f, "Vertical scale factor for SM_Display. 1.0 = original height. >1 = taller holder.");
			ConfigEnableLiveTuner = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableHandStowTuner", true, "Show the bottom-left tuner HUD and enable Numpad hotkeys to nudge the inactive-hand stow positions in real time. Useful if your seat angle makes the default offsets look off. Set false to hide.");
			ConfigHand1StowX = ((BaseUnityPlugin)this).Config.Bind<float>("InactiveHandStow", "Hand1OffsetX", 1.15f, "Hand 1 stow X-offset (applied when hand 2 is active and hand 1 is the inactive one to slide aside).");
			ConfigHand1StowY = ((BaseUnityPlugin)this).Config.Bind<float>("InactiveHandStow", "Hand1OffsetY", -0.2f, "Hand 1 stow Y-offset.");
			ConfigHand1StowZ = ((BaseUnityPlugin)this).Config.Bind<float>("InactiveHandStow", "Hand1OffsetZ", 0.4f, "Hand 1 stow Z-offset.");
			ConfigHand2StowX = ((BaseUnityPlugin)this).Config.Bind<float>("InactiveHandStow", "Hand2OffsetX", 1.1f, "Hand 2 stow X-offset (applied when hand 1 is active and hand 2 is the inactive one to slide aside).");
			ConfigHand2StowY = ((BaseUnityPlugin)this).Config.Bind<float>("InactiveHandStow", "Hand2OffsetY", 0f, "Hand 2 stow Y-offset.");
			ConfigHand2StowZ = ((BaseUnityPlugin)this).Config.Bind<float>("InactiveHandStow", "Hand2OffsetZ", -0.9f, "Hand 2 stow Z-offset.");
			Config3DButtonFallbackX = ((BaseUnityPlugin)this).Config.Bind<float>("Table3DButton", "FallbackPositionX", 0.5f, "If we can't find a button to clone, place the fallback cube at this local position relative to the Blackjack table (X).");
			Config3DButtonFallbackY = ((BaseUnityPlugin)this).Config.Bind<float>("Table3DButton", "FallbackPositionY", 1f, "Fallback cube local Y.");
			Config3DButtonFallbackZ = ((BaseUnityPlugin)this).Config.Bind<float>("Table3DButton", "FallbackPositionZ", 0f, "Fallback cube local Z.");
			_harmony = new Harmony("com.splitwithfriends.mod");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			HolderLiveTuner.EnsureInstalled();
			int num = 0;
			try
			{
				foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
				{
					_ = patchedMethod;
					num++;
				}
			}
			catch
			{
			}
			Logger.LogInfo((object)string.Format("{0} {1} loaded — {2} patches active. Toggle config via BepInEx/config/{3}.cfg.", "SplitWithFriends", "1.0.0", num, "com.splitwithfriends.mod"));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			SplitButtonOverlay.DestroyShared();
		}
	}
}
namespace SplitWithFriends.UI
{
	internal class SplitButtonInteractable : MonoBehaviour, IInteractable
	{
		private Blackjack _bj;

		private Outline _outline;

		private SFXLocalPlayer _sfx;

		private MonoBehaviour _mmfPlayer;

		private MethodInfo _mmfPlayMethod;

		private UIButtonFeedback[] _uiFeedbacks;

		public float HoldDuration { get; set; } = 0.25f;


		public bool HoldInteract { get; set; }

		public bool IsInteractable { get; set; } = true;


		public bool MeetRequirements { get; set; } = true;


		public bool IsBeingHovered { get; set; }

		public bool IsBeingHold { get; set; }

		public float HoldProgress { get; set; }

		public string TooltipMessage { get; set; } = "Press [E] to Interact";


		public string InteractableName { get; set; } = "Split Button";


		public CursorType CursorType { get; set; } = (CursorType)1;


		public event Action<IInteractable> OnInteractableChanged;

		public void Initialize(Blackjack bj)
		{
			_bj = bj;
			InteractableName = "Split Button";
			TooltipMessage = "[E] INTERACT";
		}

		public void AttachVisualHelpers(Outline outline, SFXLocalPlayer sfx, MonoBehaviour mmfPlayer)
		{
			_outline = outline;
			_sfx = sfx;
			_mmfPlayer = mmfPlayer;
			if ((Object)(object)mmfPlayer != (Object)null)
			{
				_mmfPlayMethod = ((object)mmfPlayer).GetType().GetMethod("PlayFeedbacks", Type.EmptyTypes);
			}
			_uiFeedbacks = ((Component)this).GetComponentsInChildren<UIButtonFeedback>(true);
		}

		public void OnHover(PlayerInteract playerInteract)
		{
			IsBeingHovered = true;
			if ((Object)(object)_outline != (Object)null)
			{
				((Behaviour)_outline).enabled = true;
			}
		}

		public void OnHoverExit(PlayerInteract playerInteract)
		{
			IsBeingHovered = false;
			HoldProgress = 0f;
			if ((Object)(object)_outline != (Object)null)
			{
				((Behaviour)_outline).enabled = false;
			}
		}

		public void OnHold(PlayerInteract playerInteract)
		{
			IsBeingHold = true;
		}

		public void OnHoldExit(PlayerInteract playerInteract)
		{
			IsBeingHold = false;
			HoldProgress = 0f;
		}

		public void ServerOnHover(PlayerInteract playerInteract)
		{
		}

		public void ServerOnHoverExit(PlayerInteract playerInteract)
		{
		}

		public void ServerOnHold(PlayerInteract playerInteract)
		{
		}

		public void ServerOnHoldExit(PlayerInteract playerInteract)
		{
		}

		public void ServerOnInteract(PlayerInteract playerInteract)
		{
		}

		public void RpcOnInteract(PlayerInteract playerInteract)
		{
		}

		public void OnInteract(PlayerInteract playerInteract)
		{
			PlayPressFeedback();
			if ((Object)(object)_bj == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends] 3D-button OnInteract: _bj is null, ignoring");
				return;
			}
			if ((Object)(object)playerInteract == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends] 3D-button OnInteract: playerInteract is null, ignoring");
				return;
			}
			Plugin.Logger.LogInfo((object)("[SplitWithFriends] 3D SPLIT button pressed on table '" + ((Object)_bj).name + "'"));
			SplitNetwork.SendSplit(((NetworkBehaviour)_bj).netId, ((NetworkBehaviour)playerInteract).netId);
			this.OnInteractableChanged?.Invoke((IInteractable)(object)this);
		}

		private void PlayPressFeedback()
		{
			bool flag = false;
			if (_mmfPlayMethod != null && (Object)(object)_mmfPlayer != (Object)null)
			{
				try
				{
					_mmfPlayMethod.Invoke(_mmfPlayer, null);
					flag = true;
					Plugin.Logger.LogDebug((object)"[SplitButton/SFX] called MMF_Player.PlayFeedbacks()");
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("[SplitButton] MMF_Player.PlayFeedbacks failed: " + ex.Message));
				}
			}
			if ((Object)(object)_sfx != (Object)null)
			{
				try
				{
					_sfx.PlayOneShotWith3DPos();
					flag = true;
					Plugin.Logger.LogDebug((object)"[SplitButton/SFX] called SFXLocalPlayer.PlayOneShotWith3DPos()");
				}
				catch (Exception ex2)
				{
					Plugin.Logger.LogWarning((object)("[SplitButton] SFXLocalPlayer.PlayOneShotWith3DPos failed: " + ex2.Message));
				}
			}
			if (!flag)
			{
				Plugin.Logger.LogDebug((object)"[SplitButton/SFX] no audio handler attached — silent press.");
			}
			if (_uiFeedbacks == null)
			{
				return;
			}
			UIButtonFeedback[] uiFeedbacks = _uiFeedbacks;
			foreach (UIButtonFeedback val in uiFeedbacks)
			{
				if ((Object)(object)val != (Object)null)
				{
					try
					{
						val.PlayFeedback();
					}
					catch
					{
					}
				}
			}
		}
	}
	internal class SplitButtonOverlay : MonoBehaviour
	{
		private static GameObject _canvasGo;

		private static TextMeshProUGUI _titleLabel;

		private static TextMeshProUGUI _detailLabel;

		private static SplitButtonOverlay _activeOverlay;

		private Blackjack _bj;

		private static FieldInfo _activeHandIndexField;

		private static FieldInfo _hasSplitThisRoundField;

		private static FieldInfo _playerHandField;

		private static FieldInfo _splitHandField;

		public static void AttachTo(Blackjack bj)
		{
			if (!((Object)(object)bj == (Object)null) && !((Object)(object)((Component)bj).gameObject.GetComponent<SplitButtonOverlay>() != (Object)null))
			{
				((Component)bj).gameObject.AddComponent<SplitButtonOverlay>()._bj = bj;
			}
		}

		public static void DestroyShared()
		{
			_activeOverlay = null;
			if ((Object)(object)_canvasGo != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasGo);
				_canvasGo = null;
				_titleLabel = null;
				_detailLabel = null;
			}
		}

		private void Update()
		{
			if ((Object)(object)_bj == (Object)null)
			{
				return;
			}
			if (KeybindPressedThisFrame())
			{
				Plugin.Logger.LogInfo((object)("[SplitWithFriends] Keybind '" + Plugin.ConfigSplitKeybind.Value + "' pressed at table '" + ((Object)_bj).name + "'"));
				if (TryGetSplitEligible(out var pi))
				{
					SplitNetwork.SendSplit(((NetworkBehaviour)_bj).netId, ((NetworkBehaviour)pi).netId);
				}
				else
				{
					Plugin.Logger.LogDebug((object)"[SplitWithFriends] Keybind ignored — split not currently legal for this table.");
				}
			}
			UpdateHandIndicator();
		}

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

		private static bool KeybindPressedThisFrame()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string value = Plugin.ConfigSplitKeybind.Value;
				if (string.IsNullOrEmpty(value))
				{
					value = "P";
				}
				Keyboard current = Keyboard.current;
				if (current == null)
				{
					return false;
				}
				if (Enum.TryParse<Key>(value, ignoreCase: true, out Key result))
				{
					return ((ButtonControl)current[result]).wasPressedThisFrame;
				}
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("[SplitWithFriends] Keybind read failed (giving up): " + ex.GetType().Name + ": " + ex.Message));
				return false;
			}
		}

		private bool TryGetSplitEligible(out PlayerInteract pi)
		{
			pi = null;
			if (!NetworkClient.active)
			{
				return false;
			}
			NetworkIdentity localPlayer = NetworkClient.localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			pi = ((Component)localPlayer).GetComponent<PlayerInteract>();
			if ((Object)(object)pi == (Object)null)
			{
				return false;
			}
			long sharedBalance = NetworkSingleton<MoneyManager>.Instance?.balance ?? long.MaxValue;
			return SplitEligibility.IsLegal(_bj, sharedBalance);
		}

		private void UpdateHandIndicator()
		{
			bool? flag = ReadHasSplitThisRound();
			int? num = ReadActiveHandIndex();
			if (!flag.GetValueOrDefault())
			{
				if ((Object)(object)_activeOverlay == (Object)(object)this && (Object)(object)_canvasGo != (Object)null && _canvasGo.activeSelf)
				{
					_canvasGo.SetActive(false);
				}
				return;
			}
			_activeOverlay = this;
			EnsureCanvas();
			_canvasGo.SetActive(true);
			int valueOrDefault = num.GetValueOrDefault();
			int num2 = valueOrDefault + 1;
			if ((Object)(object)_titleLabel != (Object)null)
			{
				((TMP_Text)_titleLabel).text = $"HAND {num2} OF 2";
			}
			if ((Object)(object)_detailLabel != (Object)null)
			{
				int num3 = ComputeHandValue(_playerHandField, "playerHand");
				int num4 = ComputeHandValue(_splitHandField, "splitHand");
				string text = ((valueOrDefault == 0) ? $"<color=#FF44FF>[Hand 1: {num3}]</color>" : $"Hand 1: {num3}");
				string text2 = ((valueOrDefault == 1) ? $"<color=#FF44FF>[Hand 2: {num4}]</color>" : $"Hand 2: {num4}");
				((TMP_Text)_detailLabel).text = text + "    " + text2;
			}
		}

		private int ComputeHandValue(FieldInfo cached, string fieldName)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Invalid comparison between Unknown and I4
			FieldInfo fieldInfo = cached;
			if (fieldInfo == null)
			{
				fieldInfo = typeof(Blackjack).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
				if (fieldName == "playerHand")
				{
					_playerHandField = fieldInfo;
				}
				else if (fieldName == "splitHand")
				{
					_splitHandField = fieldInfo;
				}
			}
			if (fieldInfo == null)
			{
				return 0;
			}
			if (!(fieldInfo.GetValue(_bj) is SyncList<CardData> val))
			{
				return 0;
			}
			int num = 0;
			int num2 = 0;
			Enumerator<CardData> enumerator = val.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					CardData current = enumerator.Current;
					if ((int)current.Rank == 1)
					{
						num2++;
						num += 11;
					}
					else
					{
						num += ((CardData)(ref current)).GetBlackjackValue();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			while (num > 21 && num2 > 0)
			{
				num -= 10;
				num2--;
			}
			return num;
		}

		private bool? ReadHasSplitThisRound()
		{
			if (_hasSplitThisRoundField == null)
			{
				_hasSplitThisRoundField = typeof(Blackjack).GetField("hasSplitThisRound", BindingFlags.Instance | BindingFlags.NonPublic);
			}
			return _hasSplitThisRoundField?.GetValue(_bj) as bool?;
		}

		private int? ReadActiveHandIndex()
		{
			if (_activeHandIndexField == null)
			{
				_activeHandIndexField = typeof(Blackjack).GetField("activeHandIndex", BindingFlags.Instance | BindingFlags.NonPublic);
			}
			return _activeHandIndexField?.GetValue(_bj) as int?;
		}

		private static void EnsureCanvas()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: 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_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: 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_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: 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_049f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_canvasGo != (Object)null)
			{
				return;
			}
			_canvasGo = new GameObject("SplitWithFriends.HandIndicator");
			Object.DontDestroyOnLoad((Object)(object)_canvasGo);
			Canvas obj = _canvasGo.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32500;
			CanvasScaler obj2 = _canvasGo.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.screenMatchMode = (ScreenMatchMode)0;
			obj2.matchWidthOrHeight = 0.5f;
			_canvasGo.AddComponent<GraphicRaycaster>();
			TMP_FontAsset val = null;
			TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val2 in array)
			{
				if ((Object)(object)val2 != (Object)null && (((Object)val2).name.Contains("Dangrek") || ((Object)val2).name.Contains("dangrek")))
				{
					val = val2;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				TMP_FontAsset[] array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				if (array2 != null && array2.Length != 0)
				{
					val = array2[0];
				}
			}
			Plugin.Logger.LogInfo((object)("[SplitWithFriends/HUD] TMP font for HUD: '" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "<NONE FOUND>") + "'"));
			GameObject val3 = new GameObject("Panel");
			val3.transform.SetParent(_canvasGo.transform, false);
			RectTransform obj3 = val3.AddComponent<RectTransform>();
			obj3.anchorMin = new Vector2(0.5f, 1f);
			obj3.anchorMax = new Vector2(0.5f, 1f);
			obj3.pivot = new Vector2(0.5f, 1f);
			obj3.anchoredPosition = new Vector2(0f, -20f);
			obj3.sizeDelta = new Vector2(440f, 90f);
			((Graphic)val3.AddComponent<Image>()).color = new Color(0.13f, 0.04f, 0.1f, 0.92f);
			GameObject val4 = new GameObject("InnerHighlight");
			val4.transform.SetParent(val3.transform, false);
			RectTransform obj4 = val4.AddComponent<RectTransform>();
			obj4.anchorMin = new Vector2(0f, 0f);
			obj4.anchorMax = new Vector2(1f, 1f);
			obj4.offsetMin = new Vector2(4f, 4f);
			obj4.offsetMax = new Vector2(-4f, -4f);
			((Graphic)val4.AddComponent<Image>()).color = new Color(0.2f, 0.06f, 0.15f, 0.85f);
			GameObject val5 = new GameObject("Border");
			val5.transform.SetParent(val3.transform, false);
			RectTransform obj5 = val5.AddComponent<RectTransform>();
			obj5.anchorMin = Vector2.zero;
			obj5.anchorMax = Vector2.one;
			obj5.offsetMin = new Vector2(-3f, -3f);
			obj5.offsetMax = new Vector2(3f, 3f);
			((Graphic)val5.AddComponent<Image>()).color = new Color(1f, 0.2f, 0.85f, 0.55f);
			val5.transform.SetAsFirstSibling();
			GameObject val6 = new GameObject("Title");
			val6.transform.SetParent(val3.transform, false);
			RectTransform obj6 = val6.AddComponent<RectTransform>();
			obj6.anchorMin = new Vector2(0f, 0.5f);
			obj6.anchorMax = new Vector2(1f, 1f);
			obj6.offsetMin = new Vector2(0f, 0f);
			obj6.offsetMax = new Vector2(0f, 0f);
			_titleLabel = val6.AddComponent<TextMeshProUGUI>();
			((TMP_Text)_titleLabel).text = "HAND 1 OF 2";
			((TMP_Text)_titleLabel).alignment = (TextAlignmentOptions)514;
			((Graphic)_titleLabel).color = new Color(1f, 0.93f, 0.65f, 1f);
			((TMP_Text)_titleLabel).fontSize = 32f;
			((TMP_Text)_titleLabel).fontStyle = (FontStyles)1;
			if ((Object)(object)val != (Object)null)
			{
				((TMP_Text)_titleLabel).font = val;
			}
			GameObject val7 = new GameObject("Detail");
			val7.transform.SetParent(val3.transform, false);
			RectTransform obj7 = val7.AddComponent<RectTransform>();
			obj7.anchorMin = new Vector2(0f, 0f);
			obj7.anchorMax = new Vector2(1f, 0.5f);
			obj7.offsetMin = new Vector2(0f, 0f);
			obj7.offsetMax = new Vector2(0f, 0f);
			_detailLabel = val7.AddComponent<TextMeshProUGUI>();
			((TMP_Text)_detailLabel).text = "Hand 1: 0    Hand 2: 0";
			((TMP_Text)_detailLabel).alignment = (TextAlignmentOptions)514;
			((Graphic)_detailLabel).color = new Color(0.95f, 0.95f, 0.95f, 1f);
			((TMP_Text)_detailLabel).fontSize = 22f;
			((TMP_Text)_detailLabel).richText = true;
			if ((Object)(object)val != (Object)null)
			{
				((TMP_Text)_detailLabel).font = val;
			}
			Plugin.Logger.LogInfo((object)"[SplitWithFriends/HUD] Hand indicator canvas built (TMP).");
		}
	}
	internal static class SplitEligibility
	{
		private static FieldInfo _playerHandField;

		private static FieldInfo _splitHandField;

		private static FieldInfo _dealerHandField;

		public static string CheckLegal(Blackjack bj, long sharedBalance)
		{
			//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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)bj == (Object)null)
			{
				return "bj null";
			}
			SyncList<CardData> privateHand = GetPrivateHand(ref _playerHandField, "playerHand", bj);
			SyncList<CardData> privateHand2 = GetPrivateHand(ref _splitHandField, "splitHand", bj);
			SyncList<CardData> privateHand3 = GetPrivateHand(ref _dealerHandField, "dealerHand", bj);
			if (privateHand == null)
			{
				return "playerHand reflection failed (field name changed?)";
			}
			if (privateHand2 == null)
			{
				return "splitHand reflection failed (field name changed?)";
			}
			if (privateHand3 == null)
			{
				return "dealerHand reflection failed (field name changed?)";
			}
			if (privateHand2.Count != 0)
			{
				return $"splitHand.Count != 0 (was {privateHand2.Count})";
			}
			if (privateHand.Count != 2)
			{
				return $"playerHand.Count != 2 (was {privateHand.Count})";
			}
			if (privateHand3.Count != 2)
			{
				return $"dealerHand.Count != 2 (was {privateHand3.Count})";
			}
			if (privateHand[0].Rank != privateHand[1].Rank)
			{
				return $"ranks not equal (was {privateHand[0].Rank} vs {privateHand[1].Rank})";
			}
			if (sharedBalance < ((GameBase)bj).currentBet)
			{
				return $"balance < bet (balance={sharedBalance}, bet={((GameBase)bj).currentBet})";
			}
			return null;
		}

		public static bool IsLegal(Blackjack bj, long sharedBalance)
		{
			return CheckLegal(bj, sharedBalance) == null;
		}

		private static SyncList<CardData> GetPrivateHand(ref FieldInfo cache, string name, Blackjack bj)
		{
			if (cache == null)
			{
				cache = typeof(Blackjack).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
			}
			return cache?.GetValue(bj) as SyncList<CardData>;
		}
	}
	internal class SplitHandPositioner : MonoBehaviour
	{
		private Blackjack _bj;

		private static FieldInfo _playerCardAreaField;

		private static FieldInfo _playerSplitCardAreaField;

		private static FieldInfo _activeHandIndexField;

		private static FieldInfo _hasSplitThisRoundField;

		private Vector3 _restMain;

		private bool _restMainCaptured;

		private Vector3 _restSplit;

		private bool _restSplitCaptured;

		private static FieldInfo _casinoHelperTextsField;

		private TextMeshPro _helperText0;

		private Vector3 _helperText0RestWorld;

		private bool _helperTextCaptured;

		private float _helperTextHeightAbove;

		private TextMeshPro _inactiveHandLabel;

		public static void AttachTo(Blackjack bj)
		{
			if (!((Object)(object)bj == (Object)null) && !((Object)(object)((Component)bj).gameObject.GetComponent<SplitHandPositioner>() != (Object)null))
			{
				((Component)bj).gameObject.AddComponent<SplitHandPositioner>()._bj = bj;
			}
		}

		private void Update()
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: 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_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: 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_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bj == (Object)null)
			{
				return;
			}
			EnsureReflectionCache();
			object? obj = _playerCardAreaField?.GetValue(_bj);
			Transform val = (Transform)((obj is Transform) ? obj : null);
			object? obj2 = _playerSplitCardAreaField?.GetValue(_bj);
			Transform val2 = (Transform)((obj2 is Transform) ? obj2 : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (!_restMainCaptured)
			{
				_restMain = val.localPosition;
				_restMainCaptured = true;
				ManualLogSource logger = Plugin.Logger;
				object arg = _restMain;
				string name = ((Object)val).name;
				Transform parent = val.parent;
				logger.LogInfo((object)$"[SplitWithFriends/Positioner] captured _restMain = {arg} on '{name}' (parent='{((parent != null) ? ((Object)parent).name : null)}')");
			}
			if ((Object)(object)val2 != (Object)null && !_restSplitCaptured)
			{
				_restSplit = val2.localPosition;
				_restSplitCaptured = true;
				ManualLogSource logger2 = Plugin.Logger;
				object arg2 = _restSplit;
				string name2 = ((Object)val2).name;
				Transform parent2 = val2.parent;
				logger2.LogInfo((object)$"[SplitWithFriends/Positioner] captured _restSplit = {arg2} on '{name2}' (parent='{((parent2 != null) ? ((Object)parent2).name : null)}')");
			}
			bool flag = false;
			int num = 0;
			if (_hasSplitThisRoundField != null)
			{
				flag = (bool)_hasSplitThisRoundField.GetValue(_bj);
			}
			if (_activeHandIndexField != null)
			{
				num = (int)_activeHandIndexField.GetValue(_bj);
			}
			CaptureHelperTextOnce(val);
			if (!flag)
			{
				if (_restMainCaptured)
				{
					val.localPosition = _restMain;
				}
				if ((Object)(object)val2 != (Object)null && _restSplitCaptured)
				{
					val2.localPosition = _restSplit;
				}
				if (_helperTextCaptured && (Object)(object)_helperText0 != (Object)null)
				{
					_helperText0.transform.position = _helperText0RestWorld;
				}
				if ((Object)(object)_inactiveHandLabel != (Object)null)
				{
					((Component)_inactiveHandLabel).gameObject.SetActive(false);
				}
				return;
			}
			Vector3 val3 = default(Vector3);
			((Vector3)(ref val3))..ctor(Plugin.ConfigHand1StowX.Value, Plugin.ConfigHand1StowY.Value, Plugin.ConfigHand1StowZ.Value);
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(Plugin.ConfigHand2StowX.Value, Plugin.ConfigHand2StowY.Value, Plugin.ConfigHand2StowZ.Value);
			Vector3 val5;
			Vector3 val6;
			if (num == 0)
			{
				val5 = _restMain;
				val6 = _restSplit + val4;
			}
			else
			{
				val5 = _restMain + val3;
				val6 = _restSplit;
			}
			if (_restMainCaptured && val.localPosition != val5)
			{
				Vector3 localPosition = val.localPosition;
				val.localPosition = val5;
				Vector3 localPosition2 = val.localPosition;
				Plugin.Logger.LogDebug((object)$"[Positioner] mainArea: {localPosition} → set {val5} → readback {localPosition2}");
			}
			if ((Object)(object)val2 != (Object)null && _restSplitCaptured && val2.localPosition != val6)
			{
				Vector3 localPosition3 = val2.localPosition;
				val2.localPosition = val6;
				Vector3 localPosition4 = val2.localPosition;
				Plugin.Logger.LogDebug((object)$"[Positioner] splitArea: {localPosition3} → set {val6} → readback {localPosition4}");
			}
			if (_helperTextCaptured && (Object)(object)_helperText0 != (Object)null && (Object)(object)val2 != (Object)null)
			{
				Transform val7 = ((num == 0) ? val : val2);
				Transform val8 = ((num == 0) ? val2 : val);
				_helperText0.transform.position = val7.position + new Vector3(0f, _helperTextHeightAbove, 0f);
				EnsureInactiveHandLabel();
				if ((Object)(object)_inactiveHandLabel != (Object)null)
				{
					((Component)_inactiveHandLabel).gameObject.SetActive(true);
					_inactiveHandLabel.transform.position = val8.position + new Vector3(0f, _helperTextHeightAbove, 0f);
					int num2 = ComputeInactiveHandValue(num);
					((TMP_Text)_inactiveHandLabel).text = num2.ToString();
				}
			}
		}

		private void CaptureHelperTextOnce(Transform mainArea)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			if (!_helperTextCaptured)
			{
				if (_casinoHelperTextsField == null)
				{
					_casinoHelperTextsField = typeof(GameBase).GetField("casinoHelperTexts", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				if (!(_casinoHelperTextsField == null) && _casinoHelperTextsField.GetValue(_bj) is TextMeshPro[] array && array.Length != 0 && !((Object)(object)array[0] == (Object)null))
				{
					_helperText0 = array[0];
					_helperText0RestWorld = _helperText0.transform.position;
					_helperTextHeightAbove = _helperText0RestWorld.y - mainArea.position.y;
					_helperTextCaptured = true;
					Plugin.Logger.LogInfo((object)$"[SplitWithFriends/Positioner] captured helper text [0] at world {_helperText0RestWorld}, height-above-main = {_helperTextHeightAbove:F3}m");
				}
			}
		}

		private void EnsureInactiveHandLabel()
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_inactiveHandLabel != (Object)null) && !((Object)(object)_helperText0 == (Object)null))
			{
				GameObject val = Object.Instantiate<GameObject>(((Component)_helperText0).gameObject);
				((Object)val).name = "SplitWithFriends.InactiveHandLabel";
				NetworkBehaviour[] componentsInChildren = val.GetComponentsInChildren<NetworkBehaviour>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Object.Destroy((Object)(object)componentsInChildren[i]);
				}
				NetworkIdentity[] componentsInChildren2 = val.GetComponentsInChildren<NetworkIdentity>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					Object.Destroy((Object)(object)componentsInChildren2[i]);
				}
				val.transform.SetParent(_helperText0.transform.parent, true);
				_inactiveHandLabel = val.GetComponent<TextMeshPro>();
				if ((Object)(object)_inactiveHandLabel != (Object)null)
				{
					((Graphic)_inactiveHandLabel).color = new Color(((Graphic)_inactiveHandLabel).color.r, ((Graphic)_inactiveHandLabel).color.g, ((Graphic)_inactiveHandLabel).color.b, 0.55f);
				}
			}
		}

		private int ComputeInactiveHandValue(int activeIdx)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Invalid comparison between Unknown and I4
			string name = ((activeIdx == 0) ? "splitHand" : "playerHand");
			FieldInfo field = typeof(Blackjack).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
			if (field == null)
			{
				return 0;
			}
			if (!(field.GetValue(_bj) is SyncList<CardData> val))
			{
				return 0;
			}
			int num = 0;
			int num2 = 0;
			Enumerator<CardData> enumerator = val.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					CardData current = enumerator.Current;
					if ((int)current.Rank == 1)
					{
						num2++;
						num += 11;
					}
					else
					{
						num += ((CardData)(ref current)).GetBlackjackValue();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator).Dispose();
			}
			while (num > 21 && num2 > 0)
			{
				num -= 10;
				num2--;
			}
			return num;
		}

		private void EnsureReflectionCache()
		{
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic;
			if (_playerCardAreaField == null)
			{
				_playerCardAreaField = typeof(Blackjack).GetField("playerCardArea", bindingAttr);
			}
			if (_playerSplitCardAreaField == null)
			{
				_playerSplitCardAreaField = typeof(Blackjack).GetField("playerSplitCardArea", bindingAttr);
			}
			if (_activeHandIndexField == null)
			{
				_activeHandIndexField = typeof(Blackjack).GetField("activeHandIndex", bindingAttr);
			}
			if (_hasSplitThisRoundField == null)
			{
				_hasSplitThisRoundField = typeof(Blackjack).GetField("hasSplitThisRound", bindingAttr);
			}
		}
	}
	internal class SplitTableButton : MonoBehaviour
	{
		private Blackjack _bj;

		private GameObject _spawnedButton;

		private InteractableEventTrigger _templateButton;

		private string _lastEligibilityReason = "<init>";

		private bool _holderHierarchyLogged;

		private bool _holderGrown;

		private static FieldInfo _playerHandField;

		private static FieldInfo _splitHandField;

		private static FieldInfo _dealerHandField;

		private Renderer[] _allRenderersCache;

		private Transform _smDisplay;

		private Vector3 _smDisplayOrigScale;

		private Vector3 _smDisplayOrigWorldPos;

		private static bool _buttonComponentsDumped;

		public static void AttachTo(Blackjack bj)
		{
			if (!((Object)(object)bj == (Object)null) && !((Object)(object)((Component)bj).gameObject.GetComponent<SplitTableButton>() != (Object)null))
			{
				((Component)bj).gameObject.AddComponent<SplitTableButton>()._bj = bj;
			}
		}

		private void Update()
		{
			if ((Object)(object)_bj == (Object)null)
			{
				return;
			}
			if ((Object)(object)_spawnedButton == (Object)null)
			{
				SpawnButton();
				if ((Object)(object)_spawnedButton == (Object)null)
				{
					return;
				}
			}
			ApplyHolderTransform();
			string text = ComputeIneligibilityReason();
			bool eligible = text == null;
			UpdateButtonStateForEligibility(eligible);
			if (text != _lastEligibilityReason)
			{
				if (text == null)
				{
					Plugin.Logger.LogDebug((object)("[3DButton] '" + ((Object)_bj).name + "': eligible — magenta + interactable"));
				}
				else
				{
					Plugin.Logger.LogDebug((object)("[3DButton] '" + ((Object)_bj).name + "': not eligible (" + text + ") — dimmed + non-interactable"));
				}
				_lastEligibilityReason = text;
			}
		}

		private void UpdateButtonStateForEligibility(bool eligible)
		{
			//IL_00fa: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_spawnedButton == (Object)null)
			{
				return;
			}
			SplitButtonInteractable component = _spawnedButton.GetComponent<SplitButtonInteractable>();
			if ((Object)(object)component != (Object)null)
			{
				component.IsInteractable = true;
			}
			Renderer[] componentsInChildren;
			if (_allRenderersCache == null)
			{
				List<Renderer> list = new List<Renderer>();
				componentsInChildren = _spawnedButton.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					if (!((Object)(object)val.material == (Object)null) && (!(val is MeshRenderer) || !((Object)(object)((Component)val).GetComponent<TMP_Text>() != (Object)null)))
					{
						list.Add(val);
					}
				}
				_allRenderersCache = list.ToArray();
				Plugin.Logger.LogInfo((object)$"[SplitWithFriends/3DButton] Renderers cached: {_allRenderersCache.Length} found in '{((Object)_spawnedButton).name}'.");
			}
			Color color = (eligible ? new Color(1f, 0.2f, 1f, 1f) : new Color(0.45f, 0.3f, 0.4f, 1f));
			componentsInChildren = _allRenderersCache;
			foreach (Renderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.material != (Object)null)
				{
					val2.material.color = color;
				}
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_spawnedButton != (Object)null)
			{
				Object.Destroy((Object)(object)_spawnedButton);
			}
		}

		private string ComputeIneligibilityReason()
		{
			//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_00bf: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			SyncList<CardData> val = GetField(ref _playerHandField, "playerHand", _bj) as SyncList<CardData>;
			SyncList<CardData> val2 = GetField(ref _splitHandField, "splitHand", _bj) as SyncList<CardData>;
			SyncList<CardData> val3 = GetField(ref _dealerHandField, "dealerHand", _bj) as SyncList<CardData>;
			if (val == null || val2 == null || val3 == null)
			{
				return "reflection failed";
			}
			if (val2.Count != 0)
			{
				return "splitHand not empty";
			}
			if (val.Count != 2)
			{
				return $"playerHand.Count={val.Count}";
			}
			if (val3.Count != 2)
			{
				return $"dealerHand.Count={val3.Count}";
			}
			if (val[0].Rank != val[1].Rank)
			{
				return $"ranks differ ({val[0].Rank} vs {val[1].Rank})";
			}
			MoneyManager instance = NetworkSingleton<MoneyManager>.Instance;
			long num = (((Object)(object)instance == (Object)null) ? long.MaxValue : instance.balance);
			if (num < ((GameBase)_bj).currentBet)
			{
				return $"balance={num} < bet={((GameBase)_bj).currentBet}";
			}
			return null;
		}

		private static object GetField(ref FieldInfo cache, string name, Blackjack bj)
		{
			if (cache == null)
			{
				cache = typeof(Blackjack).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
			}
			return cache?.GetValue(bj);
		}

		private void SpawnButton()
		{
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_047a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_templateButton == (Object)null)
			{
				_templateButton = FindHitButtonForBlackjack(_bj);
				if ((Object)(object)_templateButton == (Object)null)
				{
					Plugin.Logger.LogWarning((object)"[SplitWithFriends/3DButton] Couldn't find HIT button to clone — falling back to primitive cube.");
					_spawnedButton = BuildFallbackCube();
					return;
				}
				ManualLogSource logger = Plugin.Logger;
				string name = ((Object)_templateButton).name;
				object arg = ((Component)_templateButton).transform.position;
				Transform parent = ((Component)_templateButton).transform.parent;
				logger.LogInfo((object)$"[SplitWithFriends/3DButton] Found HIT template '{name}' at {arg}, parent='{((parent != null) ? ((Object)parent).name : null)}'");
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)_templateButton).gameObject);
			((Object)val).name = "SplitWithFriends.SplitButton";
			val.transform.SetParent(((Component)_templateButton).transform.parent, false);
			InteractableEventTrigger val2 = FindButtonForBlackjack(_bj, "PlayerStand");
			InteractableEventTrigger val3 = FindButtonForBlackjack(_bj, "PlayerDouble");
			Vector3 val5;
			if ((Object)(object)val2 != (Object)null && (Object)(object)val3 != (Object)null)
			{
				Vector3 localPosition = ((Component)val2).transform.localPosition;
				Vector3 localPosition2 = ((Component)_templateButton).transform.localPosition;
				Vector3 localPosition3 = ((Component)val3).transform.localPosition;
				Vector3 val4 = localPosition2 - localPosition;
				Vector3 normalized = ((Vector3)(ref val4)).normalized;
				val4 = localPosition2 - localPosition;
				float magnitude = ((Vector3)(ref val4)).magnitude;
				val5 = localPosition3 - normalized * magnitude;
				Plugin.Logger.LogInfo((object)$"[SplitWithFriends/3DButton] Row geometry: STAND={localPosition}, HIT={localPosition2}, DOUBLE={localPosition3}, forward={normalized}, spacing={magnitude:F3}, splitPos (left of DOUBLE)={val5}");
			}
			else
			{
				val5 = ((Component)_templateButton).transform.localPosition + new Vector3(Plugin.Config3DButtonOffsetX.Value, 0f, 0f);
				Plugin.Logger.LogWarning((object)$"[SplitWithFriends/3DButton] STAND or DOUBLE not found (stand={val2}, double={val3}); using fixed-offset fallback {val5}");
			}
			val.transform.localPosition = val5;
			val.transform.localRotation = ((Component)_templateButton).transform.localRotation;
			val.transform.localScale = ((Component)_templateButton).transform.localScale;
			if (!_holderHierarchyLogged)
			{
				LogHolderHierarchy(((Component)_templateButton).transform.parent);
				_holderHierarchyLogged = true;
			}
			SFXLocalPlayer componentInChildren = val.GetComponentInChildren<SFXLocalPlayer>(true);
			MonoBehaviour val6 = null;
			MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val7 in componentsInChildren)
			{
				if ((Object)(object)val7 != (Object)null && ((object)val7).GetType().FullName == "MoreMountains.Feedbacks.MMF_Player")
				{
					val6 = val7;
					break;
				}
			}
			Plugin.Logger.LogInfo((object)("[SplitWithFriends/SFX] captured: SFXLocalPlayer=" + (((Object)(object)componentInChildren != (Object)null) ? "yes" : "NO") + ", MMF_Player=" + (((Object)(object)val6 != (Object)null) ? "yes" : "NO")));
			int num = 0;
			NetworkBehaviour[] componentsInChildren2 = val.GetComponentsInChildren<NetworkBehaviour>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren2[i]);
				num++;
			}
			int num2 = 0;
			NetworkIdentity[] componentsInChildren3 = val.GetComponentsInChildren<NetworkIdentity>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren3[i]);
				num2++;
			}
			Outline val8 = val.AddComponent<Outline>();
			val8.OutlineMode = (Mode)0;
			val8.OutlineColor = Color.yellow;
			val8.OutlineWidth = 5f;
			((Behaviour)val8).enabled = false;
			int num3 = 0;
			TMP_Text[] componentsInChildren4 = val.GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text obj in componentsInChildren4)
			{
				obj.text = "SPLIT";
				((Graphic)obj).color = Color.white;
				num3++;
			}
			Text[] componentsInChildren5 = val.GetComponentsInChildren<Text>(true);
			foreach (Text obj2 in componentsInChildren5)
			{
				obj2.text = "SPLIT";
				((Graphic)obj2).color = Color.white;
				num3++;
			}
			int num4 = 0;
			Renderer[] componentsInChildren6 = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val9 in componentsInChildren6)
			{
				if (!((Object)(object)val9.material == (Object)null) && (!(val9 is MeshRenderer) || !((Object)(object)((Component)val9).GetComponent<TMP_Text>() != (Object)null)))
				{
					val9.material.color = new Color(1f, 0.2f, 1f, 1f);
					num4++;
				}
			}
			if ((Object)(object)val.GetComponentInChildren<Collider>(true) == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/3DButton] Clone has no Collider — adding a SphereCollider so raycast can target it.");
				val.AddComponent<SphereCollider>().radius = 0.1f;
			}
			SplitButtonInteractable splitButtonInteractable = val.AddComponent<SplitButtonInteractable>();
			splitButtonInteractable.Initialize(_bj);
			splitButtonInteractable.AttachVisualHelpers(val8, componentInChildren, val6);
			_spawnedButton = val;
			Plugin.Logger.LogInfo((object)$"[SplitWithFriends/3DButton] Spawned SPLIT button: stripped {num} NetworkBehaviour(s) + {num2} NetworkIdentity, retargeted {num3} label(s), retinted {num4} renderer(s).");
			GrowSM_Display(_bj);
		}

		private void GrowSM_Display(Blackjack bj)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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)
			if ((Object)(object)_smDisplay != (Object)null)
			{
				return;
			}
			Transform val = ((Component)bj).transform.Find("Model");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/Holder] no Model child on Blackjack");
				return;
			}
			Transform val2 = val.Find("Monitors");
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/Holder] no Monitors child of Model");
				return;
			}
			Transform val3 = val2.Find("SM_Display (1)");
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val2.Find("SM_Display");
			}
			if ((Object)(object)val3 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/Holder] no 'SM_Display (1)' under Monitors — aborting holder grow");
				return;
			}
			_smDisplay = val3;
			_smDisplayOrigScale = val3.localScale;
			_smDisplayOrigWorldPos = val3.position;
			ApplyHolderTransform();
			Plugin.Logger.LogInfo((object)$"[SplitWithFriends/Holder] cached SM_Display orig scale={_smDisplayOrigScale}, origWorldPos={_smDisplayOrigWorldPos}. Will re-apply current config values every frame.");
		}

		public void ApplyHolderTransform()
		{
			//IL_0052: 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)
			if (!((Object)(object)_smDisplay == (Object)null))
			{
				float value = Plugin.ConfigSMDisplayScale.Value;
				float value2 = Plugin.ConfigSMDisplayScaleY.Value;
				_smDisplay.localScale = new Vector3(_smDisplayOrigScale.x * value, _smDisplayOrigScale.y * value2, _smDisplayOrigScale.z * value);
				float value3 = Plugin.ConfigSMDisplayOffset.Value;
				float value4 = Plugin.ConfigSMDisplayOffsetY.Value;
				_smDisplay.position = new Vector3(_smDisplayOrigWorldPos.x + value3, _smDisplayOrigWorldPos.y + value4, _smDisplayOrigWorldPos.z + value3);
			}
		}

		private void SpawnFrameExtender(InteractableEventTrigger template, Vector3 splitPos, Vector3 rowForwardDirection, float spacing)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)template == (Object)null)
			{
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject);
			((Object)val).name = "SplitWithFriends.FrameExtender";
			val.transform.SetParent(((Component)template).transform.parent, false);
			val.transform.localPosition = splitPos - rowForwardDirection * spacing;
			val.transform.localRotation = ((Component)template).transform.localRotation;
			val.transform.localScale = ((Component)template).transform.localScale;
			NetworkBehaviour[] componentsInChildren = val.GetComponentsInChildren<NetworkBehaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren[i]);
			}
			NetworkIdentity[] componentsInChildren2 = val.GetComponentsInChildren<NetworkIdentity>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren2[i]);
			}
			Collider[] componentsInChildren3 = val.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				componentsInChildren3[i].enabled = false;
			}
			TMP_Text[] componentsInChildren4 = val.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				componentsInChildren4[i].text = "";
			}
			Text[] componentsInChildren5 = val.GetComponentsInChildren<Text>(true);
			for (int i = 0; i < componentsInChildren5.Length; i++)
			{
				componentsInChildren5[i].text = "";
			}
			int num = 0;
			Renderer[] componentsInChildren6 = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren6)
			{
				if (!((Object)(object)val2.material == (Object)null) && (!(val2 is MeshRenderer) || !((Object)(object)((Component)val2).GetComponent<TMP_Text>() != (Object)null)))
				{
					val2.material.color = new Color(0.05f, 0.05f, 0.07f, 1f);
					num++;
				}
			}
			Plugin.Logger.LogInfo((object)$"[SplitWithFriends/3DButton] Spawned frame extender at {val.transform.localPosition} (painted {num} renderer(s) dark).");
		}

		private static InteractableEventTrigger FindHitButtonForBlackjack(Blackjack bj)
		{
			return FindButtonForBlackjack(bj, "PlayerHit");
		}

		private static InteractableEventTrigger FindButtonForBlackjack(Blackjack bj, string methodName)
		{
			InteractableEventTrigger[] array = Object.FindObjectsByType<InteractableEventTrigger>((FindObjectsSortMode)0);
			foreach (InteractableEventTrigger val in array)
			{
				UnityEvent<PlayerInteract> serverOnInteractEvent = val.serverOnInteractEvent;
				if (serverOnInteractEvent == null)
				{
					continue;
				}
				int persistentEventCount = ((UnityEventBase)serverOnInteractEvent).GetPersistentEventCount();
				for (int j = 0; j < persistentEventCount; j++)
				{
					Object persistentTarget = ((UnityEventBase)serverOnInteractEvent).GetPersistentTarget(j);
					string persistentMethodName = ((UnityEventBase)serverOnInteractEvent).GetPersistentMethodName(j);
					if (persistentTarget == bj && persistentMethodName == methodName)
					{
						return val;
					}
				}
			}
			return null;
		}

		private static void LogHolderHierarchy(Transform holder)
		{
			//IL_002a: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)holder == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/HolderDiag] template button has no parent — can't grow holder.");
				return;
			}
			Plugin.Logger.LogInfo((object)$"[SplitWithFriends/HolderDiag] === Holder '{((Object)holder).name}' (pos={holder.localPosition}, worldPos={holder.position}) ===");
			for (int i = 0; i < holder.childCount; i++)
			{
				Transform child = holder.GetChild(i);
				Plugin.Logger.LogInfo((object)$"[SplitWithFriends/HolderDiag] BUTTON '{((Object)child).name}' (worldPos={child.position}):");
				int idx = 0;
				LogTransformTreeRecursive(child, 1, 4, idx);
			}
			if (!((Object)(object)holder.parent != (Object)null))
			{
				return;
			}
			Plugin.Logger.LogInfo((object)("[SplitWithFriends/HolderDiag] === Siblings of '" + ((Object)holder).name + "' under '" + ((Object)holder.parent).name + "' ==="));
			for (int j = 0; j < holder.parent.childCount; j++)
			{
				Transform child2 = holder.parent.GetChild(j);
				if (!((Object)(object)child2 == (Object)(object)holder))
				{
					Plugin.Logger.LogInfo((object)$"[SplitWithFriends/HolderDiag] SIBLING '{((Object)child2).name}' (worldPos={child2.position}):");
					LogTransformTreeRecursive(child2, 1, 3, 0);
				}
			}
		}

		private static void LogTransformTreeRecursive(Transform t, int depth, int maxDepth, int idx)
		{
			//IL_00ad: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			string text = new string(' ', depth * 2);
			Renderer component = ((Component)t).GetComponent<Renderer>();
			string text2 = "";
			if ((Object)(object)component != (Object)null)
			{
				string text3 = "n/a";
				MeshRenderer val = (MeshRenderer)(object)((component is MeshRenderer) ? component : null);
				if (val != null)
				{
					MeshFilter component2 = ((Component)val).GetComponent<MeshFilter>();
					if ((Object)(object)component2 != (Object)null && (Object)(object)component2.sharedMesh != (Object)null)
					{
						text3 = ((Object)component2.sharedMesh).name;
					}
				}
				string name = ((object)component).GetType().Name;
				string arg = text3;
				Bounds bounds = component.bounds;
				text2 = $" RENDERER {name} mesh='{arg}' bounds={((Bounds)(ref bounds)).size:F3}";
			}
			Plugin.Logger.LogInfo((object)$"[SplitWithFriends/HolderDiag]{text}└ '{((Object)t).name}' worldPos={t.position:F3} localScale={t.localScale:F3}{text2}");
			if (depth < maxDepth)
			{
				for (int i = 0; i < t.childCount; i++)
				{
					LogTransformTreeRecursive(t.GetChild(i), depth + 1, maxDepth, i);
				}
			}
		}

		[Obsolete("0.1.14: not used; we keep SPLIT always visible instead.")]
		private void TryGrowHolder(Transform holder, InteractableEventTrigger standBtn, InteractableEventTrigger doubleBtn, InteractableEventTrigger hitBtn)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: 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)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: 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)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: 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_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: 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_0324: 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_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			if (_holderGrown || (Object)(object)holder == (Object)null)
			{
				return;
			}
			if ((Object)(object)standBtn == (Object)null || (Object)(object)doubleBtn == (Object)null || (Object)(object)hitBtn == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/HolderGrow] missing button refs; skipping grow.");
				return;
			}
			Vector3 val = ((Component)hitBtn).transform.localPosition - ((Component)standBtn).transform.localPosition;
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			val = ((Component)hitBtn).transform.localPosition - ((Component)standBtn).transform.localPosition;
			float magnitude = ((Vector3)(ref val)).magnitude;
			Transform val2 = null;
			float num = 0f;
			Bounds bounds;
			for (int i = 0; i < holder.childCount; i++)
			{
				Transform child = holder.GetChild(i);
				if ((Object)(object)((Component)child).GetComponent<InteractableEventTrigger>() != (Object)null)
				{
					continue;
				}
				Renderer component = ((Component)child).GetComponent<Renderer>();
				if (!((Object)(object)component == (Object)null))
				{
					bounds = component.bounds;
					float x = ((Bounds)(ref bounds)).size.x;
					if (x > num)
					{
						num = x;
						val2 = child;
					}
				}
			}
			Renderer component2 = ((Component)holder).GetComponent<Renderer>();
			if ((Object)(object)component2 != (Object)null)
			{
				bounds = component2.bounds;
				if (((Bounds)(ref bounds)).size.x > num)
				{
					val2 = holder;
					bounds = component2.bounds;
					num = ((Bounds)(ref bounds)).size.x;
				}
			}
			if ((Object)(object)holder.parent != (Object)null)
			{
				Renderer component3 = ((Component)holder.parent).GetComponent<Renderer>();
				if ((Object)(object)component3 != (Object)null)
				{
					bounds = component3.bounds;
					if (((Bounds)(ref bounds)).size.x > num)
					{
						val2 = holder.parent;
						bounds = component3.bounds;
						num = ((Bounds)(ref bounds)).size.x;
					}
				}
				for (int j = 0; j < holder.parent.childCount; j++)
				{
					Transform child2 = holder.parent.GetChild(j);
					if ((Object)(object)child2 == (Object)(object)holder)
					{
						continue;
					}
					Renderer component4 = ((Component)child2).GetComponent<Renderer>();
					if ((Object)(object)component4 != (Object)null)
					{
						bounds = component4.bounds;
						if (((Bounds)(ref bounds)).size.x > num)
						{
							val2 = child2;
							bounds = component4.bounds;
							num = ((Bounds)(ref bounds)).size.x;
						}
					}
					for (int k = 0; k < child2.childCount; k++)
					{
						Transform child3 = child2.GetChild(k);
						Renderer component5 = ((Component)child3).GetComponent<Renderer>();
						if ((Object)(object)component5 != (Object)null)
						{
							bounds = component5.bounds;
							if (((Bounds)(ref bounds)).size.x > num)
							{
								val2 = child3;
								bounds = component5.bounds;
								num = ((Bounds)(ref bounds)).size.x;
							}
						}
					}
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/HolderGrow] no frame mesh found anywhere; SPLIT will sit beside the existing panel without backing.");
				_holderGrown = true;
				return;
			}
			ManualLogSource logger = Plugin.Logger;
			string name = ((Object)val2).name;
			Transform parent = val2.parent;
			logger.LogInfo((object)$"[SplitWithFriends/HolderGrow] selected frame mesh: '{name}' (parent='{((parent != null) ? ((Object)parent).name : null)}', boundsX={num:F3}).");
			Vector3 val3 = val2.InverseTransformDirection(holder.TransformDirection(normalized));
			float num2 = Mathf.Abs(val3.x);
			float num3 = Mathf.Abs(val3.y);
			float num4 = Mathf.Abs(val3.z);
			char c = ((num2 >= num3 && num2 >= num4) ? 'x' : ((num3 >= num4) ? 'y' : 'z'));
			Vector3 localScale = val2.localScale;
			Vector3 val4 = localScale;
			switch (c)
			{
			case 'x':
				val4.x *= 1.25f;
				break;
			case 'y':
				val4.y *= 1.25f;
				break;
			case 'z':
				val4.z *= 1.25f;
				break;
			}
			val2.localScale = val4;
			Vector3 val5 = -normalized * (magnitude * 0.5f);
			Transform obj = val2;
			obj.localPosition += val5;
			Plugin.Logger.LogInfo((object)$"[SplitWithFriends/HolderGrow] Grew holder frame '{((Object)val2).name}': scale {localScale} → {val4} (dominantAxis={c}, factor={1.25f}), offset by {val5} along -rowForward.");
			_holderGrown = true;
		}

		private GameObject BuildFallbackCube()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)obj).name = "SplitWithFriends.SplitButton.Fallback";
			obj.transform.SetParent(((Component)_bj).transform, false);
			obj.transform.localPosition = new Vector3(Plugin.Config3DButtonFallbackX.Value, Plugin.Config3DButtonFallbackY.Value, Plugin.Config3DButtonFallbackZ.Value);
			obj.transform.localScale = new Vector3(0.15f, 0.05f, 0.1f);
			Renderer component = obj.GetComponent<Renderer>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.material != (Object)null)
			{
				component.material.color = new Color(1f, 0.2f, 1f, 1f);
			}
			obj.AddComponent<SplitButtonInteractable>().Initialize(_bj);
			return obj;
		}

		private static void DumpButtonComponentsOnce(GameObject btn)
		{
			if (_buttonComponentsDumped || (Object)(object)btn == (Object)null)
			{
				return;
			}
			_buttonComponentsDumped = true;
			Plugin.Logger.LogInfo((object)("[SplitWithFriends/ButtonDump] === components on '" + ((Object)btn).name + "' and children ==="));
			MonoBehaviour[] componentsInChildren = btn.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Plugin.Logger.LogInfo((object)("[ButtonDump]   '" + ((Object)((Component)val).gameObject).name + "' :: " + ((object)val).GetType().FullName));
				}
			}
		}

		private static EventReference? TryFindAnyButtonSFXEventReference(Blackjack bj)
		{
			//IL_00a6: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			MonoBehaviour[] componentsInChildren = ((Component)bj).GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!(fieldInfo.FieldType != typeof(EventReference)))
					{
						string text = fieldInfo.Name.ToLowerInvariant();
						if ((text.Contains("button") || text.Contains("click") || text.Contains("press")) && fieldInfo.GetValue(val) is EventReference value && !((EventReference)(ref value)).IsNull)
						{
							Plugin.Logger.LogInfo((object)("[SplitWithFriends/SFX] field match: " + ((object)val).GetType().Name + "." + fieldInfo.Name + " on '" + ((Object)((Component)val).gameObject).name + "'"));
							return value;
						}
					}
				}
			}
			return null;
		}
	}
}
namespace SplitWithFriends.Patches
{
	[HarmonyPatch(typeof(GameBase), "Awake")]
	internal static class BlackjackAwakePatch
	{
		private static FieldInfo _splitHandAreaOffsetField;

		[HarmonyPostfix]
		public static void Postfix(GameBase __instance)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			Blackjack val = (Blackjack)(object)((__instance is Blackjack) ? __instance : null);
			if (val == null)
			{
				return;
			}
			try
			{
				if (_splitHandAreaOffsetField == null)
				{
					_splitHandAreaOffsetField = typeof(Blackjack).GetField("splitHandAreaOffset", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				if (_splitHandAreaOffsetField != null)
				{
					Vector3 val2 = default(Vector3);
					((Vector3)(ref val2))..ctor(Plugin.ConfigSplitHandOffsetX.Value, Plugin.ConfigSplitHandOffsetY.Value, Plugin.ConfigSplitHandOffsetZ.Value);
					object value = _splitHandAreaOffsetField.GetValue(val);
					_splitHandAreaOffsetField.SetValue(val, val2);
					Plugin.Logger.LogInfo((object)$"[SplitWithFriends] Patched splitHandAreaOffset on '{((Object)val).name}': {value} → {val2}");
				}
				else
				{
					Plugin.Logger.LogWarning((object)"[SplitWithFriends] Could not find splitHandAreaOffset field — split hand position will use vanilla default.");
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"[SplitWithFriends] splitHandAreaOffset patch failed: {arg}");
			}
			SplitButtonOverlay.AttachTo(val);
			SplitTableButton.AttachTo(val);
			SplitHandPositioner.AttachTo(val);
			Plugin.Logger.LogInfo((object)("[SplitWithFriends] Attached overlay + 3D button + hand positioner to Blackjack '" + ((Object)val).name + "'"));
		}
	}
	[HarmonyPatch(typeof(Blackjack), "PlayerSplit")]
	internal static class BlackjackPlayerSplitPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Blackjack __instance)
		{
			if (Plugin.ConfigDebugLogServerInvocations.Value)
			{
				Plugin.Logger.LogInfo((object)("[Patch] Blackjack.PlayerSplit fired on " + ((Object)__instance).name));
			}
		}
	}
	[HarmonyPatch(typeof(Blackjack), "EndGameWithPayout")]
	internal static class EndGameWithPayoutFixPatch
	{
		private static FieldInfo _gameStateField;

		private static FieldInfo _playerHandField;

		private static FieldInfo _splitHandField;

		private static FieldInfo _dealerHandField;

		private static FieldInfo _handBetsField;

		private static FieldInfo _handDoubledField;

		private static MethodInfo _getHandValueMethod;

		private static MethodInfo _payoutMethod;

		private static MethodInfo _resetGameRoutineMethod;

		private static MethodInfo _calculateHandPayoutMethod;

		[HarmonyPrefix]
		public static bool Prefix(Blackjack __instance, long payout)
		{
			if (!NetworkServer.active)
			{
				return false;
			}
			long currentBet = ((GameBase)__instance).currentBet;
			if (currentBet <= 0)
			{
				Plugin.Logger.LogWarning((object)$"[SplitWithFriends/PayoutFix] currentBet is {currentBet}; can't compute multiplier safely. Letting vanilla run (will likely pay 0).");
				return true;
			}
			double num = (double)payout / (double)currentBet;
			long num2 = currentBet * payout;
			try
			{
				EnsureReflectionCache();
				int num3 = ComputeHandValue(__instance, _playerHandField);
				int num4 = ComputeHandValue(__instance, _splitHandField);
				int num5 = ComputeHandValue(__instance, _dealerHandField);
				long num6 = 0L;
				long num7 = 0L;
				bool flag = false;
				bool flag2 = false;
				if (_handBetsField != null && _handBetsField.GetValue(__instance) is long[] array && array.Length >= 2)
				{
					num6 = array[0];
					num7 = array[1];
				}
				if (_handDoubledField != null && _handDoubledField.GetValue(__instance) is bool[] array2 && array2.Length >= 2)
				{
					flag = array2[0];
					flag2 = array2[1];
				}
				long num8 = ComputeHandPayout(__instance, _playerHandField, num5, num6, allowBJ: false);
				long num9 = ComputeHandPayout(__instance, _splitHandField, num5, num7, allowBJ: false);
				string text = ResolveOutcome(num3, num5, num8);
				string text2 = ResolveOutcome(num4, num5, num9);
				Plugin.Logger.LogInfo((object)"[SplitWithFriends/PayoutFix] === ROUND OUTCOME ===");
				Plugin.Logger.LogInfo((object)$"[SplitWithFriends/PayoutFix] Dealer:  {num5}");
				Plugin.Logger.LogInfo((object)string.Format("[SplitWithFriends/PayoutFix] Hand 1:  {0}{1}, bet=${2} → {3}, pays ${4}", num3, flag ? " (doubled)" : "", num6, text, num8));
				Plugin.Logger.LogInfo((object)string.Format("[SplitWithFriends/PayoutFix] Hand 2:  {0}{1}, bet=${2} → {3}, pays ${4}", num4, flag2 ? " (doubled)" : "", num7, text2, num9));
				Plugin.Logger.LogInfo((object)$"[SplitWithFriends/PayoutFix] Sum:     ${num8 + num9} (expected = vanilla `payout` arg = ${payout})");
				Plugin.Logger.LogInfo((object)$"[SplitWithFriends/PayoutFix] Vanilla bug would pay ~${num2}; correcting via multiplier {num:F4} → ~${payout}.");
				_gameStateField?.SetValue(__instance, 3);
				Dictionary<string, object> dictionary = new Dictionary<string, object>
				{
					{ "playerHandValue", num3 },
					{ "splitHandValue", num4 },
					{ "dealerHandValue", num5 }
				};
				_payoutMethod?.Invoke(__instance, new object[4]
				{
					num,
					(object)(ChangeType)1,
					dictionary,
					-1L
				});
				if (_resetGameRoutineMethod != null && _resetGameRoutineMethod.Invoke(__instance, null) is IEnumerator enumerator)
				{
					((MonoBehaviour)__instance).StartCoroutine(enumerator);
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"[SplitWithFriends/PayoutFix] Replacement crashed; falling back to vanilla buggy path: {arg}");
				return true;
			}
			return false;
		}

		private static void EnsureReflectionCache()
		{
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic;
			if (_gameStateField == null)
			{
				_gameStateField = typeof(Blackjack).GetField("gameState", bindingAttr);
			}
			if (_playerHandField == null)
			{
				_playerHandField = typeof(Blackjack).GetField("playerHand", bindingAttr);
			}
			if (_splitHandField == null)
			{
				_splitHandField = typeof(Blackjack).GetField("splitHand", bindingAttr);
			}
			if (_dealerHandField == null)
			{
				_dealerHandField = typeof(Blackjack).GetField("dealerHand", bindingAttr);
			}
			if (_handBetsField == null)
			{
				_handBetsField = typeof(Blackjack).GetField("handBets", bindingAttr);
			}
			if (_handDoubledField == null)
			{
				_handDoubledField = typeof(Blackjack).GetField("handDoubled", bindingAttr);
			}
			if (_getHandValueMethod == null)
			{
				_getHandValueMethod = typeof(Blackjack).GetMethod("GetHandValue", bindingAttr);
			}
			if (_payoutMethod == null)
			{
				_payoutMethod = typeof(GameBase).GetMethod("Payout", bindingAttr);
			}
			if (_resetGameRoutineMethod == null)
			{
				_resetGameRoutineMethod = typeof(Blackjack).GetMethod("ResetGameRoutine", bindingAttr);
			}
			if (_calculateHandPayoutMethod == null)
			{
				_calculateHandPayoutMethod = typeof(Blackjack).GetMethod("CalculateHandPayout", bindingAttr);
			}
		}

		private static long ComputeHandPayout(Blackjack bj, FieldInfo handField, int dealerValue, long handBet, bool allowBJ)
		{
			if (_calculateHandPayoutMethod == null || handField == null)
			{
				return 0L;
			}
			object value = handField.GetValue(bj);
			if (value == null)
			{
				return 0L;
			}
			return (long)_calculateHandPayoutMethod.Invoke(bj, new object[4] { value, dealerValue, handBet, allowBJ });
		}

		private static string ResolveOutcome(int handValue, int dealerValue, long payoutAmount)
		{
			if (handValue > 21)
			{
				return "BUST";
			}
			if (dealerValue > 21)
			{
				return "WIN (dealer bust)";
			}
			if (handValue > dealerValue)
			{
				return "WIN";
			}
			if (handValue < dealerValue)
			{
				return "LOSS";
			}
			if (payoutAmount <= 0)
			{
				return "LOSS";
			}
			return "PUSH";
		}

		private static int ComputeHandValue(Blackjack bj, FieldInfo field)
		{
			if (field == null || _getHandValueMethod == null)
			{
				return 0;
			}
			object value = field.GetValue(bj);
			if (value == null)
			{
				return 0;
			}
			return (int)_getHandValueMethod.Invoke(bj, new object[1] { value });
		}
	}
	internal class HolderLiveTuner : MonoBehaviour
	{
		private struct Adjustable
		{
			public string Name;

			public Func<float> Get;

			public Action<float> Set;
		}

		private Adjustable[] _targets;

		private int _idx;

		private readonly float[] _steps = new float[7] { 0.001f, 0.005f, 0.01f, 0.05f, 0.1f, 0.5f, 1f };

		private int _stepIdx = 3;

		private GameObject _hud;

		private TextMeshProUGUI _hudText;

		private bool _hudVisible = true;

		public static void EnsureInstalled()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (Plugin.ConfigEnableLiveTuner.Value)
			{
				GameObject val = new GameObject("SplitWithFriends.LiveTuner");
				Object.DontDestroyOnLoad((Object)val);
				val.AddComponent<HolderLiveTuner>();
			}
		}

		private void Start()
		{
			_targets = new Adjustable[6]
			{
				new Adjustable
				{
					Name = "Hand 1 stow X (when on hand 2)",
					Get = () => Plugin.ConfigHand1StowX.Value,
					Set = delegate(float v)
					{
						Plugin.ConfigHand1StowX.Value = v;
					}
				},
				new Adjustable
				{
					Name = "Hand 1 stow Y (when on hand 2)",
					Get = () => Plugin.ConfigHand1StowY.Value,
					Set = delegate(float v)
					{
						Plugin.ConfigHand1StowY.Value = v;
					}
				},
				new Adjustable
				{
					Name = "Hand 1 stow Z (when on hand 2)",
					Get = () => Plugin.ConfigHand1StowZ.Value,
					Set = delegate(float v)
					{
						Plugin.ConfigHand1StowZ.Value = v;
					}
				},
				new Adjustable
				{
					Name = "Hand 2 stow X (when on hand 1)",
					Get = () => Plugin.ConfigHand2StowX.Value,
					Set = delegate(float v)
					{
						Plugin.ConfigHand2StowX.Value = v;
					}
				},
				new Adjustable
				{
					Name = "Hand 2 stow Y (when on hand 1)",
					Get = () => Plugin.ConfigHand2StowY.Value,
					Set = delegate(float v)
					{
						Plugin.ConfigHand2StowY.Value = v;
					}
				},
				new Adjustable
				{
					Name = "Hand 2 stow Z (when on hand 1)",
					Get = () => Plugin.ConfigHand2StowZ.Value,
					Set = delegate(float v)
					{
						Plugin.ConfigHand2StowZ.Value = v;
					}
				}
			};
			BuildHud();
			UpdateHud();
			Plugin.Logger.LogInfo((object)"[LiveTune] tuner active. Numpad: 6/4 cycle, 8/2 +/-, +/- step, 5 log, 0 reset, . toggle HUD.");
		}

		private void Update()
		{
			try
			{
				Keyboard current = Keyboard.current;
				if (current == null)
				{
					return;
				}
				bool flag = false;
				if (((ButtonControl)current[(Key)90]).wasPressedThisFrame)
				{
					_idx = (_idx + 1) % _targets.Length;
					flag = true;
				}
				if (((ButtonControl)current[(Key)88]).wasPressedThisFrame)
				{
					_idx = (_idx + _targets.Length - 1) % _targets.Length;
					flag = true;
				}
				float num = _steps[_stepIdx];
				if (((ButtonControl)current[(Key)92]).wasPressedThisFrame)
				{
					_targets[_idx].Set(_targets[_idx].Get() + num);
					flag = true;
				}
				if (((ButtonControl)current[(Key)86]).wasPressedThisFrame)
				{
					_targets[_idx].Set(_targets[_idx].Get() - num);
					flag = true;
				}
				if (((ButtonControl)current[(Key)80]).wasPressedThisFrame)
				{
					_stepIdx = Math.Min(_stepIdx + 1, _steps.Length - 1);
					flag = true;
				}
				if (((ButtonControl)current[(Key)81]).wasPressedThisFrame)
				{
					_stepIdx = Math.Max(_stepIdx - 1, 0);
					flag = true;
				}
				if (((ButtonControl)current[(Key)89]).wasPressedThisFrame)
				{
					Plugin.Logger.LogInfo((object)"[LiveTune] === current values ===");
					Adjustable[] targets = _targets;
					for (int i = 0; i < targets.Length; i++)
					{
						Adjustable adjustable = targets[i];
						Plugin.Logger.LogInfo((object)$"[LiveTune]   {adjustable.Name} = {adjustable.Get():F4}");
					}
				}
				if (((ButtonControl)current[(Key)84]).wasPressedThisFrame)
				{
					Plugin.ConfigHand1StowX.Value = 1.15f;
					Plugin.ConfigHand1StowY.Value = -0.2f;
					Plugin.ConfigHand1StowZ.Value = 0.4f;
					Plugin.ConfigHand2StowX.Value = 1.1f;
					Plugin.ConfigHand2StowY.Value = 0f;
					Plugin.ConfigHand2StowZ.Value = -0.9f;
					Plugin.Logger.LogInfo((object)"[LiveTune] reset all to defaults");
					flag = true;
				}
				if (((ButtonControl)current[(Key)82]).wasPressedThisFrame)
				{
					_hudVisible = !_hudVisible;
					if ((Object)(object)_hud != (Object)null)
					{
						_hud.SetActive(_hudVisible);
					}
				}
				if (flag)
				{
					UpdateHud();
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("[LiveTuner] input read failed: " + ex.Message));
			}
		}

		private void BuildHud()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			_hud = new GameObject("SplitWithFriends.LiveTuneHUD");
			Object.DontDestroyOnLoad((Object)(object)_hud);
			Canvas obj = _hud.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32600;
			CanvasScaler obj2 = _hud.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			_hud.AddComponent<GraphicRaycaster>();
			GameObject val = new GameObject("Panel");
			val.transform.SetParent(_hud.transform, false);
			RectTransform obj3 = val.AddComponent<RectTransform>();
			obj3.anchorMin = new Vector2(0f, 0f);
			obj3.anchorMax = new Vector2(0f, 0f);
			obj3.pivot = new Vector2(0f, 0f);
			obj3.anchoredPosition = new Vector2(20f, 200f);
			obj3.sizeDelta = new Vector2(540f, 100f);
			((Graphic)val.AddComponent<Image>()).color = new Color(0.05f, 0.05f, 0.1f, 0.85f);
			GameObject val2 = new GameObject("Border");
			val2.transform.SetParent(val.transform, false);
			RectTransform obj4 = val2.AddComponent<RectTransform>();
			obj4.anchorMin = Vector2.zero;
			obj4.anchorMax = Vector2.one;
			obj4.offsetMin = new Vector2(-2f, -2f);
			obj4.offsetMax = new Vector2(2f, 2f);
			((Graphic)val2.AddComponent<Image>()).color = new Color(1f, 0.2f, 0.85f, 0.5f);
			val2.transform.SetAsFirstSibling();
			TMP_FontAsset val3 = null;
			TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val4 in array)
			{
				if ((Object)(object)val4 != (Object)null)
				{
					val3 = val4;
					break;
				}
			}
			GameObject val5 = new GameObject("Label");
			val5.transform.SetParent(val.transform, false);
			RectTransform obj5 = val5.AddComponent<RectTransform>();
			obj5.anchorMin = Vector2.zero;
			obj5.anchorMax = Vector2.one;
			obj5.offsetMin = new Vector2(10f, 6f);
			obj5.offsetMax = new Vector2(-10f, -6f);
			_hudText = val5.AddComponent<TextMeshProUGUI>();
			((Graphic)_hudText).color = Color.white;
			((TMP_Text)_hudText).fontSize = 18f;
			((TMP_Text)_hudText).richText = true;
			((TMP_Text)_hudText).alignment = (TextAlignmentOptions)257;
			if ((Object)(object)val3 != (Object)null)
			{
				((TMP_Text)_hudText).font = val3;
			}
		}

		private void UpdateHud()
		{
			if (!((Object)(object)_hudText == (Object)null) && _targets != null)
			{
				Adjustable adjustable = _targets[_idx];
				float num = adjustable.Get();
				float num2 = _steps[_stepIdx];
				((TMP_Text)_hudText).text = $"<b>SPLIT LIVE TUNE</b> [{_idx + 1}/{_targets.Length}]\n" + $"<color=#FFCC44>{adjustable.Name}</color> = <color=#88FF88>{num:F4}</color>\n" + $"<size=14>step: <color=#FFAAFF>{num2:F3}</color>   keys: 4/6 cycle, 8/2 ±, +/- step, 5 log, 0 reset, . toggle</size>";
			}
		}
	}
	[HarmonyPatch(typeof(CustomNetworkManager), "OnStartServer")]
	internal static class CustomNetworkManagerOnStartServerPatch
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			Plugin.Logger.LogInfo((object)"[SplitWithFriends] CustomNetworkManager.OnStartServer postfix fired — registering handler");
			SplitNetwork.RegisterServerHandlers();
		}
	}
	[HarmonyPatch(typeof(CustomNetworkManager), "OnStopServer")]
	internal static class CustomNetworkManagerOnStopServerPatch
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			Plugin.Logger.LogInfo((object)"[SplitWithFriends] CustomNetworkManager.OnStopServer postfix fired — unregistering handler");
			SplitNetwork.UnregisterServerHandlers();
		}
	}
}
namespace SplitWithFriends.Net
{
	internal static class SplitNetwork
	{
		private static bool _serverHandlerRegistered;

		public static void RegisterServerHandlers()
		{
			NetworkServer.ReplaceHandler<SplitRequestMessage>((Action<NetworkConnectionToClient, SplitRequestMessage>)OnSplitRequest, true);
			_serverHandlerRegistered = true;
			Plugin.Logger.LogInfo((object)"[SplitWithFriends] SplitRequestMessage handler registered on server.");
		}

		public static void UnregisterServerHandlers()
		{
			if (_serverHandlerRegistered)
			{
				NetworkServer.UnregisterHandler<SplitRequestMessage>();
				_serverHandlerRegistered = false;
				Plugin.Logger.LogInfo((object)"[SplitWithFriends] SplitRequestMessage handler unregistered.");
			}
		}

		private static void OnSplitRequest(NetworkConnectionToClient conn, SplitRequestMessage msg)
		{
			Plugin.Logger.LogInfo((object)$"[SplitWithFriends/SERVER] OnSplitRequest received: bjNetId={msg.blackjackNetId}, piNetId={msg.playerInteractNetId}, fromConn={conn}");
			if (!NetworkServer.spawned.TryGetValue(msg.blackjackNetId, out var value) || (Object)(object)value == (Object)null)
			{
				Plugin.Logger.LogWarning((object)$"[SplitWithFriends/SERVER] SplitRequest: unknown blackjack netId {msg.blackjackNetId}");
				return;
			}
			Blackjack component = ((Component)value).GetComponent<Blackjack>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Logger.LogWarning((object)$"[SplitWithFriends/SERVER] SplitRequest: NetworkIdentity {msg.blackjackNetId} has no Blackjack component");
				return;
			}
			if (!NetworkServer.spawned.TryGetValue(msg.playerInteractNetId, out var value2) || (Object)(object)value2 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)$"[SplitWithFriends/SERVER] SplitRequest: unknown playerInteract netId {msg.playerInteractNetId}");
				return;
			}
			PlayerInteract component2 = ((Component)value2).GetComponent<PlayerInteract>();
			if ((Object)(object)component2 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)$"[SplitWithFriends/SERVER] SplitRequest: PlayerInteract component not found on netId {msg.playerInteractNetId}");
				return;
			}
			if (((NetworkBehaviour)component2).connectionToClient != conn)
			{
				Plugin.Logger.LogWarning((object)$"[SplitWithFriends/SERVER] SplitRequest: connection {conn} tried to act as PlayerInteract owned by {((NetworkBehaviour)component2).connectionToClient} — rejected");
				return;
			}
			string text = ReadServerState(component);
			Plugin.Logger.LogInfo((object)("[SplitWithFriends/SERVER] About to call Blackjack.PlayerSplit. Pre-state: " + text));
			component.PlayerSplit(component2);
			string text2 = ReadServerState(component);
			Plugin.Logger.LogInfo((object)("[SplitWithFriends/SERVER] PlayerSplit returned. Post-state: " + text2));
			if (text == text2)
			{
				Plugin.Logger.LogWarning((object)"[SplitWithFriends/SERVER] PlayerSplit was called but state did not change — the game's internal guard chain rejected it. See decompiled/Blackjack.cs:257 for the conditions.");
			}
			else
			{
				Plugin.Logger.LogInfo((object)"[SplitWithFriends/SERVER] PlayerSplit changed state — split appears to have succeeded.");
			}
		}

		private static string Re