xcommands/init.lua

209 lines
7.2 KiB
Lua

--------------------------------------------------------
-- Minetest :: Extended Commands Mod v1.1 (xcommands)
--
-- See README.txt for licensing and other information.
-- Copyright (c) 2017-2019, Leslie Ellen Krause
--
-- ./games/minetest_game/mods/xcommands/init.lua
--------------------------------------------------------
local get_xcommand_ls = function( rank )
local player_list = { }
for i, p in ipairs( registry.player_list ) do
if rank == nil or p.rank == rank then
table.insert( player_list, { name = p.name, rank = p.rank } )
end
end
return player_list
end
local get_xcommand_who = function( name )
local p = registry.get_player( name )
if p then
local rank = ( { "basic", "guard", " staff", " admin", " owner" } )[ p.rank ]
-- local status = p.obj:get_hp( ) == 0 and "dead" or p.obj:get_idletime( ) > 60 and "inactive" or "active"
local status = p.obj:get_hp( ) == 0 and "dead" or "alive"
local joined = os.date( "%M:%S", os.time( ) - p.time ) -- should probably format this correctly
return { rank = rank, status = status, joined = joined }
end
end
local get_xcommand_w = function( name_glob )
-- TODO: support actual pattern matching via glob
local player_list = { }
local ctime = os.time( )
for i, p in ipairs( registry.player_list ) do
if string.find( string.upper( p.name ), string.upper( name_glob ) ) then
table.insert( player_list, { name = p.name, time = ( ctime - p.time ) / 60 } )
end
end
table.sort( player_list, function( a, b ) return a.time < b.time end )
return player_list
end
local get_xcommand_where = function( name1, name2 )
-- TODO: default to position of spawnpoint when name2 is unspecified
local pos1 = minetest.get_player_by_name( name1 ):getpos( )
local player = minetest.get_player_by_name( name2 )
if player then
local pos2 = player:getpos( )
local off = vector.subtract( pos2, pos1 )
local len = vector.length( off )
local dir = math.atan2( -off.x, off.z ) * 180 / math.pi
if len <= 1000 or registry.get_player_rank( name1 ) >= registry.PLAYER_RANK_ADMIN then
return { pos = pos2, off = off.y, dir = dir < 0 and 360 + dir or dir, len = len }
end
end
end
local get_xcommand_near = function( name, dist )
local pos = minetest.get_player_by_name( name ):getpos( )
local player_list = { }
if registry.get_player_rank( name ) < registry.PLAYER_RANK_ADMIN and dist > 1000 then
dist = 1000
end
for i, p in ipairs( registry.player_list ) do
local d = vector.distance( p.obj:getpos( ), pos )
if name ~= p.name and d <= dist then
table.insert( player_list, { name = p.name, dist = d } )
end
end
table.sort( player_list, function( a, b ) return a.dist < b.dist end )
return player_list
end
local get_xcommand_what = function( name )
local itemdef = minetest.registered_items[ name ]
if name ~= "" and itemdef then
local description = itemdef.description
local type = itemdef.type
local texture = itemdef.inventory_image ~= "" and itemdef.inventory_image or itemdef.tiles[ 1 ].name or itemdef.tiles[ 1 ]
return { name = name, type = type, description = description, texture = texture }
end
end
-- we finally moved the stringification to the calling methods below, and just return raw datasets above
minetest.register_chatcommand( "ls", {
description = "Show the list of online players, optionally filtered by rank (staff, admin, or owner)",
func = function( name, param )
if param == "" or param == "guard" or param == "staff" or param == "admin" or param == "owner" then
local player_list = get_xcommand_ls( ( {
guard = registry.PLAYER_RANK_GUARD,
staff = registry.PLAYER_RANK_STAFF,
admin = registry.PLAYER_RANK_ADMIN,
owner = registry.PLAYER_RANK_OWNER
} )[ param ] )
local t = { }
for i, p in ipairs( player_list ) do
table.insert( t, p.name .. ( { "", "", " (staff)", " (admin)", " (owner)" } )[ p.rank ] )
end
return true, string.format( "Player-List: %s\n", table.concat( t, ", " ) )
else
return false, "Invalid rank specified."
end
end,
})
minetest.register_chatcommand( "where", {
description = "Show the location of a specified player",
func = function( name, param )
if string.find( param, "^[_A-Za-z0-9]+$" ) and param ~= name then
local p = get_xcommand_where( name, param )
if not p then
return false, "Player not found."
else
return true, string.format( "Player-Info: pos=%s, dir=%d, off=%0.1fm, len=%0.1fm", minetest.pos_to_string( p.pos, 1 ), p.dir, p.off, p.len )
end
else
return false, "Invalid player specified."
end
end,
})
minetest.register_chatcommand( "near", {
description = "Show a list players within the specified range or 50 meters by default",
func = function( name, param )
if param == "" or string.find( param, "^%d+$" ) and tonumber( param ) > 0 then
local player_list = get_xcommand_near( name, param == "" and 500 or tonumber( param ) )
if #player_list == 0 then
return false, "No matches. Please refine your range."
else
local t = { }
for i, p in ipairs( player_list ) do
table.insert( t, string.format( "%s (%0.1fm)", p.name, p.dist ) )
end
return true, string.format( "Player-Info: %s\n", table.concat( t, ", " ) )
end
else
return false, "Invalid range specified."
end
end,
})
minetest.register_chatcommand( "who", {
description = "Show information about the specified player or yourself by default",
func = function( name, param )
if param == "" or string.find( param, "^[_A-Za-z0-9]+$" ) then
local p = get_xcommand_who( param == "" and name or param )
if p then
return true, string.format( "Player-Info: name=%s, rank=%s, status=%s, joined=%s", param == "" and name or param, p.rank, p.status, p.joined )
else
return false, "Unknown player specified."
end
else
return false, "Invalid player specified."
end
end,
})
minetest.register_chatcommand( "w", {
description = "Show a list of online players with names matching the specified search string.",
func = function( name, param )
-- should probably allow dash too, but need to sanitize for regexp?
if string.find( param, "^[_A-Za-z0-9]+$" ) and string.len( param ) >= 3 then
local player_list = get_xcommand_w( param )
if #player_list == 0 then
return false, "No matches. Please refine your search string."
else
local t = { }
for i, p in ipairs( player_list ) do
table.insert( t, string.format( "%s (%0.1f mins)", p.name, p.time ) )
end
return true, string.format( "Player-Info: %s\n", table.concat( t, ", " ) )
end
else
return false, "Invalid search string specified."
end
end,
})
minetest.register_chatcommand( "what", {
description = "Show information about the specified item or the wielded item by default.",
func = function( name, param )
if string.find( param, "^[_a-z0-9]+:[_a-z0-9]+$" ) or param == "" then
local i = get_xcommand_what(
param ~= "" and param or
minetest.get_player_by_name( name ):get_wielded_item( ):get_name( )
)
print( dump( i ) )
if i then
return true, string.format( "Item-Info: name=%s, type=%s, description=%s, texture=%s", i.name, i.type, i.description, i.texture )
else
return false, "Unknown item specified."
end
else
return false, "Invalid item specified."
end
end,
})