Jump to content
  • Error when trying to sell to a vending machine


    bdubyah
    • Version: 1.0b333

    This is related to modding the game, though is something that worked fine before 1.0. Many modders have made custom vending machines, or even faked a trader using a block setup using the VendingMachine class. But in 1.0 you will get an NRE if you try to sell to one of these vending machines. The error is:

    2024-08-04T23:34:07 85.406 ERR [XUi] Error while updating window group 'backpack':
    2024-08-04T23:34:07 85.409 EXC Object reference not set to an instance of an object
      at ItemActionEntrySell.OnActivated () [0x0060e] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiC_ItemActionEntry.OnPressAction (XUiController _sender, System.Int32 _mouseButton) [0x00041] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiController.OnPressed (System.Int32 _mouseButton) [0x0000e] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiController.Pressed (System.Int32 _mouseButton) [0x00000] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiC_ItemActionList.Update (System.Single _dt) [0x001a7] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiController.Update (System.Single _dt) [0x00084] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiController.Update (System.Single _dt) [0x00084] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiController.Update (System.Single _dt) [0x00084] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiC_InfoWindow.Update (System.Single _dt) [0x00000] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiC_ItemInfoWindow.Update (System.Single _dt) [0x00000] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUiController.Update (System.Single _dt) [0x00084] in <40e9b6e9762f43cf836123d0f549ad32>:0 
      at XUi.OnUpdateDeltaTime (System.Single updateDeltaTime) [0x00159] in <40e9b6e9762f43cf836123d0f549ad32>:0 
    UnityEngine.StackTraceUtility:ExtractStringFromException(Object)
    Log:Exception(Exception)
    XUi:OnUpdateDeltaTime(Single)
    XUiUpdater:Update()
    XUiUpdateHelper:LateUpdate()

    A fellow modder, IDC, looked into this and found that the game now assumes if you are selling items, you must be at a trader, since in vanilla that's really the only time you sell things. But this doesn't apply to mods of course. I know this won't be a priority but would be nice if it could get fixed in vanilla. IDC was kind enough to put together a small patch that sorts it, which looks like:

    [HarmonyPatch(typeof(ItemActionEntrySell))]
        public class Patch_ItemActionEntrySell {
    
            [HarmonyTranspiler]
            [HarmonyPatch("OnActivated")]
            public static IEnumerable OnActivated(IEnumerable<CodeInstruction> instructions) {
                var codes = new List<CodeInstruction>(instructions);
                int start = 0, end = 0;
    
                for (int i = 0; i < codes.Count; i++) {
                    start = i;
                    if (!(codes[i].opcode == OpCodes.Call)) continue;
                    if (!(codes[i].operand is MethodInfo methodInfo && methodInfo.Name == "get_Current")) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Ldarg_0)) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Call)) continue;
                    if (!(codes[i].operand is MethodInfo methodInfo1 && methodInfo1.Name == "get_ItemController")) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Callvirt)) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Ldfld)) continue;
                    if (!(codes[i].operand is FieldInfo fi && fi.Name == "Trader")) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Ldfld)) continue;
                    if (!(codes[i].operand is FieldInfo fi1 && fi1.Name == "TraderEntity")) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Callvirt)) continue;
                    if (!(codes[i].operand is MethodInfo methodInfo2 && methodInfo2.Name == "get_EntityName")) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Ldloc_S)) continue;
                    if (++i >= codes.Count) break;
                    if (!(codes[i].opcode == OpCodes.Callvirt)) continue;
                    if (!(codes[i].operand is MethodInfo methodInfo3 && methodInfo3.Name == "SoldItems")) continue;
                    if (++i >= codes.Count) break;
                    end = i;
                    codes[start].opcode = OpCodes.Nop; //NOP this one because its the target of a branch.
                    codes.RemoveRange(start + 1, (end - start) - 1);
                    codes.Insert(++start, new CodeInstruction(OpCodes.Ldarg_0));
                    codes.Insert(++start, new CodeInstruction(OpCodes.Ldloc, 13));
                    codes.Insert(++start, new CodeInstruction(OpCodes.Callvirt, AccessTools.Method("Patch_ItemActionEntrySell:CountSoldItem")));
                    Log.Out("[IDCSellingFix] Patching done");
                }
    
                return codes;
            }
    
            public static void CountSoldItem(ItemActionEntrySell __instance, int count) {
                if (__instance.ItemController.xui.Trader.TraderEntity != null && __instance.ItemController.xui.Trader.TraderEntity.EntityName != null) { 
                    QuestEventManager.Current.SoldItems(__instance.ItemController.xui.Trader.TraderEntity.EntityName, count);
                } 
            }
        }

    So it isn't a terribly difficult fix. The issue of course with his fix is it means you need a dll included with your mod, with means it is no longer EAC compatible. Not an issue for some, but it is for quite a few. So again, I understand it isn't a vanilla issue, but if someone could give it a look when time permits and see if it can be fixed, that would be great. Thanks. :)

     

    Oh, and since it says a log is required: https://pastebin.com/8E2ivdWe


    User Feedback

    Recommended Comments

    To add to this. The issue stems from the lack of a null check in ItemActionEntrySell.OnActivated.

     

    This line of code specifically.

    QuestEventManager.Current.SoldItems(base.ItemController.xui.Trader.TraderEntity.EntityName, count);


    With vending machines, the field access to TraderEntity will return null with a vending machine. My patch fixes that by simply adding that null check.

    Link to comment
    Share on other sites

    Thank you for reporting. I was able to reproduce this by setting allow_sell to true in traders.xml for a vending machine and trying to sell to the vending machine. I've written up an internal ticket for it.

    Edited by NekoPawtato (see edit history)
    Link to comment
    Share on other sites

    On 9/11/2024 at 9:22 PM, NekoPawtato said:

    Thank you for reporting. I was able to reproduce this by setting allow_sell to true in traders.xml for a vending machine and trying to sell to the vending machine. I've written up an internal ticket for it.

    Good to hear. Thanks for looking into it. :)

    Link to comment
    Share on other sites



    Guest
    Add a comment...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...