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