Pathfinder: Fix indentation.
Improve path decorator to avoid jumping NPCs (in Minetest 0.5-dev)
This commit is contained in:
parent
70fd62825c
commit
866b25c63c
@ -14,60 +14,61 @@ npc.pathfinder = {}
|
|||||||
local pathfinder = {}
|
local pathfinder = {}
|
||||||
|
|
||||||
npc.pathfinder.node_types = {
|
npc.pathfinder.node_types = {
|
||||||
start = 0,
|
start = 0,
|
||||||
goal = 1,
|
goal = 1,
|
||||||
walkable = 2,
|
walkable = 2,
|
||||||
openable = 3,
|
openable = 3,
|
||||||
non_walkable = 4
|
non_walkable = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
npc.pathfinder.nodes = {
|
npc.pathfinder.nodes = {
|
||||||
openable_prefix = {
|
openable_prefix = {
|
||||||
"doors:",
|
"doors:",
|
||||||
"cottages:gate",
|
"cottages:gate",
|
||||||
"cottages:half_door"
|
"cottages:half_door"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-- This function is used to determine if a node is walkable
|
-- This function is used to determine if a node is walkable
|
||||||
-- or openable, in which case is good to use when finding a path
|
-- or openable, in which case is good to use when finding a path
|
||||||
function pathfinder.is_good_node(node, exceptions)
|
function pathfinder.is_good_node(node, exceptions)
|
||||||
--local function is_good_node(node, exceptions)
|
--local function is_good_node(node, exceptions)
|
||||||
-- Is openable is to support doors, fence gates and other
|
-- Is openable is to support doors, fence gates and other
|
||||||
-- doors from other mods. Currently, default doors, gates
|
-- doors from other mods. Currently, default doors, gates
|
||||||
-- and cottages doors are supported.
|
-- and cottages doors are supported.
|
||||||
local is_openable = false
|
local is_openable = false
|
||||||
for _,node_prefix in pairs(npc.pathfinder.nodes.openable_prefix) do
|
for _,node_prefix in pairs(npc.pathfinder.nodes.openable_prefix) do
|
||||||
local start_i,end_i = string.find(node.name, node_prefix)
|
local start_i,end_i = string.find(node.name, node_prefix)
|
||||||
if start_i ~= nil then
|
if start_i ~= nil then
|
||||||
is_openable = true
|
is_openable = true
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if node ~= nil and node.name ~= nil and not minetest.registered_nodes[node.name].walkable then
|
if node ~= nil and node.name ~= nil and not minetest.registered_nodes[node.name].walkable then
|
||||||
return npc.pathfinder.node_types.walkable
|
return npc.pathfinder.node_types.walkable
|
||||||
elseif is_openable then
|
elseif is_openable then
|
||||||
return npc.pathfinder.node_types.openable
|
return npc.pathfinder.node_types.openable
|
||||||
else
|
else
|
||||||
for i = 1, #exceptions do
|
for i = 1, #exceptions do
|
||||||
if node.name == exceptions[i] then
|
if node.name == exceptions[i] then
|
||||||
return npc.pathfinder.node_types.walkable
|
return npc.pathfinder.node_types.walkable
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return npc.pathfinder.node_types.non_walkable
|
return npc.pathfinder.node_types.non_walkable
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function pathfinder.get_decorated_path(path)
|
function pathfinder.get_decorated_path(path)
|
||||||
-- Get details from path nodes
|
-- Get details from path nodes
|
||||||
local path_detail = {}
|
local path_detail = {}
|
||||||
for i = 1, #path do
|
for i = 1, #path do
|
||||||
local node = minetest.get_node(path[i])
|
local node = minetest.get_node(path[i])
|
||||||
table.insert(path_detail, {pos=path[i], type=pathfinder.is_good_node(node, {})})
|
table.insert(path_detail, {pos={x=path[i].x, y=path[i].y-0.5, z=path[i].z},
|
||||||
end
|
type=pathfinder.is_good_node(node, {})})
|
||||||
|
end
|
||||||
|
|
||||||
npc.log("DEBUG", "Detailed path: "..dump(path_detail))
|
npc.log("DEBUG", "Detailed path: "..dump(path_detail))
|
||||||
return path_detail
|
return path_detail
|
||||||
end
|
end
|
||||||
|
|
||||||
function npc.pathfinder.find_path(start_pos, end_pos, entity, decorate_path)
|
function npc.pathfinder.find_path(start_pos, end_pos, entity, decorate_path)
|
||||||
@ -78,7 +79,7 @@ function npc.pathfinder.find_path(start_pos, end_pos, entity, decorate_path)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
npc.log("ERROR", "Couldn't find path from "..minetest.pos_to_string(start_pos)
|
npc.log("ERROR", "Couldn't find path from "..minetest.pos_to_string(start_pos)
|
||||||
.." to "..minetest.pos_to_string(end_pos))
|
.." to "..minetest.pos_to_string(end_pos))
|
||||||
end
|
end
|
||||||
return path
|
return path
|
||||||
end
|
end
|
||||||
@ -135,42 +136,42 @@ end
|
|||||||
-- or openable, in which case is good to use when finding a path
|
-- or openable, in which case is good to use when finding a path
|
||||||
local function walkable(node, exceptions)
|
local function walkable(node, exceptions)
|
||||||
local exceptions = exceptions or {}
|
local exceptions = exceptions or {}
|
||||||
-- Is openable is to support doors, fence gates and other
|
-- Is openable is to support doors, fence gates and other
|
||||||
-- doors from other mods. Currently, default doors, gates
|
-- doors from other mods. Currently, default doors, gates
|
||||||
-- and cottages doors are supported.
|
-- and cottages doors are supported.
|
||||||
--minetest.log("Is good node: "..dump(node))
|
--minetest.log("Is good node: "..dump(node))
|
||||||
local is_openable = false
|
local is_openable = false
|
||||||
for _,node_prefix in pairs(npc.pathfinder.nodes.openable_prefix) do
|
for _,node_prefix in pairs(npc.pathfinder.nodes.openable_prefix) do
|
||||||
local start_i,end_i = string.find(node.name, node_prefix)
|
local start_i,end_i = string.find(node.name, node_prefix)
|
||||||
if start_i ~= nil then
|
if start_i ~= nil then
|
||||||
is_openable = true
|
is_openable = true
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Detect mg_villages ceilings usage of thin wood nodeboxes
|
-- Detect mg_villages ceilings usage of thin wood nodeboxes
|
||||||
-- TODO: Improve
|
-- TODO: Improve
|
||||||
local is_mg_villages_ceiling = false
|
local is_mg_villages_ceiling = false
|
||||||
if node.name == "cottages:wood_flat" then
|
if node.name == "cottages:wood_flat" then
|
||||||
is_mg_villages_ceiling = true
|
is_mg_villages_ceiling = true
|
||||||
end
|
end
|
||||||
if node ~= nil
|
if node ~= nil
|
||||||
and node.name ~= nil
|
and node.name ~= nil
|
||||||
and node.name ~= "ignore"
|
and node.name ~= "ignore"
|
||||||
and minetest.registered_nodes[node.name]
|
and minetest.registered_nodes[node.name]
|
||||||
and not minetest.registered_nodes[node.name].walkable then
|
and not minetest.registered_nodes[node.name].walkable then
|
||||||
return false
|
return false
|
||||||
elseif is_openable then
|
elseif is_openable then
|
||||||
return false
|
return false
|
||||||
elseif is_mg_villages_ceiling then
|
elseif is_mg_villages_ceiling then
|
||||||
return false
|
return false
|
||||||
else
|
else
|
||||||
for i = 1, #exceptions do
|
for i = 1, #exceptions do
|
||||||
if node.name == exceptions[i] then
|
if node.name == exceptions[i] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function check_clearance(cpos, x, z, height)
|
local function check_clearance(cpos, x, z, height)
|
||||||
@ -277,65 +278,65 @@ function pathfinder.find_path(pos, endpos, entity)
|
|||||||
local neighbors = {}
|
local neighbors = {}
|
||||||
local neighbors_index = 1
|
local neighbors_index = 1
|
||||||
for z = -1, 1 do
|
for z = -1, 1 do
|
||||||
for x = -1, 1 do
|
for x = -1, 1 do
|
||||||
local neighbor_pos = {x = current_pos.x + x, y = current_pos.y, z = current_pos.z + z}
|
local neighbor_pos = {x = current_pos.x + x, y = current_pos.y, z = current_pos.z + z}
|
||||||
local neighbor = minetest.get_node(neighbor_pos)
|
local neighbor = minetest.get_node(neighbor_pos)
|
||||||
local neighbor_ground_level = get_neighbor_ground_level(neighbor_pos, entity_jump_height, entity_fear_height)
|
local neighbor_ground_level = get_neighbor_ground_level(neighbor_pos, entity_jump_height, entity_fear_height)
|
||||||
local neighbor_clearance = false
|
local neighbor_clearance = false
|
||||||
if neighbor_ground_level then
|
if neighbor_ground_level then
|
||||||
-- print(neighbor_ground_level.y - current_pos.y)
|
-- print(neighbor_ground_level.y - current_pos.y)
|
||||||
--minetest.set_node(neighbor_ground_level, {name = "default:dry_shrub"})
|
--minetest.set_node(neighbor_ground_level, {name = "default:dry_shrub"})
|
||||||
local node_above_head = minetest.get_node(
|
local node_above_head = minetest.get_node(
|
||||||
{x = current_pos.x, y = current_pos.y + entity_height, z = current_pos.z})
|
{x = current_pos.x, y = current_pos.y + entity_height, z = current_pos.z})
|
||||||
if neighbor_ground_level.y - current_pos.y > 0 and not walkable(node_above_head) then
|
if neighbor_ground_level.y - current_pos.y > 0 and not walkable(node_above_head) then
|
||||||
local height = -1
|
local height = -1
|
||||||
repeat
|
repeat
|
||||||
height = height + 1
|
height = height + 1
|
||||||
local node = minetest.get_node(
|
local node = minetest.get_node(
|
||||||
{x = neighbor_ground_level.x,
|
{x = neighbor_ground_level.x,
|
||||||
y = neighbor_ground_level.y + height,
|
y = neighbor_ground_level.y + height,
|
||||||
z = neighbor_ground_level.z})
|
z = neighbor_ground_level.z})
|
||||||
until walkable(node) or height > entity_height
|
until walkable(node) or height > entity_height
|
||||||
if height >= entity_height then
|
if height >= entity_height then
|
||||||
neighbor_clearance = true
|
neighbor_clearance = true
|
||||||
end
|
end
|
||||||
elseif neighbor_ground_level.y - current_pos.y > 0 and walkable(node_above_head) then
|
elseif neighbor_ground_level.y - current_pos.y > 0 and walkable(node_above_head) then
|
||||||
neighbors[neighbors_index] = {
|
neighbors[neighbors_index] = {
|
||||||
hash = nil,
|
hash = nil,
|
||||||
pos = nil,
|
pos = nil,
|
||||||
clear = nil,
|
clear = nil,
|
||||||
walkable = nil,
|
walkable = nil,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
local height = -1
|
local height = -1
|
||||||
repeat
|
repeat
|
||||||
height = height + 1
|
height = height + 1
|
||||||
local node = minetest.get_node(
|
local node = minetest.get_node(
|
||||||
{x = neighbor_ground_level.x,
|
{x = neighbor_ground_level.x,
|
||||||
y = current_pos.y + height,
|
y = current_pos.y + height,
|
||||||
z = neighbor_ground_level.z})
|
z = neighbor_ground_level.z})
|
||||||
until walkable(node) or height > entity_height
|
until walkable(node) or height > entity_height
|
||||||
if height >= entity_height then
|
if height >= entity_height then
|
||||||
neighbor_clearance = true
|
neighbor_clearance = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
neighbors[neighbors_index] = {
|
neighbors[neighbors_index] = {
|
||||||
hash = minetest.hash_node_position(neighbor_ground_level),
|
hash = minetest.hash_node_position(neighbor_ground_level),
|
||||||
pos = neighbor_ground_level,
|
pos = neighbor_ground_level,
|
||||||
clear = neighbor_clearance,
|
clear = neighbor_clearance,
|
||||||
walkable = walkable(neighbor),
|
walkable = walkable(neighbor),
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
neighbors[neighbors_index] = {
|
neighbors[neighbors_index] = {
|
||||||
hash = nil,
|
hash = nil,
|
||||||
pos = nil,
|
pos = nil,
|
||||||
clear = nil,
|
clear = nil,
|
||||||
walkable = nil,
|
walkable = nil,
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
neighbors_index = neighbors_index + 1
|
||||||
end
|
end
|
||||||
neighbors_index = neighbors_index + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for id, neighbor in pairs(neighbors) do
|
for id, neighbor in pairs(neighbors) do
|
||||||
@ -343,22 +344,22 @@ function pathfinder.find_path(pos, endpos, entity)
|
|||||||
local cut_corner = false
|
local cut_corner = false
|
||||||
if id == 1 then
|
if id == 1 then
|
||||||
if not neighbors[id + 1].clear or not neighbors[id + 3].clear
|
if not neighbors[id + 1].clear or not neighbors[id + 3].clear
|
||||||
or neighbors[id + 1].walkable or neighbors[id + 3].walkable then
|
or neighbors[id + 1].walkable or neighbors[id + 3].walkable then
|
||||||
cut_corner = true
|
cut_corner = true
|
||||||
end
|
end
|
||||||
elseif id == 3 then
|
elseif id == 3 then
|
||||||
if not neighbors[id - 1].clear or not neighbors[id + 3].clear
|
if not neighbors[id - 1].clear or not neighbors[id + 3].clear
|
||||||
or neighbors[id - 1].walkable or neighbors[id + 3].walkable then
|
or neighbors[id - 1].walkable or neighbors[id + 3].walkable then
|
||||||
cut_corner = true
|
cut_corner = true
|
||||||
end
|
end
|
||||||
elseif id == 7 then
|
elseif id == 7 then
|
||||||
if not neighbors[id + 1].clear or not neighbors[id - 3].clear
|
if not neighbors[id + 1].clear or not neighbors[id - 3].clear
|
||||||
or neighbors[id + 1].walkable or neighbors[id - 3].walkable then
|
or neighbors[id + 1].walkable or neighbors[id - 3].walkable then
|
||||||
cut_corner = true
|
cut_corner = true
|
||||||
end
|
end
|
||||||
elseif id == 9 then
|
elseif id == 9 then
|
||||||
if not neighbors[id - 1].clear or not neighbors[id - 3].clear
|
if not neighbors[id - 1].clear or not neighbors[id - 3].clear
|
||||||
or neighbors[id - 1].walkable or neighbors[id - 3].walkable then
|
or neighbors[id - 1].walkable or neighbors[id - 3].walkable then
|
||||||
cut_corner = true
|
cut_corner = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -375,11 +376,11 @@ function pathfinder.find_path(pos, endpos, entity)
|
|||||||
end
|
end
|
||||||
local hCost = get_distance(neighbor.pos, endpos)
|
local hCost = get_distance(neighbor.pos, endpos)
|
||||||
openSet[neighbor.hash] = {
|
openSet[neighbor.hash] = {
|
||||||
gCost = move_cost_to_neighbor,
|
gCost = move_cost_to_neighbor,
|
||||||
hCost = hCost,
|
hCost = hCost,
|
||||||
fCost = move_cost_to_neighbor + hCost,
|
fCost = move_cost_to_neighbor + hCost,
|
||||||
parent = current_index,
|
parent = current_index,
|
||||||
pos = neighbor.pos
|
pos = neighbor.pos
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user