Death
Something is returning null in CanMoveItem which is causing the NRE. You'll need to find what variable, object or string is returning a null value. When a value is null it's empty. If you attempt to cast, convert or declare something that is null it will return an NRE if not properly null checked.
In this case, your function is CanMoveItem with the following arguments: Item item, PlayerInventory inventory, uint targetContainer, int targetSlot. One of these 'arguments' are either returning a null value or being cast from a null object.private object CanMoveItem(Item item, PlayerInventory inventory, uint targetContainer, int targetSlot) { }
First off, we need to ensure each argument is checked to make sure it is null. If so, we want to use a return behavior to stop the sequence. If we don't, it'll attempt to return a value where there is none.private object CanMoveItem(Item item, PlayerInventory inventory, uint targetContainer, int targetSlot) { if (item == null) return null; if (inventory == null) return null; if (targetContainer == null) return null; }
If either one of our arguments is null, the sequence will be returned. If your error continues then one of your arguments is being cast as a non-null value to something that becomes null from another argument or object. In this case, we'd want to see which object is causing our NRE. To do this you'd want to print each value to console to see if either of them returns null. In this case, we want to print item, inventory, targetSlot, container, originalContainer to ensure they're not null.
Add the following to the code and ensure you do so AFTER everything is declared:Puts($"Debug: {item} || {inventory} || {targetSlot} || {container} || {originalContainer}");So it looks like this:
private object CanMoveItem(Item item, PlayerInventory inventory, uint targetContainer, int targetSlot) { if (item == null) return null; if (inventory == null) return null; if (targetContainer == null) return null; //other code Puts($"Debug: {item} || {inventory} || {targetSlot} || {container} || {originalContainer}"); }Keep an eye out for the debug that appears right before an NRE, that'll be your culprit.
In this case, originalContainer is returning null which is being cast from item.GetRootContainer. Let's null check originalContainer so if it does return null the sequence will be halted, preventing the NRE.if (originalContainer == null) return null;So at line 336, right under ItemContainer originalContainer = item.GetRootContainer(); (Because we want it to be declared first before we check if it's null) add the following line so your code resembles:
BasePlayer player = inventory.GetComponent<BasePlayer>(); if (player == null) return null; ItemContainer container = inventory.FindContainer(targetContainer); ItemContainer originalContainer = item.GetRootContainer(); if (originalContainer == null) return null;It's as simple as that! I would also invest time into why item is returning null sometimes but for now, the null check for originalContainer will suffice.
PS: I may refer to things inappropriately but you get the idea :P
Where?
private object CanMoveItem(Item item, PlayerInventory inventory, uint targetContainer, int targetSlot)
{
BasePlayer player = inventory.GetComponent<BasePlayer>();
if (player == null)
return null;
ItemContainer container = inventory.FindContainer(targetContainer);
ItemContainer originalContainer = item.GetRootContainer();
Func<object> splitFunc = () =>
{
if (player == null || !HasPermission(player) || !GetEnabled(player))
return null;
PlayerOptions playerOptions = allPlayerOptions[player.userID];
if (container == null || container == item.GetRootContainer())
return null;
BaseOven oven = container.entityOwner as BaseOven;
ItemModCookable cookable = item.info.GetComponent<ItemModCookable>();
if (oven == null || cookable == null)
return null;
int totalSlots = 2 + (oven.allowByproductCreation ? 1 : 0);
if (playerOptions.TotalStacks.ContainsKey(oven.ShortPrefabName))
{
totalSlots = playerOptions.TotalStacks[oven.ShortPrefabName];
}
if (cookable.lowTemp > oven.cookingTemperature || cookable.highTemp < oven.cookingTemperature)
return null;
MoveSplitItem(item, oven, totalSlots);
return true;
};