Merge pull request 'Villager tries to get closest bed and jobsite. Villager will wait if failed to path recently' (#2898) from feature/villagers_pt4 into master

Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/2898
Reviewed-by: cora <cora@noreply.git.minetest.land>
This commit is contained in:
cora 2022-11-05 00:15:46 +00:00
commit d18f55aa48
2 changed files with 87 additions and 75 deletions

@ -2607,8 +2607,9 @@ local function check_gowp(self,dtime)
-- 0.1 is optimal.
--less frequently = villager will get sent back after passing a point.
--more frequently = villager will fail points they shouldn't they just didn't get there yet
if gowp_etime < 0.1 then return end
gowp_etime = 0
--if gowp_etime < 0.05 then return end
--gowp_etime = 0
local p = self.object:get_pos()
-- no destination
@ -2663,6 +2664,7 @@ local function check_gowp(self,dtime)
self.current_target = nil
self.waypoints = nil
self._target = nil
self._pf_last_failed = os.time()
self.object:set_velocity({x = 0, y = 0, z = 0})
self.object:set_acceleration({x = 0, y = 0, z = 0})
return
@ -3408,6 +3410,7 @@ local function calculate_path_through_door (p, t, target)
if not wp then
mcl_log("No direct path. Path through door")
-- This could improve. There could be multiple doors. Check you can path from door to target first.
local cur_door_pos = minetest.find_node_near(target,16,{"group:door"})
if cur_door_pos then
mcl_log("Found a door near: " .. minetest.pos_to_string(cur_door_pos))
@ -3457,21 +3460,29 @@ local gopath_last = os.time()
function mcl_mobs:gopath(self,target,callback_arrived)
if self.state == PATHFINDING then mcl_log("Already pathfinding, don't set another until done.") return end
if os.time() - gopath_last < 5 then
mcl_log("Not ready to path yet")
if self._pf_last_failed and (os.time() - self._pf_last_failed) < 30 then
mcl_log("We are not ready to path as last fail is less than threshold: " .. (os.time() - self._pf_last_failed))
return
else
mcl_log("We are ready to pathfind, no previous fail or we are past threshold")
end
gopath_last = os.time()
--if os.time() - gopath_last < 5 then
-- mcl_log("Not ready to path yet")
-- return
--end
--gopath_last = os.time()
self.order = nil
--mcl_log("gowp target: " .. minetest.pos_to_string(target))
local p = self.object:get_pos()
local t = vector.offset(target,0,1,0)
local wp = calculate_path_through_door(p, t, target)
if not wp then
mcl_log("Could not calculate path")
self._pf_last_failed = os.time()
-- Cover for a flaw in pathfind where it chooses the wrong door and gets stuck. Take a break, allow others.
end
--output_table(wp)
@ -3484,12 +3495,6 @@ function mcl_mobs:gopath(self,target,callback_arrived)
else
mcl_log("Nil pos")
end
--current_location = table.remove(wp,1)
--if current_location and current_location["pos"] then
-- mcl_log("Removing first co-ord? " .. tostring(current_location["pos"]))
--else
-- mcl_log("Nil pos")
--end
self.current_target = current_location
self.waypoints = wp
self.state = PATHFINDING

@ -578,10 +578,9 @@ function get_activity(tod)
end
tod = ( tod * 24000 ) % 24000
local lunch_start = 12000
local lunch_start = 11000
local lunch_end = 13500
local work_start = 8500
local work_start = 7000
local work_end = 16500
local activity = nil
@ -602,6 +601,31 @@ function get_activity(tod)
end
local function find_closest_unclaimed_block (p, requested_block_types)
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), requested_block_types)
local distance_to_closest_block = nil
local closest_block = nil
for i,n in pairs(nn) do
local m = minetest.get_meta(n)
if m:get_string("villager") == "" then
mcl_log("Block: " .. minetest.pos_to_string(n).. ", owner: ".. m:get_string("villager"))
local distance_to_block = vector.distance(p, n)
mcl_log("Distance to block ".. i .. ": ".. distance_to_block)
if not distance_to_closest_block or distance_to_closest_block > distance_to_block then
mcl_log("This block is closer than the last.")
closest_block = n
distance_to_closest_block = distance_to_block
end
end
end
return closest_block
end
local function check_bed (entity)
local b = entity._bed
if not b then
@ -677,16 +701,15 @@ local function take_bed (entity)
if not entity then return end
local p = entity.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48), vector.offset(p,48,48,48), spawnable_bed)
for _,n in pairs(nn) do
local m=minetest.get_meta(n)
--mcl_log("Bed owner: ".. m:get_string("villager"))
if m:get_string("villager") == "" and not (entity.state == PATHFINDING) then
mcl_log("Can we path to bed: "..minetest.pos_to_string(n) )
local gp = mcl_mobs:gopath(entity,n,function(self)
local closest_block = find_closest_unclaimed_block (p, spawnable_bed)
if closest_block then
local m = minetest.get_meta(closest_block)
mcl_log("Can we path to bed: "..minetest.pos_to_string(closest_block) )
local gp = mcl_mobs:gopath(entity, closest_block,function(self)
if self then
self.order = "sleep"
self.order = SLEEP
mcl_log("Sleepy time" )
else
mcl_log("Can't sleep, no self in the callback" )
@ -695,15 +718,12 @@ local function take_bed (entity)
if gp then
mcl_log("Nice bed. I'll defintely take it as I can path")
m:set_string("villager", entity._id)
entity._bed = n
break
entity._bed = closest_block
else
mcl_log("Awww. I can't find my bed.")
end
else
mcl_log("Currently gowp, or it's taken: ".. m:get_string("villager"))
end
end
end
local function has_golem(pos)
@ -847,43 +867,32 @@ end
local function look_for_job(self, requested_jobsites)
mcl_log("Looking for jobs")
local looking_for_type = jobsites
if requested_jobsites then
--mcl_log("Looking for jobs of my type: " .. tostring(requested_jobsites))
looking_for_type = requested_jobsites
else
mcl_log("Looking for any job type")
end
local p = self.object:get_pos()
local nn = minetest.find_nodes_in_area(vector.offset(p,-48,-48,-48),vector.offset(p,48,48,48), looking_for_type)
--Ideally should check for closest available. It'll make pathing easier.
for _,n in pairs(nn) do
local m = minetest.get_meta(n)
--mcl_log("Job owner: ".. m:get_string("villager"))
local closest_block = find_closest_unclaimed_block(p, requested_jobsites)
if m:get_string("villager") == "" then
mcl_log("It's a free job for me (".. minetest.pos_to_string(p) .. ")! I might be interested: "..minetest.pos_to_string(n) )
if closest_block then
mcl_log("It's a free job for me (" .. minetest.pos_to_string(p) .. ")! I might be interested: ".. minetest.pos_to_string(closest_block) )
local gp = mcl_mobs:gopath(self,n,function(self)
local gp = mcl_mobs:gopath(self, closest_block,function(self)
mcl_log("Arrived at block callback")
if self and self.state == "stand" then
self.order = WORK
else
mcl_log("no self. passing param to callback failed")
end
end)
if gp then
if n then
mcl_log("We can path to this block.. " .. tostring(n))
if closest_block then
mcl_log("We can path to this block.. " .. tostring(closest_block))
end
return n
return closest_block
else
mcl_log("We could not path to block or it's not ready to path yet.")
end
end
else
mcl_log("We don't have a job block to path to")
end
return nil
@ -1052,7 +1061,7 @@ end
local function do_activity (self)
-- Maybe just check we're pathfinding first?
if not self._bed then
if not self._bed and self.state ~= PATHFINDING then
--mcl_log("Villager has no bed. Currently at location: "..minetest.pos_to_string(self.object:get_pos()))
take_bed (self)
end
@ -1063,7 +1072,6 @@ local function do_activity (self)
wandered_too_far = ( self.state ~= PATHFINDING ) and (vector.distance(self.object:get_pos(),self._bed) > 50 )
end
if wandered_too_far then
--mcl_log("Wandered too far! Return home ")
go_home(self, false)
@ -1074,7 +1082,6 @@ local function do_activity (self)
elseif get_activity() == GATHERING then
go_to_town_bell(self)
else
-- gossip at town bell or stroll around
mcl_log("No order, so remove it.")
self.order = nil
end
@ -1769,12 +1776,12 @@ mcl_mobs:register_mob("mobs_mc:villager", {
self._trading_players[name] = true
if self._trades == nil or self._trades == false then
minetest.log("Trades is nil so init")
--minetest.log("Trades is nil so init")
init_trades(self)
end
update_max_tradenum(self)
if self._trades == false then
minetest.log("Trades is false. no right click op")
--minetest.log("Trades is false. no right click op")
-- Villager has no trades, rightclick is a no-op
return
end