Merge branch 'i4-add-debug-support' of whats_his_face/Traitor into master
commit
dec9610e34
|
@ -35,6 +35,12 @@ dofile(minetest.get_modpath('lobby')..'/functions.lua')
|
|||
dofile(minetest.get_modpath('lobby')..'/player_callbacks.lua')
|
||||
dofile(minetest.get_modpath('lobby')..'/shop.lua')
|
||||
dofile(minetest.get_modpath('lobby')..'/tool.lua')
|
||||
dofile(minetest.get_modpath('lobby')..'/tdc.lua')
|
||||
|
||||
minetest.register_privilege("traitor_dev", {
|
||||
description = "Can use /td.",
|
||||
give_to_singleplayer = false,
|
||||
give_to_admin = true})
|
||||
|
||||
minetest.register_privilege("pro_player", {
|
||||
description = "Completed the tutorial.",
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
-- tdc.lua: Traitor debugging utility
|
||||
--
|
||||
-- Implements the "/td" chat command.
|
||||
-- Type "/td help" for info on how to use it.
|
||||
|
||||
local TAB = ' '
|
||||
|
||||
local function _keyw(msg)
|
||||
return minetest.colorize('#a0a0ff', msg)
|
||||
end
|
||||
|
||||
local function _info(msg)
|
||||
return minetest.colorize('#ffff80', msg)
|
||||
end
|
||||
|
||||
local function _lsitem(item)
|
||||
return TAB .. '- ' .. item
|
||||
end
|
||||
|
||||
function list_actions()
|
||||
local hdr = 'Available commands: '
|
||||
local msgtab = {}
|
||||
for cmd in pairs(tdc.actions) do
|
||||
table.insert(msgtab, _keyw(cmd))
|
||||
end
|
||||
return hdr .. table.concat(msgtab, '|')
|
||||
end
|
||||
|
||||
-- return corpse count / info messages for a list <ctab> of node positions
|
||||
local function list_corpses(ctab)
|
||||
local node, meta
|
||||
local count = 0
|
||||
local corpses = {}
|
||||
for _, pos in ipairs(ctab) do
|
||||
node = minetest.get_node(pos)
|
||||
meta = minetest.get_meta(pos)
|
||||
if node and node.name and node.name ~= 'air' then
|
||||
local cinfo = meta:get_string('infotext')
|
||||
local cname = cinfo:match("[^']+") or node.name
|
||||
table.insert(corpses, _lsitem(cname .. ' ' .. minetest.pos_to_string(pos)))
|
||||
else
|
||||
table.insert(corpses, _lsitem('<nil> ' .. minetest.pos_to_string(pos)))
|
||||
end
|
||||
count = count + 1
|
||||
end
|
||||
return count, corpses
|
||||
end
|
||||
|
||||
|
||||
tdc = {
|
||||
fix_corpses = function(plr_name, map)
|
||||
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.corpses[mapid] = {}
|
||||
count = count + 1
|
||||
minetest.chat_send_player(plr_name,
|
||||
_info('Corpses in ' .. _keyw(mapid) .. ' fixed.'))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if count == 0 then
|
||||
minetest.chat_send_player(plr_name, _info('No maps found'))
|
||||
elseif pmap == '*' then
|
||||
minetest.chat_send_player(plr_name,
|
||||
_info('Corpses in ' .. tostring(count) .. ' map(s) fixed.'))
|
||||
end
|
||||
end,
|
||||
|
||||
fix_map = function(plr_name, map)
|
||||
local pmap = map or '*'
|
||||
local count = 0
|
||||
|
||||
for mapid, count in pairs(lobby.map) do
|
||||
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.update_maps(mapid)
|
||||
count = count + 1
|
||||
minetest.chat_send_player(plr_name,
|
||||
_info('Map status of ' .. _keyw(mapid) .. ' fixed.'))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if count == 0 then
|
||||
minetest.chat_send_player(plr_name, _info('No maps found'))
|
||||
elseif pmap == '*' then
|
||||
minetest.chat_send_player(plr_name,
|
||||
_info('Status data for ' .. tostring(count) .. ' map(s) fixed.'))
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
-- tdc.actions: enumerates the possible /td commands
|
||||
-- tdc.actions = { cmd_1 = def_1, cmd_2 = def_2, ... }
|
||||
--
|
||||
-- command definitions are maps:
|
||||
-- def_n = {
|
||||
-- info = (string, short description for "/td help")
|
||||
-- help = (0-arg function, returns a longer description for "/td help <action>")
|
||||
-- exec = (2-arg function, executes the action for player named <arg1> with the rest
|
||||
-- of the cmdline string passed in as <arg2>)
|
||||
-- }
|
||||
tdc.actions = {
|
||||
-- CMD: /td help
|
||||
help = {
|
||||
info = 'Show general help and list available commands',
|
||||
help = function()
|
||||
local msgtab = {
|
||||
'Traitor debugging utility. Type "' .. _keyw('/td <cmd>') .. '" to execute a command.',
|
||||
'Available commands:'
|
||||
}
|
||||
for cmd, action in pairs(tdc.actions) do
|
||||
table.insert(msgtab, string.format(TAB .. '%-10s\t%s', cmd, action.info))
|
||||
end
|
||||
table.insert(msgtab, '\nCommands can be abbreviated (e.g., "/td h" shows this help).')
|
||||
table.insert(msgtab, 'Type "' .. _keyw('/td help <cmd>') .. '" to get help for a specific command.')
|
||||
return table.concat(msgtab, '\n')
|
||||
end,
|
||||
exec = function(plr_name, params)
|
||||
if params then
|
||||
local par1 = params:match('[%w_]+')
|
||||
if par1 and tdc.actions[par1] then
|
||||
minetest.chat_send_player(plr_name, tdc.actions[par1].help())
|
||||
elseif par1 then
|
||||
-- TODO: find par1 as cmd prefix in tdc.actions
|
||||
local msg = _info('Unknown command "' .. par1 .. '"\n') .. list_actions()
|
||||
minetest.chat_send_player(plr_name, msg)
|
||||
else
|
||||
minetest.chat_send_player(plr_name, tdc.actions['help'].help())
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(plr_name, tdc.actions['help'].help())
|
||||
end
|
||||
end,
|
||||
},
|
||||
-- CMD: /td corpses
|
||||
corpses = {
|
||||
info = 'Show info on corpses',
|
||||
help = function()
|
||||
local msgtab = {
|
||||
_info('Usage: /td corpses [<map>]'),
|
||||
'Show corpses in map <map>. If <map> is omitted, list all corpses.',
|
||||
'Params:',
|
||||
TAB .. '<map> map id to search, or "*" to list all corpses'
|
||||
}
|
||||
return table.concat(msgtab, '\n')
|
||||
end,
|
||||
exec = function(plr_name, params)
|
||||
local map = params:match('[%w_]+') or '*'
|
||||
local hdr, msg, ccount, clist
|
||||
if params == '' then
|
||||
-- list all corpses instead
|
||||
hdr = _info('List of corpses:\n')
|
||||
for mid, ctab in pairs(lobby.corpses) do
|
||||
local corpses
|
||||
if ctab then ccount = list_corpses(ctab) end
|
||||
if ccount > 0 then
|
||||
msg = (msg or '') .. _lsitem(mid .. ': ' .. tostring(ccount)) .. '\n'
|
||||
end
|
||||
end
|
||||
else
|
||||
for mid, ctab in pairs(lobby.corpses) do
|
||||
if ctab and (mid:find(map) or map == '*') then
|
||||
hdr = _info('Corpses in ') .. _keyw(mid) .. ':\n'
|
||||
ccount, clist = list_corpses(ctab)
|
||||
if ccount > 0 then
|
||||
msg = (msg or '') .. hdr .. table.concat(clist, '\n') .. '\n'
|
||||
end
|
||||
hdr = ''
|
||||
if map ~= '*' then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
if msg then
|
||||
msg = hdr .. msg
|
||||
else
|
||||
msg = _info('No corpses yet.')
|
||||
end
|
||||
minetest.chat_send_player(plr_name, msg)
|
||||
minetest.log('action', minetest.strip_colors(msg))
|
||||
end,
|
||||
},
|
||||
-- CMD: /td maps
|
||||
maps = {
|
||||
info = 'Show maps currently visited by players',
|
||||
help = function()
|
||||
local msgtab = {
|
||||
_info('Usage: /td maps'),
|
||||
'Show map names of all currently active game sessions.'
|
||||
}
|
||||
return table.concat(msgtab, '\n')
|
||||
end,
|
||||
exec = function(plr_name, params)
|
||||
local msgtab = {_info('Active maps:')}
|
||||
local plr_count = 0
|
||||
local msg
|
||||
for mapid, plr_count in pairs(lobby.map) do
|
||||
local gh_count = 0
|
||||
local gh_map = mapid .. '_ghost'
|
||||
for _, mid in pairs(lobby.game) do
|
||||
if mid == gh_map then
|
||||
gh_count = gh_count + 1
|
||||
end
|
||||
end
|
||||
if plr_count > 0 or gh_count > 0 then
|
||||
table.insert(msgtab,
|
||||
_lsitem(mapid .. ': ' .. plr_count .. ' player(s)')
|
||||
.. ' / ' .. _keyw(tostring(gh_count) .. ' ghost(s)'))
|
||||
end
|
||||
end
|
||||
local clobby = 0
|
||||
for _, mid in pairs(lobby.game) do
|
||||
if mid == 'lobby' then
|
||||
clobby = clobby + 1
|
||||
end
|
||||
end
|
||||
if clobby > 0 then
|
||||
table.insert(msgtab, _lsitem('lobby: ' .. tostring(clobby) .. ' player(s)'))
|
||||
end
|
||||
msg = table.concat(msgtab, '\n')
|
||||
minetest.chat_send_player(plr_name, msg)
|
||||
minetest.log('action', minetest.strip_colors(msg))
|
||||
end,
|
||||
},
|
||||
-- CMD: /td traitors
|
||||
traitors = {
|
||||
info = 'Show the traitors in each active map',
|
||||
help = function()
|
||||
local msgtab = {
|
||||
_info('Usage: /td traitors'),
|
||||
'Show the names of all traitors in currently active game sessions'
|
||||
}
|
||||
return table.concat(msgtab, '\n')
|
||||
end,
|
||||
exec = function(plr_name, params)
|
||||
local msg = ''
|
||||
for mapid, traitor in pairs(lobby.traitors) do
|
||||
-- table value could be nil if entry is to be GC'd
|
||||
if traitor then
|
||||
msg = msg .. _lsitem(mapid .. ': ' .. traitor) .. '\n'
|
||||
end
|
||||
end
|
||||
if msg == '' then
|
||||
msg = _info('No active traitors!')
|
||||
else
|
||||
msg = _info('Active traitors:\n') .. msg
|
||||
end
|
||||
minetest.chat_send_player(plr_name, msg)
|
||||
minetest.log('action', minetest.strip_colors(msg))
|
||||
end,
|
||||
},
|
||||
-- CMD: /td player <id>
|
||||
player = {
|
||||
info = 'Show player attributes',
|
||||
help = function()
|
||||
local msgtab = {
|
||||
_info('Usage: /td player <id>'),
|
||||
'List some player metadata.',
|
||||
'Params:',
|
||||
TAB .. '<id> player name (substring suffices).',
|
||||
'\nNote: <id> is restricted to alphanumeric chars and "_", for the sake of security.'
|
||||
}
|
||||
return table.concat(msgtab, '\n')
|
||||
end,
|
||||
exec = function(plr_name, params)
|
||||
if not params or not params:find("[%w_]+") then
|
||||
minetest.chat_send_player(plr_name, 'Missing argument, type "/td help player" for help.')
|
||||
else
|
||||
local p1, p2, plid = params:find('([%w_]+)')
|
||||
local count = 0
|
||||
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local pname = player:get_player_name()
|
||||
|
||||
if pname:find(plid) then
|
||||
count = count + 1
|
||||
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
|
||||
if count == 0 then
|
||||
minetest.chat_send_player(plr_name, _info('No matching player'))
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
-- CMD: /td fix (corpses|map) <map>
|
||||
--[[
|
||||
fix corpses: call lobby.corpse_removal(<map>), then reset its poslist
|
||||
fix maps: set lobby.map[<map>] = 0, then call lobby.update_maps(<map>)
|
||||
--]]
|
||||
fix = {
|
||||
info = 'Fix internal data',
|
||||
help = function()
|
||||
local msgtab = {
|
||||
_info('Usage: /td fix <type> <map>'),
|
||||
'Try to repair damages to game data.',
|
||||
'Params:',
|
||||
TAB .. '<type> One of the following:',
|
||||
TAB .. ' ' .. _keyw('corpses') .. ' -- fix lobby.corpses',
|
||||
TAB .. ' ' .. _keyw('maps') .. ' -- fix lobby.map and player status',
|
||||
TAB .. '<map> map id to fix, or "*" to fix all active maps',
|
||||
'\nNote that you can abbreviate both <type> and <map> parameters to a',
|
||||
'prefix, e.g. \"' .. _keyw('/td fix c *') .. '\" tries to fix corpses in all maps.'
|
||||
}
|
||||
return table.concat(msgtab, '\n')
|
||||
end,
|
||||
exec = function(plr_name, params)
|
||||
local helpcmd = 'type "/td help fix" for help.'
|
||||
|
||||
if not params then
|
||||
minetest.chat_send_player(plr_name, _info('Missing arguments, ' .. helpcmd))
|
||||
else
|
||||
local p1, p2, fix, map
|
||||
p1, p2, fix, map = params:find('(%w+)%s+([%w_*]+)')
|
||||
if not fix or not map then
|
||||
minetest.chat_send_player(plr_name, _info('Missing arguments, ' .. helpcmd))
|
||||
else
|
||||
if string.find('corpses', fix) then
|
||||
tdc.fix_corpses(plr_name, map)
|
||||
elseif string.find('map', fix) then
|
||||
tdc.fix_map(plr_name, map)
|
||||
else
|
||||
minetest.chat_send_player(plr_name, _info('Unknown fix action, ' .. helpcmd))
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
}
|
||||
|
||||
function tdc.exec(plr_name, params)
|
||||
local cmd = nil
|
||||
if params and params ~= '' then
|
||||
local par1 = params:match('[%w_]+')
|
||||
local parN = params:sub(par1:len() + 1) or ''
|
||||
local cname
|
||||
if tdc.actions[par1] then
|
||||
cname = par1
|
||||
cmd = tdc.actions[par1]
|
||||
else
|
||||
-- try cmd prefix match
|
||||
for cmdname in pairs(tdc.actions) do
|
||||
if cmdname:find(par1) == 1 then
|
||||
cname = cmdname
|
||||
cmd = tdc.actions[cmdname]
|
||||
end
|
||||
end
|
||||
end
|
||||
if cname then
|
||||
minetest.log('action', plr_name .. ' runs "/td ' .. cname .. parN .. '"')
|
||||
cmd.exec(plr_name, parN)
|
||||
else
|
||||
minetest.chat_send_player(plr_name,
|
||||
_info('Unknown command "' .. par1 .. '", type "/td help" for possible commands.'))
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(plr_name, list_actions())
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
minetest.register_chatcommand('td', {
|
||||
privs = {traitor_dev = true},
|
||||
params = '<cmd> [<args>]',
|
||||
description = 'Traitor debugging commands. Type "/td help" for a list of possible commands.',
|
||||
func = tdc.exec
|
||||
})
|
||||
|
Loading…
Reference in New Issue