230 lines
8.6 KiB
Lua
230 lines
8.6 KiB
Lua
--------------------------------------------------------
|
|
-- Minetest :: Advanced Rangefinder Mod v1.0 (finder)
|
|
--
|
|
-- See README.txt for licensing and other information.
|
|
-- Copyright (c) 2020, Leslie E. Krause
|
|
--
|
|
-- ./games/minetest_game/mods/finder/init.lua
|
|
--------------------------------------------------------
|
|
|
|
dofile( minetest.get_modpath( "finder" ) .. "/api.lua" )
|
|
|
|
local function locator( pos, size, color )
|
|
minetest.add_particle( {
|
|
pos = pos,
|
|
vel = { x=0, y=0, z=0 },
|
|
acc = { x=0, y=0, z=0 },
|
|
exptime = 3.0,
|
|
size = size,
|
|
collisiondetection = false,
|
|
vertical = true,
|
|
texture = "wool_" .. color .. ".png",
|
|
} )
|
|
end
|
|
|
|
local function open_exporter( player_name, results )
|
|
local output = ""
|
|
|
|
for i, v in ipairs( results ) do
|
|
output = output .. string.format( "%s %s at (%0.1f,%0.1f,%0.1f)\n",
|
|
( { player = "Player", entity = "Entity" } )[ v.type ] or "Node", v.name, v.pos.x, v.pos.y, v.pos.z )
|
|
end
|
|
|
|
local function get_formspec( )
|
|
local formspec = "size[6.5,8.5]"
|
|
.. "textarea[0.5,0.5;6.0,8.0;buffer;Search results;" ..
|
|
minetest.formspec_escape( output ) .. "]"
|
|
.. "button_exit[2.0,8.0;2.0,0.3;close;Close]"
|
|
return formspec
|
|
end
|
|
|
|
minetest.create_form( nil, player_name, get_formspec( ) )
|
|
end
|
|
|
|
local function show_results_viewer( player_name, source, region, radius, results )
|
|
local page_idx = 1
|
|
local page_size = 25
|
|
|
|
local function get_formspec( )
|
|
local formspec = string.format( "size[6.0,%0.1f]", 1.5 + math.min( #results, page_size ) * 0.4 )
|
|
.. "position[0.8,0.5]"
|
|
.. string.format( "label[0.0,0.0;Found %d %s within %s of radius %d:]", #results, source, region, radius )
|
|
|
|
local off = 0.0
|
|
for idx = ( page_idx - 1 ) * page_size + 1, math.min( page_idx * page_size, #results ) do
|
|
local data = results[ idx ]
|
|
|
|
if data.type == "player" then
|
|
formspec = formspec
|
|
.. string.format( "box[0.0,%0.1f;0.4,0.3;#FFFF00]", 0.6 + off )
|
|
.. string.format( "image_button[0.0,%0.1f;0.6,0.4;;show:%s;;false;false]", 0.6 + off, idx )
|
|
.. string.format( "label[0.5,%0.2f;Player '%s' at %d meters.]", 0.5 + off, data.name, data.dist )
|
|
locator( data.obj:getpos( ), 8.0, "yellow" )
|
|
elseif data.type == "entity" then
|
|
formspec = formspec
|
|
.. string.format( "box[0.0,%0.1f;0.4,0.3;#00FF00]", 0.6 + off )
|
|
.. string.format( "image_button[0.0,%0.1f;0.6,0.4;;show:%s;;false;false]", 0.6 + off, idx )
|
|
.. string.format( "label[0.5,%0.2f;Entity '%s' at %d meters.]", 0.5 + off, data.name, data.dist )
|
|
locator( data.obj:getpos( ), 8.0, "green" )
|
|
else
|
|
formspec = formspec
|
|
.. string.format( "box[0.0,%0.1f;0.4,0.3;#00FFFF]", 0.6 + off )
|
|
.. string.format( "image_button[0.0,%0.1f;0.6,0.4;;show:%s;;false;false]", 0.6 + off, idx )
|
|
.. string.format( "label[0.5,%0.2f;Node '%s' at %d meters.]", 0.5 + off, data.name, data.dist )
|
|
locator( vector.offset( data.pos, 0.0, 0.55, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.0, -0.55, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.55, 0.0, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, -0.55, 0.0, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.5, 0.0, 0.55 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.5, 0.0, -0.55 ), 2.5, "cyan" )
|
|
end
|
|
|
|
off = off + 0.4
|
|
end
|
|
|
|
formspec = formspec
|
|
.. string.format( "button[0.0,%0.1f;2,0.3;export;Export]", off + 1.0 )
|
|
.. string.format( "button[2.0,%0.1f;1,0.3;prev;<<]", off + 1.0 )
|
|
.. string.format( "label[3.0,%0.1f;%d of %d]", off + 1.0, page_idx, math.max( math.ceil( #results / page_size ) ) )
|
|
.. string.format( "button[4.0,%0.1f;1,0.3;next;>>]", off + 1.0 )
|
|
|
|
return formspec
|
|
end
|
|
|
|
local function on_close( meta, player, fields )
|
|
if fields.quit then return end
|
|
|
|
if fields.export then
|
|
open_exporter( player_name, results )
|
|
|
|
elseif fields.prev then
|
|
if page_idx > 1 then
|
|
page_idx = page_idx - 1
|
|
minetest.update_form( player_name, get_formspec( ) )
|
|
end
|
|
|
|
elseif fields.next then
|
|
if page_idx < #results / page_size then
|
|
page_idx = page_idx + 1
|
|
minetest.update_form( player_name, get_formspec( ) )
|
|
end
|
|
|
|
else
|
|
local fname = next( fields, nil ) -- use next since we only care about the name of a single button
|
|
local fval = string.match( fname, "show:(.+)" )
|
|
|
|
if fval then
|
|
local data = results[ tonumber( fval ) ]
|
|
if data.type == "player" then
|
|
locator( data.obj:getpos( ), 8.0, "yellow" )
|
|
elseif data.type == "entity" then
|
|
locator( data.obj:getpos( ), 8.0, "green" )
|
|
else
|
|
locator( vector.offset( data.pos, 0.0, 0.55, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.0, -0.55, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.55, 0.0, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, -0.55, 0.0, 0.0 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.5, 0.0, 0.55 ), 2.5, "cyan" )
|
|
locator( vector.offset( data.pos, 0.5, 0.0, -0.55 ), 2.5, "cyan" )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.create_form( nil, player_name, get_formspec( ), on_close )
|
|
end
|
|
|
|
minetest.register_chatcommand( "finder", {
|
|
description = "Find various nodes or objects inside a sphere or cuboid region.",
|
|
privs = { server = true },
|
|
func = function( player_name, param )
|
|
local player = minetest.get_player_by_name( player_name )
|
|
local args = string.split( param, " " )
|
|
|
|
if not minetest.create_form then
|
|
return false, "This function requires the ActiveFormspecs Mod be installed."
|
|
end
|
|
|
|
if #args == 0 then
|
|
return false, "Invalid parameters supplied!"
|
|
|
|
elseif args[ 1 ] == "objects" then
|
|
local region, radius, player_names, entity_globs, search_logic, has_parent
|
|
local pos = player:getpos( )
|
|
local options = { }
|
|
local results = { }
|
|
|
|
if #args ~= 7 then
|
|
return false, "Usage: /finder objects [region] [radius] [player_names] [entity_globs] [search_logic] [has_parent]"
|
|
end
|
|
|
|
region = ( { sphere = "sphere" } )[ args[ 2 ] ]
|
|
if region == nil then return false, "Invalid 'region' parameter specified!" end
|
|
|
|
radius = tonumber( args[ 3 ] )
|
|
if radius == nil then return false, "Invalid 'radius' parameter specified!" end
|
|
|
|
if args[ 4 ] ~= "nil" and string.find( args[ 4 ], "^{.*}$" ) then
|
|
player_names = string.split( string.sub( args[ 4 ], 2, -2 ) )
|
|
if player_names == nil then return false, "Invalid 'player_names' parameter specified!" end
|
|
end
|
|
if args[ 5 ] ~= "nil" and string.find( args[ 5 ], "^{.*}$" ) then
|
|
entity_globs = string.split( string.sub( args[ 5 ], 2, -2 ) )
|
|
if entity_globs == nil then return false, "Invalid 'entity_globs' parameter specified!" end
|
|
end
|
|
if args[ 6 ] ~= "nil" then
|
|
search_logic = ( { any = "any", all = "all" } )[ args[ 6 ] ]
|
|
if search_logic == nil then return false, "Invalid 'search_logic' parameter specified!" end
|
|
end
|
|
if args[ 7 ] ~= "nil" then
|
|
options.has_parent = ( { ["true"] = true, ["false"] = false } )[ args[ 7 ] ]
|
|
if options.has_parent == nil then return false, "Invalid 'has_parent' parameter specified!" end
|
|
end
|
|
|
|
if region == "sphere" then
|
|
results = minetest.find_objects_in_sphere( pos, radius, player_names, entity_globs, search_logic, options )
|
|
elseif region == "cuboid" then
|
|
results = minetest.find_objects_in_cuboid( pos, radius, radius, player_names, entity_globs, search_logic, options )
|
|
end
|
|
|
|
show_results_viewer( player_name, "objects", region, radius, results )
|
|
|
|
elseif args[ 1 ] == "nodes" then
|
|
local region, radius, node_globs, search_logic
|
|
local pos = player:getpos( )
|
|
local results = { }
|
|
|
|
if #args ~= 5 then
|
|
return false, "Usage: /finder nodes [region] [radius] [node_globs] [search_logic]"
|
|
end
|
|
|
|
region = ( { sphere = "sphere", cuboid = "cuboid" } )[ args[ 2 ] ]
|
|
if region == nil then return false, "Invalid 'region' parameter specified!" end
|
|
|
|
radius = tonumber( args[ 3 ] )
|
|
if radius == nil then return false, "Invalid 'radius' parameter specified!" end
|
|
|
|
if args[ 4 ] ~= "nil" and string.find( args[ 4 ], "^{.*}$" ) then
|
|
node_globs = string.split( string.sub( args[ 4 ], 2, -2 ) )
|
|
if node_globs == nil then return false, "Invalid 'node_globs' parameter specified!" end
|
|
end
|
|
if args[ 5 ] ~= "nil" then
|
|
search_logic = ( { any = "any", all = "all" } )[ args[ 5 ] ]
|
|
if search_logic == nil then return false, "Invalid 'search_logic' parameter specified!" end
|
|
end
|
|
|
|
local node_names = minetest.search_registered_nodes( node_globs, search_logic )
|
|
|
|
if region == "sphere" then
|
|
results = minetest.find_nodes_in_sphere( pos, radius, node_names )
|
|
elseif region == "cuboid" then
|
|
results = minetest.find_nodes_in_cuboid( pos, radius, radius, node_names )
|
|
end
|
|
|
|
show_results_viewer( player_name, "nodes", region, radius, results )
|
|
end
|
|
|
|
return true
|
|
end
|
|
} )
|