Decompiled source of SplitWithFriends v1.0.2
BepInEx\plugins\SplitWithFriends\SplitWithFriends.dll
Decompiled 15 hours ago
The result has been truncated due to the large size, download it to view full contents!
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