As I was modding various things, autoharvest for renewables being one of them, I found areas where small additions to the code could benefit the possibilities a lot. I decided to list them here.
task_tracker_component.lua: in many cases, especially with more than one player, it would be beneficial to be able to inform components about task cancellations so they can double-check how their situation has changed; this solution has practically no impact on performance as it is just a single event:
function TaskTrackerComponent:cancel_current_task(should_reconsider_ai)
log:debug('Entity %s: cancelling current task \"%s\"', self._entity, tostring(self._sv.task_activity_name))
local can_reconsider = false
if self._sv.task_player_id ~= nil then
can_reconsider = true
end
if self._task_effect then
log:debug('Entity %s: removing effect "%s"', self._entity, self._sv._task_effect_name)
self._task_effect:stop()
self._task_effect = nil
end
if self._position_trace then
self._position_trace:destroy()
self._position_trace = nil
end
-- ADDITION: it is necessary to store event data prior to cancellation
local cancel_info = {entity = self._entity, player_id = self._sv.task_player_id, category = self._sv.task_category, activity_name = self._sv.task_activity_name}
self._sv.task_player_id = nil
self._sv.task_category = nil
self._sv.task_activity_name = nil
self._sv._task_effect_name = nil
self._sv._cancelled_if_entity_moves = false
if can_reconsider and should_reconsider_ai then
stonehearth.ai:reconsider_entity(self._entity, 'task tracker cancelling task')
end
self.__saved_variables:mark_changed()
-- ADDITION: trigger an event so components can notice a task being removed and react properly
radiant.events.trigger(self._entity, 'stonehearth:task_tracker:task_cancelled', cancel_info)
return self
end
place_item_call_handler.lua: this is not an optimal solution, but there is no way to restock objects which have no player ID assigned (e.g. berry bushes) so they cannot be undeployed; assigning player ID during undeploying is a temporary solution as it won’t work properly in mulitplayer:
function PlaceItemCallHandler:undeploy_item(session, response, item)
local efc = item:get_component('stonehearth:entity_forms')
if efc then
-- ADDITION: setting the player ID here allows to undeploy items with no player ID
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
renewable_resource_node_component.lua: here we have two places which can result in buggy behaviour:
- if the node is not harvestable on load starting model variant and description are not updated:
function RenewableResourceNodeComponent:post_activate()
if not self._sv.renew_timer and not self._sv.harvestable then
self:_update_renew_timer()
end
--If we're harvestable on load, fire the harvestable event again,
--in case we need to reinitialize tasks and other nonsavables on the event
if self._sv.harvestable then
radiant.events.trigger(self._entity, 'stonehearth:on_renewable_resource_renewed', {target = self._entity, available_resource = self._resource})
-- ADDITION: in case we are not harvestable on load we should use depleted model and description
else
local render_info = self._entity:add_component('render_info')
render_info:set_model_variant('depleted')
if self._json.unripe_description then
radiant.entities.set_description(self._entity, self._json.unripe_description)
end
end
end
- unlike resource node, renewable resource node does not cancel tasks when harvest is requested:
function RenewableResourceNodeComponent:request_harvest(player_id)
if not self:is_harvestable() then
return false
end
local task_tracker_component = self._entity:add_component('stonehearth:task_tracker')
if task_tracker_component:is_activity_requested(HARVEST_ACTION) then
return false -- If someone has requested to harvest already
end
-- ADDITION: cancel tasks (pasted from resource_node_component.lua)
task_tracker_component:cancel_current_task(false) -- cancel current task first and force the resource node harvest
local json = self._json
local category = json.category or 'harvest'
local success = task_tracker_component:request_task(player_id, category, HARVEST_ACTION, json.harvest_overlay_effect)
return success
end
farming_service.lua: it would be nice if it was possible to specify starting crop availability per biome as well as per kingdom:
function FarmingService:_get_crop_list(session)
local player_id = session.player_id
local crop_list = self._data.player_crops[player_id]
if not crop_list then
-- xxx: look this up from the player info when that is avaiable
local kingdom = stonehearth.population:get_population(player_id):get_kingdom()
-- start out with the default crops for this player's kingdom.
crop_list = {}
local all_crops = self._all_crops
local kingdom_crops = self._initial_crops[kingdom]
-- ADDITION: biome-enabled crops are added to the list of available crops
----[[
local enabled_crops = kingdom_crops
local biome = stonehearth.world_generation:get_biome_alias()
local biome_crops = self._initial_crops[biome]
if biome_crops then
for key, crop in pairs (biome_crops) do
enabled_crops[key] = crop
end
end
--]]
-- gather data when all available crops are listed in enabled_crops
if enabled_crops and all_crops then
for key, crop in pairs(all_crops) do
crop_list[key] = {
crop_key = key,
crop_type = crop.crop_type,
crop_info = self:get_crop_details(crop.crop_type),
crop_level_requirement = crop.level_requirement,
ordinal = crop.ordinal,
initial_crop = enabled_crops[key]
}
end
end
self._data.player_crops[player_id] = crop_list
end
return crop_list
end
I decided to write this because after looking at code changes affecting my mods I noticed the new alpha uses a resource call handler fix for renewable and one-time resource nodes used in BrunoSupremo’s mods so I thought someone may find my observations useful.