Pathfinder: Drop jumper.lua's pathfinder in favor of MarkBu's pathfinder with slight modifications, as the later one supports 3D paths.

Clean up old pathfinder code.
Add path decoration to MarkBu pathfinder's generated paths.
Change actions.lua and places.lua to use the new pathfinder.
Properly modify README.md.
This commit is contained in:
Hector Franqui 2017-06-17 11:47:51 -04:00
parent e1bf931064
commit fb549e7f93
12 changed files with 346 additions and 1548 deletions

View File

@ -4,25 +4,40 @@ advanced_npc
Introduction Introduction
------------ ------------
Advanced NPC is a mod for Minetest, based on mobs_redo. Advanced NPC is a mod for Minetest using mobs_redo API.
The goal of this mod is to be able to have live villages in Minetest. These NPCs are highly inspired by the typical NPCs of Harvest Moon games. The general idea is that on almost all buildings of a village there are NPCs that are kind of intelligent: they have daily tasks they perform, can speak to players, can trade with the player, can use their own items (chests and furnaces for example), know where to go around their house and village, can be lumbers, miners or any other Minetest-suitable profession and can ultimately engage into relationships with the player. And while basically only players are mentioned here, the ultimate goal is that they can do all of this also among themselves, so that villages are alive and evolving by themselves, without player intervention. The goal of this mod is to be able to have live villages in Minetest. These NPCs are highly inspired by the typical NPCs of _Harvest Moon_ games. The general idea is that on almost all buildings of a village there are NPCs that are kind of intelligent: they have daily tasks they perform, can speak to players, can trade with the player, can use their own items (chests and furnaces for example), know where to go around their house and village, can be lumbers, miners or any other Minetest-suitable profession and can ultimately engage into relationships with the player. And while basically only players are mentioned here, the ultimate goal is that they can do all of this also among themselves, so that villages are alive and evolving by themselves, without player intervention.
Installation Installation
------------ ------------
__NOTE__: Advanced NPC is still under development. While the mod is largely stable, it lacks one of the most important pieces: spawning. Currently, NPCs will spawn on stone (default:stone) and the mg_villages' plotmarkers (mg_villages:plotmarker). The spawning is not controlled, so you will have several of them walking around. This is not how it is planned and is just for testing purposes. In the future, only a handful of NPCs should spawn at village house's plotmarker and they will know their way around the house and have specific jobs. __NOTE__: Advanced NPC is still under development. While the mod is largely stable, it lacks one of the most important pieces: spawning. Currently, NPCs can be spawned using eggs (found in creative inventory as 'NPC') and by themselves on villages of the [mg_villages mod](https://forum.minetest.net/viewtopic.php?t=13589). NPCs will spawn automatically on mg_villages villages and over time will populate the entire village. If something goes wrong, you can reset the village by:
- Clearing all objects (in chat, type /clearobjects quick)
- Restore original plotmarkers (in chat, type /restore_plotmarkers radius)
- The radius can be any number, but it is recommended you use a not so large number. 200 is suitable. So stand in the middle of the village and then run that command.
This will actually restore the village and will slowly make NPCs spawn again. Currently there's no way to disable NPCs spawning on village, except by going to `spawner.lua` and commenting out all of `minetest.register_abm()` code.
Download the mod [here](https://github.com/hkzorman/advanced_npc/archive/master.zip) (link always pointing to latest version) __Download__ the mod [here](https://github.com/hkzorman/advanced_npc/archive/master.zip) (link always pointing to latest version)
For this mod to work correctly, you also need to install the [mobs_redo](https://github.com/tenplus1/mobs_redo) mod. After installation, make sure you enable it in your world. For this mod to work correctly, you also need to install the [mobs_redo](https://github.com/tenplus1/mobs_redo) mod. After installation, make sure you enable it in your world.
License License
------- -------
__advanced_npc__ is Copyright (C) 2016-2017 Hector Franqui (zorman2000), licensed under the GPLv3 license. See `license.txt` for details. __advanced_npc__ is Copyright (C) 2016-2017 Hector Franqui (zorman2000), licensed under the GPLv3 license. See `license.txt` for details.
The `jumper.lua` file contains code based on the [Jumper library](https://github.com/Yonaba/Jumper), which is Copyright (c) 2012-2013 Roland Yonaba, licensed under MIT license. See `actions/jumper.lua` for details. The `pathfinder.lua` file contains code slighlty modified from the [pathfinder mod](https://github.com/Yonaba/Jumper) by MarkBu, which is licensed as WTFPL. See `actions/pathfinder.lua` for details.
Current NPC textures are from mobs_redo mod.
The following textures are by Zorman2000:
- marriage_ring.png - CC BY-SA
Documentation and API
---------------------
This mod requires a good user manual, and also is planned to have an extensive API, properly documented. Unfortunately, these still aren't ready. A very very very WIP manual can be found in the [wiki](https://github.com/hkzorman/advanced_npc/wiki/Concept%3A-Dialogues)
Roadmap Roadmap

View File

@ -599,7 +599,7 @@ function npc.actions.use_bed(self, args)
end end
local action = args.action local action = args.action
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
minetest.log(dump(node)) --minetest.log(dump(node))
local dir = minetest.facedir_to_dir(node.param2) local dir = minetest.facedir_to_dir(node.param2)
if action == npc.actions.const.beds.LAY then if action == npc.actions.const.beds.LAY then
@ -746,20 +746,9 @@ function npc.actions.walk_to_pos(self, args)
end end
-- Find path -- Find path
--local path = pathfinder.find_path(start_pos, end_pos, 20, walkable_nodes) local path = npc.pathfinder.find_path(start_pos, end_pos, self, true)
local path = pathfinder.find_path(start_pos, end_pos, self)
if path ~= nil and #path > 1 then if path ~= nil and #path > 1 then
-- Get details from path nodes
-- This might get moved to proper place, pathfinder.lua code
local path_detail = {}
for i = 1, #path do
local node = minetest.get_node(path[i])
table.insert(path_detail, {pos=path[i], type=npc.pathfinder.is_good_node(node, {})})
end
path = path_detail
npc.log("DEBUG", "Detailed path: "..dump(path))
npc.log("INFO", "walk_to_pos Found path to node: "..minetest.pos_to_string(end_pos)) npc.log("INFO", "walk_to_pos Found path to node: "..minetest.pos_to_string(end_pos))
-- Store path -- Store path
self.actions.walking.path = path self.actions.walking.path = path

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,13 @@
-- Pathfinding code by Zorman2000 -- Pathfinding code by MarkBu, original can be found here:
-- https://github.com/MarkuBu/pathfinder
--
-- Modifications by Zorman2000
-- This version is slightly modified to use another "walkable" function,
-- plus add a "decorating" path function which allows to know the type
-- of nodes in the path.
--------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------
-- Pathfinding functionality -- Pathfinding functionality
--------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------
-- This class contains functions that allows to map the 3D map of Minetest into
-- a 2D array (basically by ignoring the y coordinate for the moment being) in order
-- to use the A* pathfinding algorithm to find the shortest path from one node to
-- another. The A* algorithm implementation is in the 'jumper.lua' file which a
-- reduced and slightly modified version of the Jumper library, by Roland Yonaba
-- (https://github.com/Yonaba/Jumper).
-- Mapping algorithm: transforms a Minetest map surface to a 2d grid.
npc.pathfinder = {} npc.pathfinder = {}
@ -30,57 +29,15 @@ npc.pathfinder.nodes = {
} }
} }
-- This function uses the mapping functions and the A* algorithm implementation
-- of the Jumper library to find a path from start_pos to end_pos. The range is
-- an extra amount of nodes to search in both the x and z coordinates.
function npc.pathfinder.find_path(start_pos, end_pos, range, walkable_nodes)
-- Check that start and end position are not the same
if start_pos.x == end_pos.x and start_pos.z == end_pos.z then
return nil
end
-- Set walkable nodes to empty if parameter wasn't used
if walkable_nodes == nil then
walkable_nodes = {}
end
-- Map the Minetest area to a 2D array
local map = pathfinder.create_map(start_pos, end_pos, range, walkable_nodes)
-- Find start and end positions
local pos = pathfinder.find_start_and_end_pos(map)
-- Normalize the map
local normalized_map = pathfinder.normalize_map(map)
-- Create pathfinder object
local grid_object = Grid(normalized_map)
-- Define what is a walkable node
local walkable = 0
-- Pathfinder object using A* algorithm
local finder = Pathfinder(grid_object, "ASTAR", walkable)
-- Set orthogonal mode meaning it will not move in diagonal directions
finder:setMode("ORTHOGONAL")
-- Calculates the path, and its length
local path = finder:getPath(pos.start_pos.x, pos.start_pos.z, pos.end_pos.x, pos.end_pos.z)
--minetest.log("Found path: "..dump(path))
-- Pretty-printing the results
if path then
return pathfinder.get_path(map, path:nodes())
end
end
-- 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 npc.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.
--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
--for _,node_prefix in pairs(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
@ -88,159 +45,346 @@ function npc.pathfinder.is_good_node(node, exceptions)
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 pathfinder.node_types.walkable
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
--return 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
--return pathfinder.node_types.walkable
end end
end end
return npc.pathfinder.node_types.non_walkable return npc.pathfinder.node_types.non_walkable
--return pathfinder.node_types.non_walkable
end end
end end
function pathfinder.create_map(start_pos, end_pos, extra_range, walkables) function pathfinder.get_decorated_path(path)
-- Get details from path nodes
minetest.log("Start pos: "..minetest.pos_to_string(start_pos)) local path_detail = {}
minetest.log("End pos: "..minetest.pos_to_string(end_pos)) for i = 1, #path do
local node = minetest.get_node(path[i])
-- Calculate all signs to ensure: table.insert(path_detail, {pos=path[i], type=pathfinder.is_good_node(node, {})})
-- 1. Correct area calculation
-- 2. Iterate in the correct direction
local start_x_sign = (start_pos.x - end_pos.x) / math.abs(start_pos.x - end_pos.x)
local start_z_sign = (start_pos.z - end_pos.z) / math.abs(start_pos.z - end_pos.z)
local end_x_sign = (end_pos.x - start_pos.x) / math.abs(end_pos.x - start_pos.x)
local end_z_sign = (end_pos.z - start_pos.z) / math.abs(end_pos.z - start_pos.z)
-- Correct the signs if they are nan
if math.abs(start_pos.x - end_pos.x) == 0 then
start_x_sign = -1
end_x_sign = 1
end
if math.abs(start_pos.z - end_pos.z) == 0 then
start_z_sign = -1
end_z_sign = 1
end
-- Get starting and ending positions, adding the extra nodes to the area
local pos1 = {x=start_pos.x + (extra_range * start_x_sign), y = start_pos.y - 1, z=start_pos.z + (extra_range * start_z_sign)}
local pos2 = {x=end_pos.x + (extra_range * end_x_sign), y = end_pos.y, z=end_pos.z + (extra_range * end_z_sign)}
local grid = {}
-- Loop through the area and classify nodes
for z = 1, math.abs(pos1.z - pos2.z) do
local current_row = {}
for x = 1, math.abs(pos1.x - pos2.x) do
-- Calculate current position
local current_pos = {x=pos1.x + (x*end_x_sign), y=pos1.y, z=pos1.z + (z*end_z_sign)}
-- Check if this is the starting position
if current_pos.x == start_pos.x and current_pos.z == start_pos.z then
-- Is start position
table.insert(current_row, {pos=current_pos, type=pathfinder.node_types.start})
elseif current_pos.x == end_pos.x and current_pos.z == end_pos.z then
-- Is ending position or goal position
table.insert(current_row, {pos=current_pos, type=pathfinder.node_types.goal})
else
-- Check if node is walkable
local node = minetest.get_node(current_pos)
-- Check node has air above it
local node_above = minetest.get_node({x=current_pos.x, y=current_pos.y+1, z=current_pos.z})
if node.name == "air" then
-- Check if node above is air
if node.name == "air" then
-- If air do no more checks
table.insert(current_row, {pos=current_pos, type=pathfinder.node_types.walkable})
end
else
-- Check if it is of a walkable or openable type
table.insert(current_row, {pos=current_pos, type=is_good_node(node, walkables)})
end
end
end end
-- Insert the converted row into the grid
table.insert(grid, current_row) npc.log("DEBUG", "Detailed path: "..dump(path_detail))
return path_detail
end
function npc.pathfinder.find_path(start_pos, end_pos, entity, decorate_path)
local path = pathfinder.find_path(start_pos, end_pos, entity)
if path then
if decorate_path then
path = pathfinder.get_decorated_path(path)
end
else
npc.log("ERROR", "Couldn't find path from "..minetest.pos_to_string(start_pos)
.." to "..minetest.pos_to_string(end_pos))
end end
return path
return grid
end end
-- Utility function to print the created map to the console. -- From this point onwards is MarkBu's original pathfinder code,
-- Used for debug. -- except for the "walkable" function, which is modified by Zorman2000
local function print_map(map) -- to include doors and other "walkable" nodes.
for z,row in pairs(map) do -- The version here is exactly this:
local row_string = "[" -- https://github.com/MarkuBu/pathfinder/commit/ca0b433bf5efde5da545b11b2691fa7f7e53dc30
for x,node in pairs(row) do
if node.type == 2 then --[[
row_string = row_string.."- " minetest.get_content_id(name)
else minetest.registered_nodes
row_string = row_string..node.type.." " minetest.get_name_from_content_id(id)
end local ivm = a:index(pos.x, pos.y, pos.z)
-- Use the following if the coordinates are also needed local ivm = a:indexp(pos)
--row_string = row_string..node.type..": {"..node.pos.x..", "..node.pos.y..", "..node.pos.z.."}, " minetest.hash_node_position({x=,y=,z=})
end minetest.get_position_from_hash(hash)
row_string = row_string.."]"
print(row_string) start_index, target_index, current_index
end ^ Hash of position
current_value
^ {int:hCost, int:gCost, int:fCost, hash:parent, vect:pos}
]]--
local openSet = {}
local closedSet = {}
local function get_distance(start_pos, end_pos)
local distX = math.abs(start_pos.x - end_pos.x)
local distZ = math.abs(start_pos.z - end_pos.z)
if distX > distZ then
return 14 * distZ + 10 * (distX - distZ)
else
return 14 * distX + 10 * (distZ - distX)
end
end end
local function get_distance_to_neighbor(start_pos, end_pos)
local distX = math.abs(start_pos.x - end_pos.x)
local distY = math.abs(start_pos.y - end_pos.y)
local distZ = math.abs(start_pos.z - end_pos.z)
-- This function find the starting and ending points in the if distX > distZ then
-- map representation, and returns the coordinates in the map return (14 * distZ + 10 * (distX - distZ)) * (distY + 1)
-- for the pathfinding algorithm to use else
function pathfinder.find_start_and_end_pos(map) return (14 * distX + 10 * (distZ - distX)) * (distY + 1)
-- This is for debug end
--print_map(map) end
local result = {}
for z,row in pairs(map) do -- This function is used to determine if a node is walkable
for x,node in pairs(row) do -- or openable, in which case is good to use when finding a path
if node.type == pathfinder.node_types.start then local function walkable(node, exceptions)
--minetest.log("Start node: "..dump(node)) local exceptions = exceptions or {}
result["start_pos"] = {x=x, z=z} -- Is openable is to support doors, fence gates and other
elseif node.type == pathfinder.node_types.goal then -- doors from other mods. Currently, default doors, gates
--minetest.log("End node: "..dump(node)) -- and cottages doors are supported.
result["end_pos"] = {x=x, z=z} --minetest.log("Is good node: "..dump(node))
end local is_openable = false
for _,node_prefix in pairs(npc.pathfinder.nodes.openable_prefix) do
local start_i,end_i = string.find(node.name, node_prefix)
if start_i ~= nil then
is_openable = true
break
end end
end end
--minetest.log("Found start and end positions: ("..result.start_pos.)..", "..minetest.pos_to_string(result.end_pos)) -- Detect mg_villages ceilings usage of thin wood nodeboxes
return result -- TODO: Improve
end local is_mg_villages_ceiling = false
if node.name == "cottages:wood_flat" then
-- This function transforms the grid into binary values is_mg_villages_ceiling = true
-- (0 walkable, 1 non-walkable) for the pathfinding algorithm. end
function pathfinder.normalize_map(map) if node ~= nil and node.name ~= nil and not minetest.registered_nodes[node.name].walkable then
local result = {} return false
for _,row in pairs(map) do elseif is_openable then
local result_row = {} return false
for _,node in pairs(row) do elseif is_mg_villages_ceiling then
if node.type ~= pathfinder.node_types.non_walkable then return false
table.insert(result_row, 0) else
else for i = 1, #exceptions do
table.insert(result_row, 1) if node.name == exceptions[i] then
return false
end end
end end
table.insert(result, result_row) return true
end end
return result
end end
-- This function returns an array of tables with two parameters: type and pos. local function check_clearance(cpos, x, z, height)
-- The position parameter is the actual coordinate on the Minetest map. The for i = 1, height do
-- type is the type of the node at the coordinate defined as pathfinder.node_types. local n_name = minetest.get_node({x = cpos.x + x, y = cpos.y + i, z = cpos.z + z}).name
function pathfinder.get_path(map, path_nodes) local c_name = minetest.get_node({x = cpos.x, y = cpos.y + i, z = cpos.z}).name
local result = {} --~ print(i, n_name, c_name)
for node, count in path_nodes do if walkable(n_name) or walkable(c_name) then
table.insert(result, map[node:getY()][node:getX()]) return false
-- For debug end
--minetest.log("Node: "..dump(map[node:getY()][node:getX()])) end
--print(('Step: %d - x: %d - y: %d'):format(count, node:getX(), node:getY())) return true
end end
return result
local function get_neighbor_ground_level(pos, jump_height, fall_height)
local node = minetest.get_node(pos)
local height = 0
if walkable(node) then
repeat
height = height + 1
if height > jump_height then
return nil
end
pos.y = pos.y + 1
node = minetest.get_node(pos)
until not walkable(node)
return pos
else
repeat
height = height + 1
if height > fall_height then
return nil
end
pos.y = pos.y - 1
node = minetest.get_node(pos)
until walkable(node)
return {x = pos.x, y = pos.y + 1, z = pos.z}
end
end
function pathfinder.find_path(pos, endpos, entity)
local start_index = minetest.hash_node_position(pos)
local target_index = minetest.hash_node_position(endpos)
local count = 1
openSet = {}
closedSet = {}
local h_start = get_distance(pos, endpos)
openSet[start_index] = {hCost = h_start, gCost = 0, fCost = h_start, parent = nil, pos = pos}
-- Entity values
local entity_height = math.ceil(entity.collisionbox[5] - entity.collisionbox[2])
local entity_fear_height = entity.fear_height or 2
local entity_jump_height = entity.jump_height or 1
repeat
local current_index
local current_values
-- Get one index as reference from openSet
for i, v in pairs(openSet) do
current_index = i
current_values = v
break
end
-- Search for lowest fCost
for i, v in pairs(openSet) do
if v.fCost < openSet[current_index].fCost or v.fCost == current_values.fCost and v.hCost < current_values.hCost then
current_index = i
current_values = v
end
end
openSet[current_index] = nil
closedSet[current_index] = current_values
count = count - 1
if current_index == target_index then
-- print("Success")
local path = {}
local reverse_path = {}
repeat
if not closedSet[current_index] then
return
end
table.insert(path, closedSet[current_index].pos)
current_index = closedSet[current_index].parent
if #path > 100 then
-- print("path to long")
return
end
until start_index == current_index
repeat
table.insert(reverse_path, table.remove(path))
until #path == 0
-- print("path lenght: "..#reverse_path)
return reverse_path
end
local current_pos = current_values.pos
local neighbors = {}
local neighbors_index = 1
for z = -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 = minetest.get_node(neighbor_pos)
local neighbor_ground_level = get_neighbor_ground_level(neighbor_pos, entity_jump_height, entity_fear_height)
local neighbor_clearance = false
if neighbor_ground_level then
-- print(neighbor_ground_level.y - current_pos.y)
--minetest.set_node(neighbor_ground_level, {name = "default:dry_shrub"})
local node_above_head = minetest.get_node(
{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
local height = -1
repeat
height = height + 1
local node = minetest.get_node(
{x = neighbor_ground_level.x,
y = neighbor_ground_level.y + height,
z = neighbor_ground_level.z})
until walkable(node) or height > entity_height
if height >= entity_height then
neighbor_clearance = true
end
elseif neighbor_ground_level.y - current_pos.y > 0 and walkable(node_above_head) then
neighbors[neighbors_index] = {
hash = nil,
pos = nil,
clear = nil,
walkable = nil,
}
else
local height = -1
repeat
height = height + 1
local node = minetest.get_node(
{x = neighbor_ground_level.x,
y = current_pos.y + height,
z = neighbor_ground_level.z})
until walkable(node) or height > entity_height
if height >= entity_height then
neighbor_clearance = true
end
end
neighbors[neighbors_index] = {
hash = minetest.hash_node_position(neighbor_ground_level),
pos = neighbor_ground_level,
clear = neighbor_clearance,
walkable = walkable(neighbor),
}
else
neighbors[neighbors_index] = {
hash = nil,
pos = nil,
clear = nil,
walkable = nil,
}
end
neighbors_index = neighbors_index + 1
end
end
for id, neighbor in pairs(neighbors) do
-- don't cut corners
local cut_corner = false
if id == 1 then
if not neighbors[id + 1].clear or not neighbors[id + 3].clear
or neighbors[id + 1].walkable or neighbors[id + 3].walkable then
cut_corner = true
end
elseif id == 3 then
if not neighbors[id - 1].clear or not neighbors[id + 3].clear
or neighbors[id - 1].walkable or neighbors[id + 3].walkable then
cut_corner = true
end
elseif id == 7 then
if not neighbors[id + 1].clear or not neighbors[id - 3].clear
or neighbors[id + 1].walkable or neighbors[id - 3].walkable then
cut_corner = true
end
elseif id == 9 then
if not neighbors[id - 1].clear or not neighbors[id - 3].clear
or neighbors[id - 1].walkable or neighbors[id - 3].walkable then
cut_corner = true
end
end
if neighbor.hash ~= current_index and not closedSet[neighbor.hash] and neighbor.clear and not cut_corner then
local move_cost_to_neighbor = current_values.gCost + get_distance_to_neighbor(current_values.pos, neighbor.pos)
local gCost = 0
if openSet[neighbor.hash] then
gCost = openSet[neighbor.hash].gCost
end
if move_cost_to_neighbor < gCost or not openSet[neighbor.hash] then
if not openSet[neighbor.hash] then
count = count + 1
end
local hCost = get_distance(neighbor.pos, endpos)
openSet[neighbor.hash] = {
gCost = move_cost_to_neighbor,
hCost = hCost,
fCost = move_cost_to_neighbor + hCost,
parent = current_index,
pos = neighbor.pos
}
end
end
end
if count > 100 then
-- print("fail")
return
end
until count < 1
-- print("count < 1")
return {pos}
end end

View File

@ -196,7 +196,7 @@ function npc.places.find_entrance_from_openable_nodes(all_openable_nodes, marker
entity.collisionbox = {-0.20,-1.0,-0.20, 0.20,0.8,0.20} entity.collisionbox = {-0.20,-1.0,-0.20, 0.20,0.8,0.20}
--minetest.log("Start pos: "..minetest.pos_to_string(start_pos)) --minetest.log("Start pos: "..minetest.pos_to_string(start_pos))
--minetest.log("End pos: "..minetest.pos_to_string(end_pos)) --minetest.log("End pos: "..minetest.pos_to_string(end_pos))
local path = pathfinder.find_path(start_pos, end_pos, entity) local path = npc.pathfinder.find_path(start_pos, end_pos, entity, false)
--minetest.log("Found path: "..dump(path)) --minetest.log("Found path: "..dump(path))
if path ~= nil then if path ~= nil then
--minetest.log("Path distance: "..dump(#path)) --minetest.log("Path distance: "..dump(#path))

View File

@ -32,7 +32,6 @@ dofile(path .. "/trade/prices.lua")
dofile(path .. "/actions/actions.lua") dofile(path .. "/actions/actions.lua")
dofile(path .. "/actions/places.lua") dofile(path .. "/actions/places.lua")
dofile(path .. "/actions/pathfinder.lua") dofile(path .. "/actions/pathfinder.lua")
dofile(path .. "/actions/jumper.lua")
dofile(path .. "/actions/node_registry.lua") dofile(path .. "/actions/node_registry.lua")
dofile(path .. "/random_data.lua") dofile(path .. "/random_data.lua")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B