Merge branch 'path_fixes'
This commit is contained in:
commit
c3feffbd16
@ -153,7 +153,7 @@ Instantly set mob acceleration to the given `acceleration` parameter (a vector).
|
||||
|
||||
Finish condition: Finishes instantly.
|
||||
|
||||
### `rp_mobs.microtasks.follow_path(path, walk_speed, jump_strength, set_yaw, can_jump, finish_func)
|
||||
### `rp_mobs.microtasks.follow_path(path, walk_speed, jump_strength, set_yaw, can_jump, finish_func, valid_node_func)
|
||||
|
||||
Make the mob follow along a path, i.e. a sequence of positions by walking.
|
||||
This assumes the mob is bound to gravity along the whole path and the *entire* path is walkable.
|
||||
@ -175,6 +175,10 @@ Parameters:
|
||||
`self` is the microtask reference, `mob` the mob reference.
|
||||
Returns `<stop>, <success>`. If `stop` is `true`, microtask will finish.
|
||||
with the given success (`success` = `true`/`false`; `true` is default).
|
||||
* `valid_node_func`: Optional function that checks if the next node is still “valid” (i.e. can
|
||||
be safely moved towadrds). It's called right before the mob is starting to go towards
|
||||
a new position of the path with arguments `pos, node`.
|
||||
Returns `true` or `false`. If it returns `true`, the microtask will finish and fail.
|
||||
|
||||
Finish condition: There are multiple reasons for finishing:
|
||||
|
||||
@ -203,4 +207,4 @@ Parameters:
|
||||
* `anim_walk`: Mob animation name for horizontal movement (default: `"walk"`)
|
||||
* `anim_climb`: Mob animation name for vertical movement (default: `"idle"`)
|
||||
* `anim_idle`: Mob animation name when idling (default: `"idle"`)
|
||||
|
||||
* `valid_node_func`: See `rp_mobs.microtasks.follow_path`
|
||||
|
@ -12,6 +12,9 @@ local PATH_STUCK_RECHECK_TIME = 1.0
|
||||
-- Minimum distance a mob has to have moved to count as no longer stuck
|
||||
local PATH_UNSTUCK_DISTANCE = 0.1
|
||||
|
||||
-- Check if next node is valid at least every this many seconds
|
||||
local PATH_VALID_CHECK_TIME = 1.0
|
||||
|
||||
-- Precision for random yaw calculation
|
||||
local YAW_PRECISION = 10000
|
||||
-- How long in seconds to wait before jumping again
|
||||
@ -86,7 +89,7 @@ end
|
||||
|
||||
rp_mobs.microtasks = {}
|
||||
|
||||
rp_mobs.microtasks.follow_path_climb = function(path, walk_speed, climb_speed, set_yaw, finish_func, anim_walk, anim_climb, anim_idle)
|
||||
rp_mobs.microtasks.follow_path_climb = function(path, walk_speed, climb_speed, set_yaw, finish_func, anim_walk, anim_climb, anim_idle, valid_node_func)
|
||||
local mtask = {}
|
||||
mtask.label = "follow climb path"
|
||||
mtask.on_start = function(self, mob)
|
||||
@ -145,6 +148,27 @@ rp_mobs.microtasks.follow_path_climb = function(path, walk_speed, climb_speed, s
|
||||
|
||||
-- Get next target position
|
||||
local next_pos = self.statedata.path[1]
|
||||
|
||||
-- Validate target position
|
||||
if next_pos and valid_node_func then
|
||||
self.statedata.valid_timer = self.statedata.valid_timer + dtime
|
||||
if not self.statedata.valid_last_position or (not vector.equals(self.statedata.valid_last_position, next_pos)) or self.statedata.valid_timer >= PATH_VALID_CHECK_TIME then
|
||||
local next_node = minetest.get_node(next_pos)
|
||||
self.statedata.valid_last_position = table.copy(next_pos)
|
||||
self.statedata.valid_last_node = next_node
|
||||
self.statedata.valid_timer = 0
|
||||
if not valid_node_func(next_pos, next_node) then
|
||||
self.statedata.stop = true
|
||||
self.statedata.success = false
|
||||
local vel = mob.object:get_velocity()
|
||||
vel.x = 0
|
||||
vel.z = 0
|
||||
mob.object:set_velocity(vel)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local mob_pos = mob.object:get_pos()
|
||||
mob_pos = vector.add(mob_pos, mob._path_check_point or vector.zero())
|
||||
|
||||
@ -261,7 +285,7 @@ rp_mobs.microtasks.follow_path_climb = function(path, walk_speed, climb_speed, s
|
||||
end
|
||||
|
||||
|
||||
rp_mobs.microtasks.follow_path = function(path, walk_speed, jump_strength, set_yaw, can_jump, finish_func)
|
||||
rp_mobs.microtasks.follow_path = function(path, walk_speed, jump_strength, set_yaw, can_jump, finish_func, valid_node_func)
|
||||
if can_jump == nil then
|
||||
can_jump = true
|
||||
end
|
||||
@ -279,6 +303,10 @@ rp_mobs.microtasks.follow_path = function(path, walk_speed, jump_strength, set_y
|
||||
self.statedata.stuck_last_position = nil
|
||||
self.statedata.stuck_recheck_timer = 0
|
||||
|
||||
self.statedata.valid_timer = 0
|
||||
self.statedata.valid_last_position = nil
|
||||
self.statedata.valid_last_node = nil
|
||||
|
||||
if not path then
|
||||
path = mob._temp_custom_state.follow_path
|
||||
end
|
||||
@ -326,6 +354,27 @@ rp_mobs.microtasks.follow_path = function(path, walk_speed, jump_strength, set_y
|
||||
|
||||
-- Get next target position
|
||||
local next_pos = self.statedata.path[1]
|
||||
|
||||
-- Validate target position
|
||||
if next_pos and valid_node_func then
|
||||
self.statedata.valid_timer = self.statedata.valid_timer + dtime
|
||||
if not self.statedata.valid_last_position or (not vector.equals(self.statedata.valid_last_position, next_pos)) or self.statedata.valid_timer >= PATH_VALID_CHECK_TIME then
|
||||
local next_node = minetest.get_node(next_pos)
|
||||
self.statedata.valid_last_position = table.copy(next_pos)
|
||||
self.statedata.valid_last_node = next_node
|
||||
self.statedata.valid_timer = 0
|
||||
if not valid_node_func(next_pos, next_node) then
|
||||
self.statedata.stop = true
|
||||
self.statedata.success = false
|
||||
local vel = mob.object:get_velocity()
|
||||
vel.x = 0
|
||||
vel.z = 0
|
||||
mob.object:set_velocity(vel)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local mob_pos = mob.object:get_pos()
|
||||
mob_pos = vector.add(mob_pos, mob._path_check_point or vector.zero())
|
||||
|
||||
|
@ -1061,6 +1061,31 @@ local path_to_microtasks = function(path)
|
||||
end
|
||||
end
|
||||
|
||||
-- Validate if the next position in the villager path is still valid.
|
||||
-- Used to halt the villager if the path was sabotaged.
|
||||
local validate_next_path_pos = function(pos, node)
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
if not def then
|
||||
return false
|
||||
end
|
||||
if is_node_blocking_water_ok(node) or is_node_stucking(node) then
|
||||
return false
|
||||
end
|
||||
local apos = vector.offset(pos, 0, 1, 0)
|
||||
local anode = minetest.get_node(apos)
|
||||
if is_node_blocking_water_ok(anode) or is_node_stucking(anode) then
|
||||
return false
|
||||
end
|
||||
|
||||
local fpos = vector.offset(pos, 0, -1, 0)
|
||||
local fnode = minetest.get_node(fpos)
|
||||
local fdef = minetest.registered_nodes[fnode.name]
|
||||
if not is_node_walkable(fnode) and not is_node_swimmable(fnode) and (fdef and not fdef.climbable) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local todo = path_to_todo_list(path)
|
||||
local microtasks = {}
|
||||
if not todo then
|
||||
@ -1070,7 +1095,7 @@ local path_to_microtasks = function(path)
|
||||
local entry = todo[t]
|
||||
local mt
|
||||
if entry.type == "path" then
|
||||
mt = rp_mobs.microtasks.follow_path(entry.path, WALK_SPEED, JUMP_STRENGTH, true)
|
||||
mt = rp_mobs.microtasks.follow_path(entry.path, WALK_SPEED, JUMP_STRENGTH, true, true, nil, validate_next_path_pos)
|
||||
mt.start_animation = "walk"
|
||||
elseif entry.type == "door" then
|
||||
mt = create_microtask_open_door(entry.pos, entry.axis)
|
||||
@ -1079,7 +1104,7 @@ local path_to_microtasks = function(path)
|
||||
mt = create_microtask_open_fence_gate(entry.pos)
|
||||
mt.start_animation = "idle"
|
||||
elseif entry.type == "climb" then
|
||||
mt = rp_mobs.microtasks.follow_path_climb(entry.path, WALK_SPEED, CLIMB_SPEED, true, stop_follow_path_climb)
|
||||
mt = rp_mobs.microtasks.follow_path_climb(entry.path, WALK_SPEED, CLIMB_SPEED, true, stop_follow_path_climb, nil, nil, nil, validate_next_path_pos)
|
||||
elseif entry.type == "idle" then
|
||||
mt = rp_mobs.microtasks.drag(vector.new(STAND_DRAG,0,STAND_DRAG), {"x", "z"}, entry.time)
|
||||
mt.start_animation = "idle"
|
||||
|
Loading…
x
Reference in New Issue
Block a user