Merge branch 'i24-td-players' of whats_his_face/Traitor into master

master
NathanS21 2022-05-13 02:00:12 +00:00 committed by Gogs
commit 7b6af2f58b
1 changed files with 220 additions and 88 deletions

View File

@ -13,6 +13,10 @@ local function _info(msg)
return minetest.colorize('#ffff80', msg) return minetest.colorize('#ffff80', msg)
end end
local function _stdout(msg)
return minetest.colorize('#80ddee', msg)
end
local function _lsitem(item) local function _lsitem(item)
return TAB .. '- ' .. item return TAB .. '- ' .. item
end end
@ -47,63 +51,157 @@ local function list_corpses(ctab)
end end
tdc = { --[[ -------------------- tdc namespace -------------------- ]]--
fix_corpses = function(plr_name, map) tdc = {}
local pmap = map or '*'
local count = 0
for mapid, cplist in pairs(lobby.corpses) do function tdc.fix_corpses(td_user, map)
if pmap == '*' then local pmap = map or '*'
local count = 0
for mapid, cplist in pairs(lobby.corpses) do
if pmap == '*' then
lobby.corpse_removal(mapid)
lobby.corpses[mapid] = {}
count = count + 1
else
if mapid:find(pmap) then
lobby.corpse_removal(mapid) lobby.corpse_removal(mapid)
lobby.corpses[mapid] = {} lobby.corpses[mapid] = {}
count = count + 1 count = count + 1
else minetest.chat_send_player(td_user,
if mapid:find(pmap) then _info('Corpses in ' .. _keyw(mapid) .. ' fixed.'))
lobby.corpse_removal(mapid) break
lobby.corpses[mapid] = {}
count = count + 1
minetest.chat_send_player(plr_name,
_info('Corpses in ' .. _keyw(mapid) .. ' fixed.'))
break
end
end end
end end
if count == 0 then end
minetest.chat_send_player(plr_name, _info('No maps found')) if count == 0 then
elseif pmap == '*' then minetest.chat_send_player(td_user, _info('No maps found'))
minetest.chat_send_player(plr_name, elseif pmap == '*' then
_info('Corpses in ' .. tostring(count) .. ' map(s) fixed.')) minetest.chat_send_player(td_user,
end _info('Corpses in ' .. tostring(count) .. ' map(s) fixed.'))
end, end
end
fix_map = function(plr_name, map) function tdc.fix_map(td_user, map)
local pmap = map or '*' local pmap = map or '*'
local count = 0 local count = 0
for mapid, count in pairs(lobby.map) do for mapid, count in pairs(lobby.map) do
if pmap == '*' then if pmap == '*' then
lobby.map[mapid] = 0
lobby.update_maps(mapid)
count = count + 1
else
if mapid:find(pmap) then
lobby.map[mapid] = 0 lobby.map[mapid] = 0
lobby.update_maps(mapid) lobby.update_maps(mapid)
count = count + 1 count = count + 1
else minetest.chat_send_player(td_user,
if mapid:find(pmap) then _info('Map status of ' .. _keyw(mapid) .. ' fixed.'))
lobby.map[mapid] = 0 break
lobby.update_maps(mapid)
count = count + 1
minetest.chat_send_player(plr_name,
_info('Map status of ' .. _keyw(mapid) .. ' fixed.'))
break
end
end end
end end
if count == 0 then end
minetest.chat_send_player(plr_name, _info('No maps found')) if count == 0 then
elseif pmap == '*' then minetest.chat_send_player(td_user, _info('No maps found'))
minetest.chat_send_player(plr_name, elseif pmap == '*' then
_info('Status data for ' .. tostring(count) .. ' map(s) fixed.')) minetest.chat_send_player(td_user,
_info('Status data for ' .. tostring(count) .. ' map(s) fixed.'))
end
end
-- Return active players whose player name matches `expr`
function tdc.active_players_matching(expr)
local players = {}
for _, player in pairs(minetest.get_connected_players()) do
local pl_name = player:get_player_name()
if pl_name:find(expr) then
table.insert(players, player)
end end
end, end
} return players
end
-- Return active map ids matching `expr`
function tdc.active_mapids_matching(expr)
local mapids = {}
for mapid, count in pairs(lobby.map) do
if mapid:find(expr) and count ~= nil and count > 0 then
mapids[mapid] = true
end
end
-- The lobby itself never gets into lobby.map, so we insert it manually,
-- since we want to treat it just like a map.
local mapid_lobby = 'lobby'
if mapid_lobby:find(expr) then mapids[mapid_lobby] = true end
return mapids
end
-- Return players currently visiting a map whose id is in the list `mapids`
function tdc.players_visiting(mapids)
local players = {}
for pl_name, mapid in pairs(lobby.game) do
local mid = mapid
if mapid:find("_solo$") then
mid = mapid:sub(1, -6)
elseif mapid:find("_ghost$") then
mid = mapid:sub(1, -7)
end
if mapids[mid] then
table.insert(players, minetest.get_player_by_name(pl_name))
end
end
return players
end
-- For each player in the `players` list, create an entry in the `index` table,
-- having `player:get_player_name()` as keyword.
function tdc.index_by_name(players, index)
if players == nil or index == nil then return end
for _, player in ipairs(players) do
local pl_name = player:get_player_name()
index[pl_name] = player
end
end
-- Return a list of currently active players where either the player name
-- or the map id they're currently visiting matches `expr`.
function tdc.list_players_matching(expr)
local players = tdc.active_players_matching(expr)
local mapids = tdc.active_mapids_matching(expr)
local visitors = tdc.players_visiting(mapids)
local matches = {}
-- index all matching players by their name
tdc.index_by_name(players, matches)
tdc.index_by_name(visitors, matches)
return matches
end
-- Return a "footprint" representation of the player privileges `privs`
function tdc.privs_footprint(privs)
local s, t, b, c, w, p, m
if privs.server then s = 's' else s = '-' end
if privs.traitor_dev then t = 't' else t = '-' end
if privs.builder then b = 'b' else b = '-' end
if privs.creative then c = 'c' else c = '-' end
if privs.worldeditor then w = 'w' else w = '-' end
if privs.pro_player then p = 'p' else p = '-' end
if privs.multihome then m = 'm' else m = '-' end
return table.concat({s, t, b, c, w, p, m})
end
-- tdc.actions: enumerates the possible /td commands -- tdc.actions: enumerates the possible /td commands
-- tdc.actions = { cmd_1 = def_1, cmd_2 = def_2, ... } -- tdc.actions = { cmd_1 = def_1, cmd_2 = def_2, ... }
@ -131,20 +229,20 @@ tdc.actions = {
table.insert(msgtab, 'Type "' .. _keyw('/td help <cmd>') .. '" to get help for a specific command.') table.insert(msgtab, 'Type "' .. _keyw('/td help <cmd>') .. '" to get help for a specific command.')
return table.concat(msgtab, '\n') return table.concat(msgtab, '\n')
end, end,
exec = function(plr_name, params) exec = function(td_user, params)
if params then if params then
local par1 = params:match('[%w_]+') local par1 = params:match('[%w_]+')
if par1 and tdc.actions[par1] then if par1 and tdc.actions[par1] then
minetest.chat_send_player(plr_name, tdc.actions[par1].help()) minetest.chat_send_player(td_user, tdc.actions[par1].help())
elseif par1 then elseif par1 then
-- TODO: find par1 as cmd prefix in tdc.actions -- TODO: find par1 as cmd prefix in tdc.actions
local msg = _info('Unknown command "' .. par1 .. '"\n') .. list_actions() local msg = _info('Unknown command "' .. par1 .. '"\n') .. list_actions()
minetest.chat_send_player(plr_name, msg) minetest.chat_send_player(td_user, msg)
else else
minetest.chat_send_player(plr_name, tdc.actions['help'].help()) minetest.chat_send_player(td_user, tdc.actions['help'].help())
end end
else else
minetest.chat_send_player(plr_name, tdc.actions['help'].help()) minetest.chat_send_player(td_user, tdc.actions['help'].help())
end end
end, end,
}, },
@ -160,7 +258,7 @@ tdc.actions = {
} }
return table.concat(msgtab, '\n') return table.concat(msgtab, '\n')
end, end,
exec = function(plr_name, params) exec = function(td_user, params)
local map = params:match('[%w_]+') or '*' local map = params:match('[%w_]+') or '*'
local hdr, msg, ccount, clist local hdr, msg, ccount, clist
if params == '' then if params == '' then
@ -191,7 +289,7 @@ tdc.actions = {
else else
msg = _info('No corpses yet.') msg = _info('No corpses yet.')
end end
minetest.chat_send_player(plr_name, msg) minetest.chat_send_player(td_user, msg)
minetest.log('action', minetest.strip_colors(msg)) minetest.log('action', minetest.strip_colors(msg))
end, end,
}, },
@ -205,7 +303,7 @@ tdc.actions = {
} }
return table.concat(msgtab, '\n') return table.concat(msgtab, '\n')
end, end,
exec = function(plr_name, params) exec = function(td_user, params)
local msgtab = {_info('Active maps:')} local msgtab = {_info('Active maps:')}
local plr_count = 0 local plr_count = 0
local msg local msg
@ -233,7 +331,7 @@ tdc.actions = {
table.insert(msgtab, _lsitem('lobby: ' .. tostring(clobby) .. ' player(s)')) table.insert(msgtab, _lsitem('lobby: ' .. tostring(clobby) .. ' player(s)'))
end end
msg = table.concat(msgtab, '\n') msg = table.concat(msgtab, '\n')
minetest.chat_send_player(plr_name, msg) minetest.chat_send_player(td_user, msg)
minetest.log('action', minetest.strip_colors(msg)) minetest.log('action', minetest.strip_colors(msg))
end, end,
}, },
@ -247,7 +345,7 @@ tdc.actions = {
} }
return table.concat(msgtab, '\n') return table.concat(msgtab, '\n')
end, end,
exec = function(plr_name, params) exec = function(td_user, params)
local msg = '' local msg = ''
for mapid, traitor in pairs(lobby.traitors) do for mapid, traitor in pairs(lobby.traitors) do
-- table value could be nil if entry is to be GC'd -- table value could be nil if entry is to be GC'd
@ -260,47 +358,81 @@ tdc.actions = {
else else
msg = _info('Active traitors:\n') .. msg msg = _info('Active traitors:\n') .. msg
end end
minetest.chat_send_player(plr_name, msg) minetest.chat_send_player(td_user, msg)
minetest.log('action', minetest.strip_colors(msg)) minetest.log('action', minetest.strip_colors(msg))
end, end,
}, },
-- CMD: /td player <id> -- CMD: /td players <id>
player = { players = {
info = 'Show player attributes', info = 'Show player attributes',
help = function() help = function()
local msgtab = { local msgtab = {
_info('Usage: /td player <id>'), _info('Usage: /td players <expr>'),
'List some player metadata.', 'Show metadata of one or more players.',
'Params:', 'Params:',
TAB .. '<id> player name (substring suffices).', TAB .. '<expr> Part of a player name or map ID used as search expression.',
'\nNote: <id> is restricted to alphanumeric chars and "_", for the sake of security.' TAB .. ' Any matching player name will be included in the result list.',
TAB .. ' If <expr> is part of a map ID, lists all players currently',
TAB .. ' visiting that map.',
'\nNote: <expr> is restricted to alphanumeric chars and "_", for the sake of security.',
'\nThe metadata of matching players is listed in a table with the following columns:',
TAB .. 'Player displays the player\'s login name',
TAB .. 'Map shows the map id the player is currently visiting',
TAB .. 'Privs shows the state of some more widely used traitor privileges, which is',
TAB .. ' a short string where each letter symbolizes a certain privilege',
TAB .. ' (' ..
_stdout('s') .. 'erver, ' ..
_stdout('t') .. 'raitor_dev, ' ..
_stdout('b') .. 'uilder, ' ..
_stdout('c') .. 'reative, ' ..
_stdout('w') .. 'orldeditor, ' ..
_stdout('p') .. 'ro_player, ' ..
_stdout('m') .. 'ultihome)',
TAB .. ' If a player does not have a certain privilege, the privilege\'s letter',
TAB .. ' is replaced by a \'-\' instead.',
TAB .. 'Mode displays the player mode',
TAB .. 'Tone shows the player\'s current tone color',
TAB .. 'Spawn prints the player\'s current spawn position (if any)',
} }
return table.concat(msgtab, '\n') return table.concat(msgtab, '\n')
end, end,
exec = function(plr_name, params) exec = function(td_user, params)
if not params or not params:find("[%w_]+") then if not params or not params:find("[%w_]+") then
minetest.chat_send_player(plr_name, 'Missing argument, type "/td help player" for help.') minetest.chat_send_player(td_user, 'Missing argument, type "/td help players" for help.')
else else
local p1, p2, plid = params:find('([%w_]+)') local p1, p2, expr = params:find('([%w_]+)')
local matches = tdc.list_players_matching(expr)
local count = 0 local count = 0
local mtab = {
_info('Player Map Privs Mode Tone Spawn'),
'--------------------------------------------------------------------------------------',
}
-- sort list by player name
local sorted = {}
for name in pairs(matches) do table.insert(sorted, name) end
table.sort(sorted)
for _, player in pairs(minetest.get_connected_players()) do for _, name in pairs(sorted) do
local pname = player:get_player_name() count = count + 1
local player = matches[name]
local attr = player:get_meta()
local pl_name = _keyw(name)
local padding = 20 - name:len()
local pl_padding = string.rep(' ', padding)
local pl_map = lobby.game[name] or '<nil>'
local pl_privs = tdc.privs_footprint(minetest.get_player_privs(name))
local pl_mode = attr:get_string('mode') or '<nil>'
local pl_tone = attr:get_int('tone')
local pl_spawn = attr:get_string('spawn_pos') or '<nil>'
if pname:find(plid) then table.insert(mtab, string.format('%s%s %-20s %-7s %-7s %5d %-20s',
count = count + 1 pl_name, pl_padding, pl_map, pl_privs, pl_mode, pl_tone, pl_spawn)
local attr = player:get_meta() )
local mtab = {
_info('Attributes of ') .. _keyw(pname) .. ':',
TAB .. 'ghost: ' .. (attr:get_string('ghost') or 'false'),
TAB .. 'spawn: ' .. (attr:get_string('spawn_pos') or '<nil>'),
TAB .. 'voting: ' .. (attr:get_string('voting') or 'false')
}
minetest.chat_send_player(plr_name, table.concat(mtab, '\n'))
end
end end
if count == 0 then if count == 0 then
minetest.chat_send_player(plr_name, _info('No matching player')) minetest.chat_send_player(td_user, _info('No match'))
else
minetest.chat_send_player(td_user, table.concat(mtab, '\n'))
end end
end end
end, end,
@ -326,23 +458,23 @@ tdc.actions = {
} }
return table.concat(msgtab, '\n') return table.concat(msgtab, '\n')
end, end,
exec = function(plr_name, params) exec = function(td_user, params)
local helpcmd = 'type "/td help fix" for help.' local helpcmd = 'type "/td help fix" for help.'
if not params then if not params then
minetest.chat_send_player(plr_name, _info('Missing arguments, ' .. helpcmd)) minetest.chat_send_player(td_user, _info('Missing arguments, ' .. helpcmd))
else else
local p1, p2, fix, map local p1, p2, fix, map
p1, p2, fix, map = params:find('(%w+)%s+([%w_*]+)') p1, p2, fix, map = params:find('(%w+)%s+([%w_*]+)')
if not fix or not map then if not fix or not map then
minetest.chat_send_player(plr_name, _info('Missing arguments, ' .. helpcmd)) minetest.chat_send_player(td_user, _info('Missing arguments, ' .. helpcmd))
else else
if string.find('corpses', fix) then if string.find('corpses', fix) then
tdc.fix_corpses(plr_name, map) tdc.fix_corpses(td_user, map)
elseif string.find('map', fix) then elseif string.find('map', fix) then
tdc.fix_map(plr_name, map) tdc.fix_map(td_user, map)
else else
minetest.chat_send_player(plr_name, _info('Unknown fix action, ' .. helpcmd)) minetest.chat_send_player(td_user, _info('Unknown fix action, ' .. helpcmd))
end end
end end
end end
@ -350,7 +482,7 @@ tdc.actions = {
} }
} }
function tdc.exec(plr_name, params) function tdc.exec(td_user, params)
local cmd = nil local cmd = nil
if params and params ~= '' then if params and params ~= '' then
local par1 = params:match('[%w_]+') local par1 = params:match('[%w_]+')
@ -369,14 +501,14 @@ function tdc.exec(plr_name, params)
end end
end end
if cname then if cname then
minetest.log('action', plr_name .. ' runs "/td ' .. cname .. parN .. '"') minetest.log('action', td_user .. ' runs "/td ' .. cname .. parN .. '"')
cmd.exec(plr_name, parN) cmd.exec(td_user, parN)
else else
minetest.chat_send_player(plr_name, minetest.chat_send_player(td_user,
_info('Unknown command "' .. par1 .. '", type "/td help" for possible commands.')) _info('Unknown command "' .. par1 .. '", type "/td help" for possible commands.'))
end end
else else
minetest.chat_send_player(plr_name, list_actions()) minetest.chat_send_player(td_user, list_actions())
end end
return true return true
end end