mirror of
https://github.com/minetest/minetest.git
synced 2024-11-14 03:33:44 +01:00
133 lines
4.1 KiB
Lua
133 lines
4.1 KiB
Lua
|
local S = minetest.get_translator("testpathfinder")
|
||
|
|
||
|
-- Config parameters
|
||
|
|
||
|
-- Maximum direct distance between start and end
|
||
|
local MAX_DIRECT_DISTANCE = 64
|
||
|
-- Maximum search distance
|
||
|
local MAX_SEARCH_DISTANCE = 32
|
||
|
-- Maximum permitted jump height
|
||
|
local MAX_JUMP = 1
|
||
|
-- Maximum permitted drop height
|
||
|
local MAX_DROP = 5
|
||
|
-- If true, mod won't refuse to run pathfinder even at long distances
|
||
|
local IGNORE_MAX_DISTANCE_SAFEGUARD = false
|
||
|
|
||
|
-- End of config parameters
|
||
|
|
||
|
local timer = 0
|
||
|
local algorithms = {
|
||
|
"A*_noprefetch",
|
||
|
"A*",
|
||
|
"Dijkstra",
|
||
|
}
|
||
|
|
||
|
local function find_path_for_player(player, itemstack)
|
||
|
local meta = itemstack:get_meta()
|
||
|
if not meta then
|
||
|
return
|
||
|
end
|
||
|
local x = meta:get_int("pos_x")
|
||
|
local y = meta:get_int("pos_y")
|
||
|
local z = meta:get_int("pos_z")
|
||
|
local algo = meta:get_int("algorithm")
|
||
|
if x and y and z then
|
||
|
local pos2 = {x=x, y=y, z=z}
|
||
|
algo = algorithms[algo+1]
|
||
|
local pos1 = vector.round(player:get_pos())
|
||
|
-- Don't bother calling pathfinder for high distance to avoid freezing
|
||
|
if (not IGNORE_MAX_DISTANCE_SAFEGUARD) and (vector.distance(pos1, pos2) > MAX_DIRECT_DISTANCE) then
|
||
|
minetest.chat_send_player(player:get_player_name(), S("Destination too far away! Set a destination (via placing) within a distance of @1 and try again!", MAX_DIRECT_DISTANCE))
|
||
|
return
|
||
|
end
|
||
|
local str = S("Path from @1 to @2:",
|
||
|
minetest.pos_to_string(pos1),
|
||
|
minetest.pos_to_string(pos2))
|
||
|
|
||
|
minetest.chat_send_player(player:get_player_name(), str)
|
||
|
local time_start = minetest.get_us_time()
|
||
|
local path = minetest.find_path(pos1, pos2, MAX_SEARCH_DISTANCE, MAX_JUMP, MAX_DROP, algo)
|
||
|
local time_end = minetest.get_us_time()
|
||
|
local time_diff = time_end - time_start
|
||
|
str = ""
|
||
|
if not path then
|
||
|
minetest.chat_send_player(player:get_player_name(), S("No path!"))
|
||
|
minetest.chat_send_player(player:get_player_name(), S("Time: @1 ms", time_diff/1000))
|
||
|
return
|
||
|
end
|
||
|
for s=1, #path do
|
||
|
str = str .. minetest.pos_to_string(path[s]) .. "\n"
|
||
|
local t
|
||
|
if s == #path then
|
||
|
t = "testpathfinder_waypoint_end.png"
|
||
|
elseif s == 1 then
|
||
|
t = "testpathfinder_waypoint_start.png"
|
||
|
else
|
||
|
local c = math.floor(((#path-s)/#path)*255)
|
||
|
t = string.format("testpathfinder_waypoint.png^[multiply:#%02x%02x00", 0xFF-c, c)
|
||
|
end
|
||
|
minetest.add_particle({
|
||
|
pos = path[s],
|
||
|
expirationtime = 5 + 0.2 * s,
|
||
|
playername = player:get_player_name(),
|
||
|
glow = minetest.LIGHT_MAX,
|
||
|
texture = t,
|
||
|
size = 3,
|
||
|
})
|
||
|
end
|
||
|
minetest.chat_send_player(player:get_player_name(), str)
|
||
|
minetest.chat_send_player(player:get_player_name(), S("Path length: @1", #path))
|
||
|
minetest.chat_send_player(player:get_player_name(), S("Time: @1 ms", time_diff/1000))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function set_destination(itemstack, user, pointed_thing)
|
||
|
if not (user and user:is_player()) then
|
||
|
return
|
||
|
end
|
||
|
local name = user:get_player_name()
|
||
|
local obj
|
||
|
local meta = itemstack:get_meta()
|
||
|
if pointed_thing.type == "node" then
|
||
|
local pos = pointed_thing.above
|
||
|
meta:set_int("pos_x", pos.x)
|
||
|
meta:set_int("pos_y", pos.y)
|
||
|
meta:set_int("pos_z", pos.z)
|
||
|
minetest.chat_send_player(user:get_player_name(), S("Destination set to @1", minetest.pos_to_string(pos)))
|
||
|
return itemstack
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function find_path_or_set_algorithm(itemstack, user, pointed_thing)
|
||
|
if not (user and user:is_player()) then
|
||
|
return
|
||
|
end
|
||
|
local ctrl = user:get_player_control()
|
||
|
-- No sneak: Find path
|
||
|
if not ctrl.sneak then
|
||
|
find_path_for_player(user, itemstack)
|
||
|
else
|
||
|
-- Sneak: Set algorithm
|
||
|
local meta = itemstack:get_meta()
|
||
|
local algo = meta:get_int("algorithm")
|
||
|
algo = (algo + 1) % #algorithms
|
||
|
meta:set_int("algorithm", algo)
|
||
|
minetest.chat_send_player(user:get_player_name(), S("Algorithm: @1", algorithms[algo+1]))
|
||
|
return itemstack
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Punch: Find path
|
||
|
-- Sneak+punch: Select pathfinding algorithm
|
||
|
-- Place: Select destination node
|
||
|
minetest.register_tool("testpathfinder:testpathfinder", {
|
||
|
description = S("Pathfinder Tester"),
|
||
|
inventory_image = "testpathfinder_testpathfinder.png",
|
||
|
groups = { testtool = 1, disable_repair = 1 },
|
||
|
on_use = find_path_or_set_algorithm,
|
||
|
on_secondary_use = set_destination,
|
||
|
on_place = set_destination,
|
||
|
})
|
||
|
|
||
|
|