Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Double Down in Lethal Casino v4.0.2
LethalCasinoDoubleDown.dll
Decompiled 5 months agousing 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 GameNetcodeStuff; using HarmonyLib; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("LethalCasinoDoubleDown")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LethalCasinoDoubleDown")] [assembly: AssemblyTitle("LethalCasinoDoubleDown")] [assembly: AssemblyVersion("1.0.0.0")] public static class PluginInfo { public const string PLUGIN_GUID = "Papkasse_Manden.Double_Down_In_Lethal_Casino"; public const string PLUGIN_NAME = "Double_Down_In_Lethal_Casino"; public const string PLUGIN_VERSION = "4.0.2"; } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("Papkasse_Manden.Double_Down_In_Lethal_Casino", "Double_Down_In_Lethal_Casino", "4.0.2")] public class BlackjackDoubleDownMod : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("Papkasse_Manden.Double_Down_In_Lethal_Casino"); public static ManualLogSource Log { get; private set; } public static ConfigEntry<KeyboardShortcut> DoubleDownKey { get; private set; } private void Awake() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Plugin Papkasse_Manden.Double_Down_In_Lethal_Casino is loading..."); DoubleDownKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "DoubleDownKey", new KeyboardShortcut((KeyCode)117, Array.Empty<KeyCode>()), "Key to perform Double Down action in Blackjack"); ApplyAllPatches(); Log.LogInfo((object)"Plugin Papkasse_Manden.Double_Down_In_Lethal_Casino v4.0.2 loaded successfully"); } private void ApplyAllPatches() { if (!BlackjackReflectionCache.Initialize(Log)) { Log.LogError((object)"Failed to initialize reflection cache. Aborting patches."); return; } CustomScrapControllerPatcher.ApplyPatches(harmony, Log); BlackjackDoubleDownPatcher.ApplyPatches(harmony, Log); BlackjackMultiplyScrapValuesPatcher.ApplyPatches(harmony, Log); BlackjackProcessResultsPatcher.ApplyPatches(harmony, Log); JoinGameServerRpcPatcher.ApplyPatches(harmony, Log); } } internal static class BlackjackReflectionCache { public static Type BlackjackType { get; private set; } public static Type CustomScrapControllerType { get; private set; } public static FieldInfo GameInProgressField { get; private set; } public static FieldInfo GamblingPlayersField { get; private set; } public static FieldInfo GambledScrapField { get; private set; } public static FieldInfo PlayerCardsField { get; private set; } public static FieldInfo PlayerCompletedTurnField { get; private set; } public static FieldInfo OriginalScrapValueField { get; private set; } public static FieldInfo LockFromGamblingField { get; private set; } public static FieldInfo DelayedTasksField { get; private set; } public static FieldInfo DelayedTasksQueuedField { get; private set; } public static MethodInfo DestroyBetControlsClientRpcMethod { get; private set; } public static MethodInfo TakeTurnAsPlayerServerRpcMethod { get; private set; } public static MethodInfo ShowWarningMessageClientRpcMethod { get; private set; } public static MethodInfo MultiplyScrapValuesMethod { get; private set; } public static MethodInfo UpdateScrapValueClientRpcMethod { get; private set; } public static MethodInfo JoinGameServerRpcMethod { get; private set; } public static MethodInfo JoinGameSuccessfulClientRpcMethod { get; private set; } public static bool Initialize(ManualLogSource log) { try { BlackjackType = AccessTools.TypeByName("LethalCasino.Custom.Blackjack"); CustomScrapControllerType = AccessTools.TypeByName("LethalCasino.Custom.CustomScrapController"); if (BlackjackType == null || CustomScrapControllerType == null) { log.LogError((object)"Required LethalCasino types not found. Is LethalCasino installed?"); return false; } GameInProgressField = GetField(BlackjackType, "gameInProgress"); GamblingPlayersField = GetField(BlackjackType, "gamblingPlayers"); GambledScrapField = GetField(BlackjackType, "gambledScrap"); PlayerCardsField = GetField(BlackjackType, "playerCards"); PlayerCompletedTurnField = GetField(BlackjackType, "playerCompletedTurn"); DelayedTasksField = GetField(BlackjackType, "delayedTasks"); DelayedTasksQueuedField = GetField(BlackjackType, "delayedTasksQueued"); OriginalScrapValueField = GetField(CustomScrapControllerType, "originalScrapValue"); LockFromGamblingField = GetField(CustomScrapControllerType, "lockFromGambling"); TakeTurnAsPlayerServerRpcMethod = GetMethod(BlackjackType, "TakeTurnAsPlayerServerRpc", new Type[3] { typeof(NetworkBehaviourReference), typeof(int), typeof(string) }); ShowWarningMessageClientRpcMethod = GetMethod(BlackjackType, "ShowWarningMessageClientRpc", new Type[4] { typeof(NetworkBehaviourReference), typeof(string), typeof(string), typeof(bool) }); MultiplyScrapValuesMethod = GetMethod(BlackjackType, "MultiplyScrapValues", new Type[3] { typeof(List<GrabbableObject>), typeof(float), typeof(bool) }); UpdateScrapValueClientRpcMethod = GetMethod(BlackjackType, "UpdateScrapValueClientRpc", new Type[3] { typeof(NetworkBehaviourReference), typeof(int), typeof(bool) }); JoinGameServerRpcMethod = GetMethod(BlackjackType, "JoinGameServerRpc", new Type[2] { typeof(NetworkBehaviourReference), typeof(int) }); DestroyBetControlsClientRpcMethod = GetMethod(BlackjackType, "DestroyBetControlsClientRpc", new Type[1] { typeof(int) }); JoinGameSuccessfulClientRpcMethod = GetMethod(BlackjackType, "JoinGameSuccessfulClientRpc", new Type[3] { typeof(NetworkBehaviourReference), typeof(int), typeof(int) }); return ValidateReflection(log); } catch (Exception arg) { log.LogError((object)$"Failed to initialize reflection cache: {arg}"); return false; } } private static FieldInfo GetField(Type type, string fieldName) { FieldInfo fieldInfo = AccessTools.Field(type, fieldName); if (fieldInfo == null) { BlackjackDoubleDownMod.Log.LogWarning((object)("Field '" + fieldName + "' not found in " + type.Name)); } return fieldInfo; } private static MethodInfo GetMethod(Type type, string methodName, Type[] parameters = null) { MethodInfo methodInfo = AccessTools.Method(type, methodName, parameters, (Type[])null); if (methodInfo == null) { BlackjackDoubleDownMod.Log.LogWarning((object)("Method '" + methodName + "' not found in " + type.Name)); } return methodInfo; } private static bool ValidateReflection(ManualLogSource log) { (FieldInfo, string)[] array = new(FieldInfo, string)[7] { (GameInProgressField, "gameInProgress"), (GamblingPlayersField, "gamblingPlayers"), (GambledScrapField, "gambledScrap"), (PlayerCardsField, "playerCards"), (PlayerCompletedTurnField, "playerCompletedTurn"), (OriginalScrapValueField, "originalScrapValue"), (LockFromGamblingField, "lockFromGambling") }; (MethodInfo, string)[] array2 = new(MethodInfo, string)[7] { (TakeTurnAsPlayerServerRpcMethod, "TakeTurnAsPlayerServerRpc"), (ShowWarningMessageClientRpcMethod, "ShowWarningMessageClientRpc"), (MultiplyScrapValuesMethod, "MultiplyScrapValues"), (UpdateScrapValueClientRpcMethod, "UpdateScrapValueClientRpc"), (JoinGameServerRpcMethod, "JoinGameServerRpc"), (JoinGameSuccessfulClientRpcMethod, "JoinGameSuccessfulClientRpc"), (DestroyBetControlsClientRpcMethod, "DestroyBetControlsClientRpc") }; bool result = true; (FieldInfo, string)[] array3 = array; for (int i = 0; i < array3.Length; i++) { var (fieldInfo, text) = array3[i]; if (fieldInfo == null) { log.LogError((object)("Required field '" + text + "' not found")); result = false; } } (MethodInfo, string)[] array4 = array2; for (int j = 0; j < array4.Length; j++) { var (methodInfo, text2) = array4[j]; if (methodInfo == null) { log.LogError((object)("Required method '" + text2 + "' not found")); result = false; } } return result; } } internal static class CustomScrapControllerPatcher { private static Dictionary<object, int> gambledValues = new Dictionary<object, int>(); public static void ApplyPatches(Harmony harmony, ManualLogSource log) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(BlackjackReflectionCache.CustomScrapControllerType, "__initializeVariables", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CustomScrapControllerPatcher), "InitializeVariables_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"CustomScrapController __initializeVariables method patched"); } else { log.LogWarning((object)"Could not find __initializeVariables method in CustomScrapController"); } } catch (Exception arg) { log.LogError((object)$"Failed to patch CustomScrapController: {arg}"); } } [HarmonyPostfix] public static void InitializeVariables_Postfix(object __instance) { try { gambledValues[__instance] = 0; BlackjackDoubleDownMod.Log.LogDebug((object)"Initialized gambledValue to 0 for scrap"); } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in InitializeVariables_Postfix: {arg}"); } } public static int GetGambledValue(object customScrapController) { int value; return gambledValues.TryGetValue(customScrapController, out value) ? value : 0; } public static void SetGambledValue(object customScrapController, int value) { gambledValues[customScrapController] = value; } public static void ClearAllGambledValues() { gambledValues.Clear(); } } internal static class BlackjackMultiplyScrapValuesPatcher { public static void ApplyPatches(Harmony harmony, ManualLogSource log) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown try { MethodInfo multiplyScrapValuesMethod = BlackjackReflectionCache.MultiplyScrapValuesMethod; if (multiplyScrapValuesMethod != null) { harmony.Patch((MethodBase)multiplyScrapValuesMethod, new HarmonyMethod(typeof(BlackjackMultiplyScrapValuesPatcher), "MultiplyScrapValues_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"Blackjack MultiplyScrapValues method patched successfully"); } else { log.LogWarning((object)"Could not find MultiplyScrapValues method in Blackjack"); } } catch (Exception arg) { log.LogError((object)$"Failed to patch MultiplyScrapValues: {arg}"); } } [HarmonyPrefix] public static bool MultiplyScrapValues_Prefix(object __instance, List<GrabbableObject> scrapItems, float multiplier, bool disablePoofsOnZero, ref int __result) { //IL_0507: Unknown result type (might be due to invalid IL or missing references) try { int playerIndexForScrap = GetPlayerIndexForScrap(__instance, scrapItems); BlackjackDoubleDownMod.Log.LogInfo((object)$"===== MultiplyScrapValues called for playerposition {playerIndexForScrap} ====="); if (multiplier == 0f && playerIndexForScrap != -1 && BustTracking.IsPlayerAlreadyBusted(playerIndexForScrap)) { BlackjackDoubleDownMod.Log.LogInfo((object)"SKIPPING duplicate bust processing caused by ProcessResults"); __result = 0; return false; } if (multiplier == 0f && playerIndexForScrap != -1 && !BustTracking.IsPlayerAlreadyBusted(playerIndexForScrap)) { BustTracking.MarkPlayerBusted(playerIndexForScrap); BlackjackDoubleDownMod.Log.LogInfo((object)$"MARKED player {playerIndexForScrap} as busted"); } BlackjackDoubleDownMod.Log.LogInfo((object)$"Multiplier: {multiplier}, ScrapItems Count: {scrapItems?.Count}"); List<GrabbableObject>[] array = (List<GrabbableObject>[])BlackjackReflectionCache.GambledScrapField.GetValue(__instance); for (int i = 0; i < array.Length; i++) { if (array[i] == null || array[i].Count <= 0) { continue; } BlackjackDoubleDownMod.Log.LogInfo((object)$"gambledScrapArray[{i}] has {array[i].Count} items"); foreach (GrabbableObject item in array[i]) { if ((Object)(object)item != (Object)null) { BlackjackDoubleDownMod.Log.LogInfo((object)$" - {item.itemProperties.itemName} (Value: {item.scrapValue})"); } } } int num = 0; foreach (GrabbableObject scrapItem in scrapItems) { if ((Object)(object)scrapItem == (Object)null) { continue; } BlackjackDoubleDownMod.Log.LogInfo((object)$"Processing scrap item: {scrapItem.itemProperties.itemName}, Current Value: {scrapItem.scrapValue}"); Component component = ((Component)scrapItem).GetComponent(BlackjackReflectionCache.CustomScrapControllerType); if ((Object)(object)component == (Object)null) { BlackjackDoubleDownMod.Log.LogWarning((object)"No CustomScrapController found!"); continue; } int num2 = CustomScrapControllerPatcher.GetGambledValue(component); int num3 = (int)BlackjackReflectionCache.OriginalScrapValueField.GetValue(component); if (num3 < num2) { num2 = num3; } BlackjackDoubleDownMod.Log.LogInfo((object)$"OriginalValue: {num3}, GambledValue: {num2}"); int num4; if (num2 > 0) { if (multiplier == 0f) { num4 = Math.Max(0, num3 - num2); BlackjackDoubleDownMod.Log.LogInfo((object)$"DoubleDown LOSS Calculation: {num3} - {num2} = {num4}"); } else if (multiplier == 2f) { num4 = num3 + num2; BlackjackDoubleDownMod.Log.LogInfo((object)$"DoubleDown WIN Calculation: {num3} + {num2} = {num4}"); } else if (multiplier == 2.5f) { num4 = num3 + (int)((float)num2 * 1.5f); BlackjackDoubleDownMod.Log.LogInfo((object)$"DoubleDown BLACKJACK Calculation: {num3} + ({num2} * 1.5) = {num4}"); } else { num4 = num3; BlackjackDoubleDownMod.Log.LogInfo((object)$"DoubleDown TIE - Keeping original value: {num4}"); } } else if (multiplier == 0f) { num4 = 0; BlackjackDoubleDownMod.Log.LogInfo((object)$"Normal LOSS Calculation: {num3} = {num4}"); } else if (multiplier == 2f) { num4 = (int)((float)num3 * 2f); BlackjackDoubleDownMod.Log.LogInfo((object)$"Normal WIN Calculation: {num3} * 2 = {num4}"); } else if (multiplier == 2.5f) { num4 = (int)((float)num3 * 2.5f); BlackjackDoubleDownMod.Log.LogInfo((object)$"Normal BLACKJACK Calculation: {num3} * 2.5 = {num4}"); } else { num4 = num3; BlackjackDoubleDownMod.Log.LogInfo((object)$"Normal TIE - Keeping original value: {num4}"); } int num5 = num4 - num3; num += num5; BlackjackDoubleDownMod.Log.LogInfo((object)$"Profit for this item: {num5}"); if (num4 != scrapItem.scrapValue) { BlackjackDoubleDownMod.Log.LogInfo((object)$"Value changed! Updating from {scrapItem.scrapValue} to {num4}"); BlackjackReflectionCache.UpdateScrapValueClientRpcMethod.Invoke(__instance, new object[3] { (object)new NetworkBehaviourReference((NetworkBehaviour)(object)scrapItem), num4, false }); } else { BlackjackDoubleDownMod.Log.LogInfo((object)$"No value change needed. Current: {scrapItem.scrapValue}, New: {num4}"); } } BlackjackDoubleDownMod.Log.LogInfo((object)$"Total Profit: {num}"); __result = num; return false; } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in MultiplyScrapValues_Prefix: {arg}"); return true; } } private static int GetPlayerIndexForScrap(object blackjackInstance, List<GrabbableObject> scrapItems) { List<GrabbableObject>[] array = (List<GrabbableObject>[])BlackjackReflectionCache.GambledScrapField.GetValue(blackjackInstance); for (int i = 0; i < array.Length; i++) { if (array[i] == scrapItems) { return i; } } return -1; } } internal static class BlackjackDoubleDownPatcher { private static int lastItemSlot = -1; private static float lastHintTime = 0f; public static void ApplyPatches(Harmony harmony, ManualLogSource log) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(BlackjackReflectionCache.BlackjackType, "Update", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BlackjackDoubleDownPatcher), "Update_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo2 = AccessTools.Method(BlackjackReflectionCache.BlackjackType, "CreateBetControlsClientRpc", new Type[2] { typeof(int), typeof(NetworkBehaviourReference) }, (Type[])null); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(BlackjackDoubleDownPatcher), "CreateBetControls_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"Double Down patches applied successfully"); } catch (Exception arg) { log.LogError((object)$"Failed to apply patches: {arg}"); } } [HarmonyPrefix] public static void Update_Prefix(object __instance) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) try { PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null || !(bool)BlackjackReflectionCache.GameInProgressField.GetValue(__instance)) { return; } int hoveredPlayerIndex = GetHoveredPlayerIndex(); if (hoveredPlayerIndex != -1 && IsHoveringOverBetControls(localPlayerController) && !((Object)(object)localPlayerController.hoveringOverTrigger == (Object)null)) { CheckForItemSwitchAndUpdateHint(__instance, localPlayerController, hoveredPlayerIndex); KeyboardShortcut value = BlackjackDoubleDownMod.DoubleDownKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && CanDoubleDown(__instance, localPlayerController, hoveredPlayerIndex)) { PerformDoubleDown(__instance, localPlayerController, hoveredPlayerIndex); } } } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in Update_Prefix: {arg}"); } } private static bool IsHoveringOverBetControls(PlayerControllerB player) { InteractTrigger hoveringOverTrigger = player.hoveringOverTrigger; int result; if (hoveringOverTrigger != null) { GameObject gameObject = ((Component)hoveringOverTrigger).gameObject; if (((gameObject == null) ? null : ((Object)gameObject).name?.Contains("Hit")).GetValueOrDefault()) { result = 1; goto IL_009e; } } InteractTrigger hoveringOverTrigger2 = player.hoveringOverTrigger; if (hoveringOverTrigger2 == null) { result = 0; } else { GameObject gameObject2 = ((Component)hoveringOverTrigger2).gameObject; result = (((gameObject2 == null) ? null : ((Object)gameObject2).name?.Contains("Stand")).GetValueOrDefault() ? 1 : 0); } goto IL_009e; IL_009e: return (byte)result != 0; } [HarmonyPostfix] public static void CreateBetControls_Postfix(object __instance, int playerIdx, NetworkBehaviourReference playerRef) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) try { if (ShouldShowDoubleDownHint()) { PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; PlayerControllerB val = default(PlayerControllerB); if (!((Object)(object)localPlayerController == (Object)null) && ((NetworkBehaviourReference)(ref playerRef)).TryGet<PlayerControllerB>(ref val, (NetworkManager)null) && !((Object)(object)val != (Object)(object)localPlayerController) && CanDoubleDown(__instance, localPlayerController, playerIdx)) { KeyboardShortcut value = BlackjackDoubleDownMod.DoubleDownKey.Value; string text = ((object)(KeyboardShortcut)(ref value)).ToString(); HUDManager.Instance.DisplayTip("Double Down Hint", "Press [" + text + "] to double your bet and receive one card.", false, false, "LC_Tip1"); } } } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in CreateBetControls_Postfix: {arg}"); } } private static void CheckForItemSwitchAndUpdateHint(object blackjackInstance, PlayerControllerB player, int playerIndex) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) try { if (player.currentItemSlot != lastItemSlot) { lastItemSlot = player.currentItemSlot; if (CanDoubleDown(blackjackInstance, player, playerIndex)) { KeyboardShortcut value = BlackjackDoubleDownMod.DoubleDownKey.Value; string text = ((object)(KeyboardShortcut)(ref value)).ToString(); HUDManager.Instance.DisplayTip("Double Down Hint", "Press [" + text + "] to double your bet and receive one card.", false, false, "LC_Tip1"); } } } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in CheckForItemSwitchAndUpdateHint: {arg}"); } } private static bool ShouldShowDoubleDownHint() { if (Time.time - lastHintTime > 20f) { lastHintTime = Time.time; return true; } return false; } private static int GetLocalPlayerIndex(object blackjackInstance, PlayerControllerB localPlayer) { PlayerControllerB[] array = (PlayerControllerB[])BlackjackReflectionCache.GamblingPlayersField.GetValue(blackjackInstance); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] == (Object)(object)localPlayer) { return i; } } return -1; } private static int GetHoveredPlayerIndex() { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || (Object)(object)val.hoveringOverTrigger == (Object)null) { return -1; } GameObject gameObject = ((Component)val.hoveringOverTrigger).gameObject; if ((Object)(object)gameObject == (Object)null) { return -1; } Transform val2 = gameObject.transform; while ((Object)(object)val2 != (Object)null) { if (((Object)val2).name.StartsWith("Player") && ((Object)val2).name.EndsWith("HandPosition")) { string s = ((Object)val2).name.Substring(6, 1); if (int.TryParse(s, out var result)) { return result - 1; } } val2 = val2.parent; } return -1; } private static bool CanDoubleDown(object blackjackInstance, PlayerControllerB player, int playerIndex) { bool[] array = (bool[])BlackjackReflectionCache.PlayerCompletedTurnField.GetValue(blackjackInstance); if (array[playerIndex]) { return false; } IList list = (IList)BlackjackReflectionCache.PlayerCardsField.GetValue(blackjackInstance); if (!(list[playerIndex] is IList list2) || list2.Count != 2) { return false; } GrabbableObject val = player.ItemSlots[player.currentItemSlot]; if ((Object)(object)val == (Object)null) { return false; } Component component = ((Component)val).GetComponent(BlackjackReflectionCache.CustomScrapControllerType); if ((Object)(object)component == (Object)null) { return false; } if (val.scrapValue <= 0) { return false; } return true; } private static void PerformDoubleDown(object blackjackInstance, PlayerControllerB player, int playerIndex) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) try { BlackjackDoubleDownMod.Log.LogInfo((object)$"Starting double down locally, for {player.playerUsername} at position {playerIndex}"); GrabbableObject val = player.ItemSlots[player.currentItemSlot]; NetworkBehaviourReference val2 = default(NetworkBehaviourReference); ((NetworkBehaviourReference)(ref val2))..ctor((NetworkBehaviour)(object)player); int num = playerIndex - 1000; BlackjackReflectionCache.JoinGameServerRpcMethod.Invoke(blackjackInstance, new object[2] { val2, num }); BlackjackDoubleDownMod.Log.LogInfo((object)"Double down request sent"); } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in PerformDoubleDown: {arg}"); } } } internal static class BustTracking { private static HashSet<int> alreadyBustedPlayers = new HashSet<int>(); public static void MarkPlayerBusted(int playerIdx) { alreadyBustedPlayers.Add(playerIdx); } public static bool IsPlayerAlreadyBusted(int playerIdx) { return alreadyBustedPlayers.Contains(playerIdx); } public static void Clear() { alreadyBustedPlayers.Clear(); } } internal static class BlackjackProcessResultsPatcher { public static void ApplyPatches(Harmony harmony, ManualLogSource log) { //IL_0032: 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_0054: Expected O, but got Unknown //IL_0054: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(BlackjackReflectionCache.BlackjackType, "ProcessResults", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BlackjackProcessResultsPatcher), "ProcessResults_Prefix", (Type[])null), new HarmonyMethod(typeof(BlackjackProcessResultsPatcher), "ProcessResults_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"ProcessResults patched for bust tracking cleanup"); } } catch (Exception arg) { log.LogError((object)$"Failed to patch ProcessResults: {arg}"); } } [HarmonyPrefix] public static void ProcessResults_Prefix(object __instance) { try { PlayerControllerB[] array = (PlayerControllerB[])BlackjackReflectionCache.GamblingPlayersField.GetValue(__instance); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && BustTracking.IsPlayerAlreadyBusted(i)) { BlackjackDoubleDownMod.Log.LogInfo((object)$"Removing player {i} from ProcessResults - double down bust"); array[i] = null; } } } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in ProcessResults_Prefix: {arg}"); } } [HarmonyPostfix] public static void ProcessResults_Postfix() { BustTracking.Clear(); CustomScrapControllerPatcher.ClearAllGambledValues(); BlackjackDoubleDownMod.Log.LogInfo((object)"Cleared bust tracking AFTER ProcessResults"); } } internal static class JoinGameServerRpcPatcher { public static void ApplyPatches(Harmony harmony, ManualLogSource log) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(BlackjackReflectionCache.BlackjackType, "JoinGameServerRpc", new Type[2] { typeof(NetworkBehaviourReference), typeof(int) }, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(JoinGameServerRpcPatcher), "JoinGameServerRpc_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"JoinGameServerRpc patched for double down support"); } else { log.LogError((object)"Could not find JoinGameServerRpc method to patch!"); } } catch (Exception arg) { log.LogError((object)$"Failed to patch JoinGameServerRpc: {arg}"); } } [HarmonyPrefix] public static bool JoinGameServerRpc_Prefix(object __instance, NetworkBehaviourReference playerRef, int playerIdx) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) try { BlackjackDoubleDownMod.Log.LogInfo((object)$"Running JoinGameServerRPC {playerIdx}"); if (playerIdx >= -100) { return true; } object obj = ((__instance is NetworkBehaviour) ? __instance : null); if (obj != null && ((NetworkBehaviour)obj).IsServer) { BlackjackDoubleDownMod.Log.LogInfo((object)"SERVER: Handling double down logic"); int playerIdx2 = playerIdx + 1000; HandleDoubleDownOnServer(__instance, playerRef, playerIdx2); return false; } BlackjackDoubleDownMod.Log.LogInfo((object)"CLIENT: sending joinGameServerRPC double down to host"); return true; } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in JoinGameServerRpc_Prefix: {arg}"); return true; } } private static void HandleDoubleDownOnServer(object __instance, NetworkBehaviourReference playerRef, int playerIdx) { //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) try { BlackjackDoubleDownMod.Log.LogInfo((object)$"SERVER: Handling double down for player {playerIdx}"); PlayerControllerB val = default(PlayerControllerB); if (!((NetworkBehaviourReference)(ref playerRef)).TryGet<PlayerControllerB>(ref val, (NetworkManager)null)) { BlackjackDoubleDownMod.Log.LogError((object)"Failed to get player controller from NetworkBehaviourReference"); return; } GrabbableObject val2 = val.ItemSlots[val.currentItemSlot]; if ((Object)(object)val2 == (Object)null) { BlackjackDoubleDownMod.Log.LogError((object)"No held item found for double down"); return; } Component component = ((Component)val2).GetComponent(BlackjackReflectionCache.CustomScrapControllerType); if ((Object)(object)component == (Object)null) { BlackjackDoubleDownMod.Log.LogError((object)"No CustomScrapController found on held item"); return; } if ((bool)BlackjackReflectionCache.LockFromGamblingField.GetValue(component)) { BlackjackReflectionCache.ShowWarningMessageClientRpcMethod.Invoke(__instance, new object[4] { val, "Cannot bet", "Scrap is already being gambled", true }); return; } BlackjackReflectionCache.LockFromGamblingField.SetValue(component, true); List<GrabbableObject>[] array = (List<GrabbableObject>[])BlackjackReflectionCache.GambledScrapField.GetValue(__instance); if (array == null || playerIdx < 0 || playerIdx >= array.Length) { BlackjackDoubleDownMod.Log.LogError((object)"Invalid gambledScrap array or player index"); return; } int scrapValue = val2.scrapValue; BlackjackReflectionCache.OriginalScrapValueField.SetValue(component, val2.scrapValue); BlackjackDoubleDownMod.Log.LogInfo((object)"Updated originalScrapValue field"); int num = 0; foreach (GrabbableObject item in array[playerIdx]) { if ((Object)(object)item != (Object)null) { Component component2 = ((Component)item).GetComponent(BlackjackReflectionCache.CustomScrapControllerType); if ((Object)(object)component2 != (Object)null) { int num2 = (int)BlackjackReflectionCache.OriginalScrapValueField.GetValue(component2); num += num2; } } } int num3 = ((num <= scrapValue) ? num : scrapValue); CustomScrapControllerPatcher.SetGambledValue(component, num3); array[playerIdx].Add(val2); int num4 = num + num3; BlackjackDoubleDownMod.Log.LogInfo((object)$"Double down total bet amount: {num4}"); PlayerControllerB[] array2 = (PlayerControllerB[])BlackjackReflectionCache.GamblingPlayersField.GetValue(__instance); if (array2 == null || playerIdx >= array2.Length) { BlackjackDoubleDownMod.Log.LogError((object)"Invalid gamblingPlayers array"); return; } BlackjackReflectionCache.JoinGameSuccessfulClientRpcMethod?.Invoke(__instance, new object[3] { (object)new NetworkBehaviourReference((NetworkBehaviour)(object)val), playerIdx, num4 }); BlackjackReflectionCache.DestroyBetControlsClientRpcMethod?.Invoke(__instance, new object[1] { playerIdx }); BlackjackReflectionCache.TakeTurnAsPlayerServerRpcMethod?.Invoke(__instance, new object[3] { (object)new NetworkBehaviourReference((NetworkBehaviour)(object)val), playerIdx, "hit" }); BlackjackReflectionCache.TakeTurnAsPlayerServerRpcMethod?.Invoke(__instance, new object[3] { (object)new NetworkBehaviourReference((NetworkBehaviour)(object)val), playerIdx, "stand" }); BlackjackDoubleDownMod.Log.LogInfo((object)$"Double down completed successfully for player {playerIdx}"); } catch (Exception arg) { BlackjackDoubleDownMod.Log.LogError((object)$"Error in HandleDoubleDownOnServer: {arg}"); } } }