Undeplyoing items without player ID

I need a little help. Hearthlings can move items which have no player ID assigned but cannot undeploy them, probably because they need to know that so they can choose an inventory correctly (like if they couldn’t take their own player ID instead). I cannot find out which part of the code is responsible for that.

@ayazar and @morgan10e were looking at player ID shenanigans. They might know.

So I found the function responsible for the very behaviour in inventory.lua:

local function item_should_be_restocked(item, player_id)
   -- ignore invalid items..
   if not item or not item:is_valid() then
      return false
   end

   -- always pick up items that we've looted...
   local task_tracker_component = item:get_component('stonehearth:task_tracker')
   if task_tracker_component and task_tracker_component:is_task_requested(player_id, nil, 'stonehearth:loot_item') then
      return true
   end

   -- ignore items that aren't ours...
   local item_player_id = radiant.entities.get_player_id(item)
   if item_player_id ~= player_id then
      log:spam('(item should be restocked) %s has player id does not match ours.  returning false.', tostring(item))
      return false
   end

   -- if an item is in storage, we only want to restock it if it does not pass
   -- the filter of that storage
   local inventory = stonehearth.inventory:get_inventory(item_player_id)
   if not inventory then
      log:spam('(item should be restocked) %s could not find an inventory.  returning false.', item)
      return false
   end
   local storage = inventory:container_for(item)
   if storage then
      local sc = storage:get_component('stonehearth:storage')
      if sc then
         if sc:get_type() == 'backpack' then
            log:spam('(item should be restocked) %s is in a backpack.  returning false.', item)
            return false
         end
         local items_in_filter = sc:get_passed_items()
         if items_in_filter[item:get_id()] ~= nil then
            log:spam('(item should be restocked) %s is fine in its current storage.  returning false.', item)
            return false
         end
      end
   end

   --log:spam('(item should be restocked) item %s should be restocked. returning true.', item)
   return true
end

Now the real problem arises. As of now we have Player 1 and the Goblins. Commenting out this part of the code is not an option because Goblin workers would attempt to restock every resource obtained by Player 1 and vice versa. This means restocking should not cover objects with different Player ID than ours. The question is: what to do with objects without player ID?

There are many ways to treat objects without player ID. The problem is gone when an objects is moved first and then undeployed. Why? Because when it is placed it is assigned the player’s player ID. The simplest possible trick would be to modify the undeploy command to begin with assigning player’s ID to an object if it has none. I tested it and it works flawlessly:

function modded_server_function:_undeploy_no_player()
   local PlaceItemCallHandler = radiant.mods.require('stonehearth.call_handlers.place_item_call_handler')

PlaceItemCallHandler.undeploy_item = function(self, session, response, item)
   local efc = item:get_component('stonehearth:entity_forms')
   if efc then
      radiant.entities.set_player_id(item, session.player_id)
      local current_value = efc:get_should_restock()
      efc:set_should_restock(not current_value)
   end

   radiant.events.trigger_async(item, 'stonehearth:item_undeployed')
   return true
end

end