mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +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,
 | 
						|
})
 | 
						|
 | 
						|
 |