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 Big Cart Fix v1.0.6
BigCartFix.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace BigCartFix; [BepInPlugin("bigcart.fix.runtime", "Big Cart Fix", "1.0.6")] public sealed class Plugin : BaseUnityPlugin { internal const string PluginGuid = "bigcart.fix.runtime"; internal const string PluginName = "Big Cart Fix"; internal const string PluginVersion = "1.0.6"; private void Awake() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) ModLog.Source = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); new Harmony("bigcart.fix.runtime").PatchAll(); CartPurchaseSettings.Apply(); ModLog.Info("Patched Big Cart display, null guard, and shop purchase limits."); } } internal static class ModConfig { private const string DisplaySection = "Display"; private const string ShopSection = "Shop"; private const string GeneralSection = "General"; private static ConfigEntry<bool> debugLogging; private static ConfigEntry<bool> enableShopSettings; private static ConfigEntry<int> maxBigCartsForPurchase; private static ConfigEntry<int> guaranteedBigCartsInShop; private static ConfigEntry<int> bigCartPriceOverride; private static ConfigEntry<string> bigCartVolumeOverride; private static ConfigEntry<string> valueTextPath; public static bool DebugLogging { get { if (debugLogging != null) { return debugLogging.Value; } return false; } } public static int MaxBigCartsForPurchase { get { if (maxBigCartsForPurchase == null) { return 4; } return Mathf.Clamp(maxBigCartsForPurchase.Value, 1, 20); } } public static bool EnableShopSettings { get { if (enableShopSettings != null) { return enableShopSettings.Value; } return true; } } public static int GuaranteedBigCartsInShop { get { if (guaranteedBigCartsInShop == null) { return 1; } return Mathf.Clamp(guaranteedBigCartsInShop.Value, 0, 20); } } public static int BigCartPriceOverride { get { if (bigCartPriceOverride == null) { return 0; } return Mathf.Clamp(bigCartPriceOverride.Value, 0, 1000000); } } public static string BigCartVolumeOverride { get { if (bigCartVolumeOverride == null || bigCartVolumeOverride.Value == null) { return "Default"; } return bigCartVolumeOverride.Value.Trim(); } } public static string ValueTextPath { get { if (valueTextPath == null || valueTextPath.Value == null) { return string.Empty; } return valueTextPath.Value.Trim(); } } public static void Bind(ConfigFile config) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown debugLogging = config.Bind<bool>("General", "DebugLogging", false, "Enable extra logs for Big Cart Fix."); valueTextPath = config.Bind<string>("Display", "ValueTextPath", string.Empty, "Optional Transform path to the Big Cart TMP value text. Leave empty to use the built-in paths."); enableShopSettings = config.Bind<bool>("Shop", "EnableShopSettings", true, "Enable Big Cart shop limit, guarantee, price, and volume settings."); maxBigCartsForPurchase = config.Bind<int>("Shop", "MaxBigCartsForPurchase", 4, new ConfigDescription("Maximum amount of Big Carts that can be offered/purchased during a run.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[0])); guaranteedBigCartsInShop = config.Bind<int>("Shop", "GuaranteedBigCartsInShop", 1, new ConfigDescription("How many Big Carts should be forced into the regular shop candidate list. Set to 0 to only use vanilla/random shop selection.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), new object[0])); bigCartPriceOverride = config.Bind<int>("Shop", "BigCartPriceOverride", 0, new ConfigDescription("Override Big Cart item value. Set to 0 to keep the original mod value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000000), new object[0])); bigCartVolumeOverride = config.Bind<string>("Shop", "BigCartVolumeOverride", "Default", new ConfigDescription("Override the shop slot volume used by Big Cart. Use Default, small, medium, large, large_wide, large_high, large_plus, or vehicle.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[8] { "Default", "small", "medium", "large", "large_wide", "large_high", "large_plus", "vehicle" }), new object[0])); } } internal static class ModLog { public static ManualLogSource Source; public static void Info(string message) { if (Source != null) { Source.LogInfo((object)message); } } public static void Warning(string message) { if (Source != null) { Source.LogWarning((object)message); } else { Debug.LogWarning((object)("[Big Cart Fix] " + message)); } } public static void DebugInfo(string message) { if (ModConfig.DebugLogging && Source != null) { Source.LogInfo((object)("[Debug] " + message)); } } } internal static class CartValueDisplay { private static readonly FieldInfo HaulCurrentField = AccessTools.Field(typeof(PhysGrabCart), "haulCurrent"); private static readonly FieldInfo OriginalColorField = AccessTools.Field(typeof(ValueScreen), "originalColor"); private static readonly FieldInfo ValuePreviousField = AccessTools.Field(typeof(ValueScreen), "valuePrevious"); private static readonly FieldInfo ValueCurrentField = AccessTools.Field(typeof(ValueScreen), "valueCurrent"); private static readonly FieldInfo ResetTextField = AccessTools.Field(typeof(ValueScreen), "resetText"); private static readonly FieldInfo SoundSourceField = AccessTools.Field(typeof(Sound), "Source"); private static readonly FieldInfo[] SoundFields = typeof(Sound).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly string[] ValueTextPathCandidates = new string[12] { "Value Screen/Value Text", "Value Screen/Text", "Value Screen/Text (TMP)", "ValueScreen/ValueText", "ValueScreen/Text", "Screen/Value Text", "Screen/Text", "Canvas/Value Text", "Canvas/Text", "Canvas/Text (TMP)", "Value Text", "Text (TMP)" }; private static readonly Dictionary<int, TMP_Text> FallbackTexts = new Dictionary<int, TMP_Text>(); private static readonly HashSet<int> BoundScreens = new HashSet<int>(); private static readonly HashSet<int> MissingDisplayWarnings = new HashSet<int>(); private static readonly HashSet<int> LoggedTextPaths = new HashSet<int>(); private static Sound sourceIncreaseSound; private static Sound sourceDecreaseSound; private static bool loggedSoundAttached; private static bool loggedSoundMissing; public static void EnsureBound(PhysGrabCart cart) { if ((Object)(object)cart == (Object)null) { return; } int instanceID = ((Object)cart).GetInstanceID(); if (FallbackTexts.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null) { return; } LogTextPaths(cart); if ((Object)(object)cart.valueScreen != (Object)null && (Object)(object)cart.valueScreen.displayText != (Object)null) { BindScreen(cart, cart.valueScreen, cart.valueScreen.displayText); return; } ValueScreen componentInChildren = ((Component)cart).GetComponentInChildren<ValueScreen>(true); TMP_Text val = FindDisplayText(cart, componentInChildren); TextMeshPro val2 = (TextMeshPro)(object)((val is TextMeshPro) ? val : null); if ((Object)(object)componentInChildren != (Object)null) { if ((Object)(object)componentInChildren.displayText == (Object)null && (Object)(object)val2 != (Object)null) { componentInChildren.displayText = val2; } if ((Object)(object)componentInChildren.displayText != (Object)null) { BindScreen(cart, componentInChildren, componentInChildren.displayText); return; } } if ((Object)(object)val2 != (Object)null) { ValueScreen val3 = ((Component)val2).gameObject.GetComponent<ValueScreen>(); if ((Object)(object)val3 == (Object)null) { val3 = ((Component)val2).gameObject.AddComponent<ValueScreen>(); } BindScreen(cart, val3, val2); } else if ((Object)(object)val != (Object)null) { FallbackTexts[instanceID] = val; SetText(val, ReadHaul(cart)); } else if (MissingDisplayWarnings.Add(instanceID)) { ModLog.Warning("Could not find a value text display on this cart prefab."); } } private static void BindScreen(PhysGrabCart cart, ValueScreen screen, TextMeshPro displayText) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)cart == (Object)null) && !((Object)(object)screen == (Object)null) && !((Object)(object)displayText == (Object)null)) { int instanceID = ((Object)cart).GetInstanceID(); screen.displayText = displayText; cart.valueScreen = screen; OriginalColorField.SetValue(screen, ((Graphic)displayText).color); TryAttachSounds(screen); if (BoundScreens.Add(instanceID)) { SetScreenBaseline(screen, ReadHaul(cart)); } } } private static bool TryAttachSounds(ValueScreen screen) { if ((Object)(object)screen == (Object)null) { return false; } CacheSourceSounds(screen); if (!HasPlayableSound(screen.soundValueIncrease) && HasPlayableSound(sourceIncreaseSound)) { screen.soundValueIncrease = CloneSound(sourceIncreaseSound); } if (!HasPlayableSound(screen.soundValueDecrease) && HasPlayableSound(sourceDecreaseSound)) { screen.soundValueDecrease = CloneSound(sourceDecreaseSound); } bool flag = HasPlayableSound(screen.soundValueIncrease) && HasPlayableSound(screen.soundValueDecrease); if (flag && !loggedSoundAttached) { ModLog.Info("Attached vanilla cart value sounds to Big Cart value display."); loggedSoundAttached = true; } return flag; } private static void CacheSourceSounds(ValueScreen skipScreen) { if (HasPlayableSound(sourceIncreaseSound) && HasPlayableSound(sourceDecreaseSound)) { return; } ValueScreen[] array = Resources.FindObjectsOfTypeAll<ValueScreen>(); ValueScreen[] array2 = array; foreach (ValueScreen val in array2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)skipScreen) && HasPlayableSound(val.soundValueIncrease) && HasPlayableSound(val.soundValueDecrease)) { sourceIncreaseSound = val.soundValueIncrease; sourceDecreaseSound = val.soundValueDecrease; break; } } } private static bool HasPlayableSound(Sound sound) { if (sound != null && sound.Sounds != null) { return sound.Sounds.Length > 0; } return false; } private static Sound CloneSound(Sound source) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown if (source == null) { return null; } Sound val = new Sound(); FieldInfo[] soundFields = SoundFields; foreach (FieldInfo fieldInfo in soundFields) { if (!fieldInfo.IsInitOnly && !(fieldInfo.Name == "Source") && !(fieldInfo.Name == "LowPassLogic") && !(fieldInfo.Name == "HasLowPassLogic")) { fieldInfo.SetValue(val, fieldInfo.GetValue(source)); } } SoundSourceField.SetValue(val, null); return val; } private static void SetScreenBaseline(ValueScreen screen, int value) { int num = Mathf.Max(0, value); ValuePreviousField.SetValue(screen, num); ValueCurrentField.SetValue(screen, num); ResetTextField.SetValue(screen, true); SetText((TMP_Text)(object)screen.displayText, num); } public static void Refresh(PhysGrabCart cart) { EnsureBound(cart); if ((Object)(object)cart != (Object)null && FallbackTexts.TryGetValue(((Object)cart).GetInstanceID(), out var value) && (Object)(object)value != (Object)null) { SetText(value, ReadHaul(cart)); } } public static bool TryHandleValueScreenUpdate(ValueScreen screen, int value) { if ((Object)(object)screen == (Object)null) { return false; } if ((Object)(object)screen.displayText == (Object)null) { return false; } if (TryAttachSounds(screen)) { return true; } if (!loggedSoundMissing) { ModLog.Warning("No playable vanilla cart value sounds found yet; updating Big Cart value display without audio."); loggedSoundMissing = true; } SetText((TMP_Text)(object)screen.displayText, value); return false; } private static int ReadHaul(PhysGrabCart cart) { object value = HaulCurrentField.GetValue(cart); if (value is int) { return (int)value; } return 0; } private static TMP_Text FindDisplayText(PhysGrabCart cart, ValueScreen existingScreen) { if ((Object)(object)existingScreen != (Object)null && (Object)(object)existingScreen.displayText != (Object)null) { return (TMP_Text)(object)existingScreen.displayText; } TMP_Text val = FindTextAtPath(cart, ModConfig.ValueTextPath); if ((Object)(object)val != (Object)null) { ModLog.DebugInfo("Found value text from config path: " + GetPath(((Component)cart).transform, val.transform)); return val; } string[] valueTextPathCandidates = ValueTextPathCandidates; foreach (string path in valueTextPathCandidates) { TMP_Text val2 = FindTextAtPath(cart, path); if ((Object)(object)val2 != (Object)null) { ModLog.DebugInfo("Found value text from built-in path: " + GetPath(((Component)cart).transform, val2.transform)); return val2; } } TMP_Text val3 = FindTextByInitialValue(cart); if ((Object)(object)val3 != (Object)null) { ModLog.DebugInfo("Found value text by initial value: " + GetPath(((Component)cart).transform, val3.transform)); return val3; } return FindOnlyWorldText(cart); } private static TMP_Text FindTextAtPath(PhysGrabCart cart, string path) { if ((Object)(object)cart == (Object)null || string.IsNullOrEmpty(path)) { return null; } Transform val = FindTransformByPath(((Component)cart).transform, path); if ((Object)(object)val == (Object)null) { return null; } TMP_Text component = ((Component)val).GetComponent<TMP_Text>(); if ((Object)(object)component != (Object)null) { return component; } return ((Component)val).GetComponentInChildren<TMP_Text>(true); } private static Transform FindTransformByPath(Transform root, string path) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(path)) { return null; } string text = path.Trim().Replace('\\', '/').Trim(new char[1] { '/' }); if (text.Length == 0) { return null; } if (string.Equals(text, ((Object)root).name, StringComparison.OrdinalIgnoreCase)) { return root; } string text2 = ((Object)root).name + "/"; if (text.StartsWith(text2, StringComparison.OrdinalIgnoreCase)) { text = text.Substring(text2.Length); } Transform val = root.Find(text); if ((Object)(object)val != (Object)null) { return val; } return FindTransformByPathIgnoreCase(root, text); } private static Transform FindTransformByPathIgnoreCase(Transform root, string path) { string[] array = path.Split(new char[1] { '/' }); Transform val = root; string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (text2.Length == 0) { continue; } Transform val2 = null; for (int j = 0; j < val.childCount; j++) { Transform child = val.GetChild(j); if (string.Equals(((Object)child).name, text2, StringComparison.OrdinalIgnoreCase)) { val2 = child; break; } } if ((Object)(object)val2 == (Object)null) { return null; } val = val2; } return val; } private static TMP_Text FindTextByInitialValue(PhysGrabCart cart) { TMP_Text[] componentsInChildren = ((Component)cart).GetComponentsInChildren<TMP_Text>(true); TMP_Text[] array = componentsInChildren; foreach (TMP_Text val in array) { if (!((Object)(object)val == (Object)null) && val.text != null && val.text.Contains("100000")) { return val; } } return null; } private static TMP_Text FindOnlyWorldText(PhysGrabCart cart) { TMP_Text[] componentsInChildren = ((Component)cart).GetComponentsInChildren<TMP_Text>(true); TMP_Text val = null; int num = 0; TMP_Text[] array = componentsInChildren; foreach (TMP_Text val2 in array) { if (val2 is TextMeshPro) { val = val2; num++; } } if (num == 1) { ModLog.DebugInfo("Found the only world TMP text: " + GetPath(((Component)cart).transform, val.transform)); return val; } return null; } private static void LogTextPaths(PhysGrabCart cart) { if (!ModConfig.DebugLogging || (Object)(object)cart == (Object)null) { return; } int instanceID = ((Object)cart).GetInstanceID(); if (!LoggedTextPaths.Add(instanceID)) { return; } TMP_Text[] componentsInChildren = ((Component)cart).GetComponentsInChildren<TMP_Text>(true); TMP_Text[] array = componentsInChildren; foreach (TMP_Text val in array) { if (!((Object)(object)val == (Object)null)) { string text = ((val.text == null) ? string.Empty : val.text); ModLog.DebugInfo("TMP path: " + GetPath(((Component)cart).transform, val.transform) + " | text: " + text); } } } private static string GetPath(Transform root, Transform target) { if ((Object)(object)root == (Object)null || (Object)(object)target == (Object)null) { return string.Empty; } List<string> list = new List<string>(); Transform val = target; while ((Object)(object)val != (Object)null) { list.Insert(0, ((Object)val).name); if ((Object)(object)val == (Object)(object)root) { break; } val = val.parent; } return string.Join("/", list.ToArray()); } private static void SetText(TMP_Text text, int value) { int num = Mathf.Max(0, value); text.text = "<color=#bd4300>$</color>" + SemiFunc.DollarGetString(num); } } internal static class CartPurchaseSettings { private static readonly string[] BigCartItemNames = new string[5] { "Cart Big", "Item Cart Big", "Big Cart", "B.I.G. C.A.R.T.", "Big_Cart" }; private static readonly HashSet<int> AppliedItems = new HashSet<int>(); private static readonly HashSet<int> GuaranteedManagers = new HashSet<int>(); private static bool loggedMissingBigCartItem; public static void Apply() { if (!ModConfig.EnableShopSettings || (Object)(object)StatsManager.instance == (Object)null || StatsManager.instance.itemDictionary == null) { return; } foreach (KeyValuePair<string, Item> item in StatsManager.instance.itemDictionary) { if (IsBigCartItem(item.Key, item.Value)) { ApplyToItem(item.Value); } } } public static void GuaranteeShopCandidates(ShopManager shopManager) { if (!ModConfig.EnableShopSettings || ModConfig.GuaranteedBigCartsInShop <= 0 || (Object)(object)shopManager == (Object)null || shopManager.potentialItems == null) { return; } Item val = FindBigCartItem(); if ((Object)(object)val == (Object)null) { if (!loggedMissingBigCartItem) { ModLog.Warning("Could not find the Big Cart item in StatsManager.itemDictionary; shop guarantee skipped."); loggedMissingBigCartItem = true; } return; } ApplyToItem(val); RemoveBigCartCandidates(shopManager.potentialItems); int num = SemiFunc.StatGetItemsPurchased(((Object)val).name); int num2 = Mathf.Max(0, val.maxAmountInShop - num); int num3 = Mathf.Min(ModConfig.GuaranteedBigCartsInShop, num2); if (num3 > 0) { for (int i = 0; i < num3; i++) { shopManager.potentialItems.Add(val); } shopManager.itemSpawnTargetAmount = Mathf.Max(shopManager.itemSpawnTargetAmount, num3); if (GuaranteedManagers.Add(((Object)shopManager).GetInstanceID())) { ModLog.Info("Guaranteed " + num3 + " Big Cart shop candidate(s)."); } else { ModLog.DebugInfo("Refreshed guaranteed Big Cart shop candidates: " + num3 + "."); } } } private static Item FindBigCartItem() { if ((Object)(object)StatsManager.instance == (Object)null || StatsManager.instance.itemDictionary == null) { return null; } foreach (KeyValuePair<string, Item> item in StatsManager.instance.itemDictionary) { if (IsBigCartItem(item.Key, item.Value)) { return item.Value; } } return null; } private static void RemoveBigCartCandidates(List<Item> items) { for (int num = items.Count - 1; num >= 0; num--) { if (IsBigCartItem(string.Empty, items[num])) { items.RemoveAt(num); } } } private static bool IsBigCartItem(string dictionaryKey, Item item) { if ((Object)(object)item == (Object)null) { return false; } if (!MatchesKnownName(dictionaryKey) && !MatchesKnownName(((Object)item).name)) { return MatchesKnownName(item.itemName); } return true; } private static bool MatchesKnownName(string value) { if (string.IsNullOrEmpty(value)) { return false; } string a = value.Replace("(Clone)", string.Empty).Trim(); string[] bigCartItemNames = BigCartItemNames; foreach (string b in bigCartItemNames) { if (string.Equals(a, b, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static void ApplyToItem(Item item) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) int num = (item.maxPurchaseAmount = (item.maxAmountInShop = (item.maxAmount = ModConfig.MaxBigCartsForPurchase))); int bigCartPriceOverride = ModConfig.BigCartPriceOverride; if (bigCartPriceOverride > 0 && (Object)(object)item.value != (Object)null) { item.value.valueMin = bigCartPriceOverride; item.value.valueMax = bigCartPriceOverride; } if (TryParseVolumeOverride(out var volume)) { item.itemVolume = volume; } if (AppliedItems.Add(((Object)item).GetInstanceID())) { ModLog.Info("Big Cart shop limit set to " + num + "."); } else { ModLog.DebugInfo("Big Cart shop limit refreshed to " + num + "."); } } private static bool TryParseVolumeOverride(out itemVolume volume) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected I4, but got Unknown volume = (itemVolume)1; string bigCartVolumeOverride = ModConfig.BigCartVolumeOverride; if (string.IsNullOrEmpty(bigCartVolumeOverride) || string.Equals(bigCartVolumeOverride, "Default", StringComparison.OrdinalIgnoreCase)) { return false; } try { volume = (itemVolume)(int)(itemVolume)Enum.Parse(typeof(itemVolume), bigCartVolumeOverride, ignoreCase: true); return true; } catch { ModLog.Warning("Invalid BigCartVolumeOverride value: " + bigCartVolumeOverride + ". Keeping original item volume."); return false; } } } [HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")] internal static class StatsManagerLoadItemsFromFolderPatch { private static void Postfix() { CartPurchaseSettings.Apply(); } } [HarmonyPatch(typeof(ShopManager), "GetAllItemsFromStatsManager")] internal static class ShopManagerGetAllItemsFromStatsManagerPatch { private static void Prefix() { CartPurchaseSettings.Apply(); } private static void Postfix(ShopManager __instance) { CartPurchaseSettings.GuaranteeShopCandidates(__instance); } } [HarmonyPatch(typeof(ItemManager), "GetPurchasedItems")] internal static class ItemManagerGetPurchasedItemsPatch { private static void Prefix() { CartPurchaseSettings.Apply(); } } [HarmonyPatch(typeof(PhysGrabCart), "Start")] internal static class PhysGrabCartStartPatch { private static void Postfix(PhysGrabCart __instance) { CartValueDisplay.EnsureBound(__instance); } } [HarmonyPatch(typeof(PhysGrabCart), "ObjectsInCart")] internal static class PhysGrabCartObjectsInCartPatch { private static readonly FieldInfo InCartField = AccessTools.Field(typeof(PhysGrabCart), "inCart"); private static readonly HashSet<int> MissingInCartWarnings = new HashSet<int>(); private static bool Prefix(PhysGrabCart __instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown CartValueDisplay.EnsureBound(__instance); Transform val = (Transform)InCartField.GetValue(__instance); if ((Object)(object)val != (Object)null) { return true; } int instanceID = ((Object)__instance).GetInstanceID(); if (MissingInCartWarnings.Add(instanceID)) { ModLog.Warning("Skipping cart item scan because this cart prefab has no 'In Cart' transform."); } return false; } private static void Postfix(PhysGrabCart __instance) { CartValueDisplay.Refresh(__instance); } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { return null; } return __exception; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { FieldInfo valueScreenField = AccessTools.Field(typeof(PhysGrabCart), "valueScreen"); FieldInfo haulCurrentField = AccessTools.Field(typeof(PhysGrabCart), "haulCurrent"); MethodInfo updateValueMethod = AccessTools.Method(typeof(ValueScreen), "UpdateValue", new Type[1] { typeof(int) }, (Type[])null); List<CodeInstruction> codes = new List<CodeInstruction>(instructions); bool patched = false; for (int i = 0; i < codes.Count; i++) { CodeInstruction code = codes[i]; if (!patched && CodeInstructionExtensions.LoadsField(code, valueScreenField, false) && i + 3 < codes.Count && codes[i + 1].opcode == OpCodes.Ldarg_0 && CodeInstructionExtensions.LoadsField(codes[i + 2], haulCurrentField, false) && CodeInstructionExtensions.Calls(codes[i + 3], updateValueMethod)) { Label hasValueScreenLabel = generator.DefineLabel(); codes[i + 1].labels.Add(hasValueScreenLabel); yield return code; yield return new CodeInstruction(OpCodes.Dup, (object)null); yield return new CodeInstruction(OpCodes.Brtrue_S, (object)hasValueScreenLabel); yield return new CodeInstruction(OpCodes.Pop, (object)null); yield return new CodeInstruction(OpCodes.Ret, (object)null); patched = true; } else { yield return code; } } if (!patched) { ModLog.Warning("Could not find ValueScreen.UpdateValue in PhysGrabCart.ObjectsInCart."); } } } [HarmonyPatch(typeof(ValueScreen), "UpdateValue")] internal static class ValueScreenUpdateValuePatch { private static bool Prefix(ValueScreen __instance, int __0) { return CartValueDisplay.TryHandleValueScreenUpdate(__instance, __0); } }