209 lines
7.2 KiB
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,
|
|
})
|