aboutsummaryrefslogtreecommitdiff
path: root/builtin/common/chatcommands.lua
blob: 52edda659baab0a89ede36a09b6c45faf6877641 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
-- Minetest: builtin/common/chatcommands.lua

core.registered_chatcommands = {}

function core.register_chatcommand(cmd, def)
	def = def or {}
	def.params = def.params or ""
	def.description = def.description or ""
	def.privs = def.privs or {}
	def.mod_origin = core.get_current_modname() or "??"
	core.registered_chatcommands[cmd] = def
end

function core.unregister_chatcommand(name)
	if core.registered_chatcommands[name] then
		core.registered_chatcommands[name] = nil
	else
		core.log("warning", "Not unregistering chatcommand " ..name..
			" because it doesn't exist.")
	end
end

function core.override_chatcommand(name, redefinition)
	local chatcommand = core.registered_chatcommands[name]
	assert(chatcommand, "Attempt to override non-existent chatcommand "..name)
	for k, v in pairs(redefinition) do
		rawset(chatcommand, k, v)
	end
	core.registered_chatcommands[name] = chatcommand
end

local cmd_marker = "/"

local function gettext(...)
	return ...
end

local function gettext_replace(text, replace)
	return text:gsub("$1", replace)
end


if INIT == "client" then
	cmd_marker = "."
	gettext = core.gettext
	gettext_replace = fgettext_ne
end

local function do_help_cmd(name, param)
	local function format_help_line(cmd, def)
		local msg = core.colorize("#00ffff", cmd_marker .. cmd)
		if def.params and def.params ~= "" then
			msg = msg .. " " .. def.params
		end
		if def.description and def.description ~= "" then
			msg = msg .. ": " .. def.description
		end
		return msg
	end
	if param == "" then
		local cmds = {}
		for cmd, def in pairs(core.registered_chatcommands) do
			if INIT == "client" or core.check_player_privs(name, def.privs) then
				cmds[#cmds + 1] = cmd
			end
		end
		table.sort(cmds)
		return true, gettext("Available commands: ") .. table.concat(cmds, " ") .. "\n"
				.. gettext_replace("Use '$1help <cmd>' to get more information,"
				.. " or '$1help all' to list everything.", cmd_marker)
	elseif param == "all" then
		local cmds = {}
		for cmd, def in pairs(core.registered_chatcommands) do
			if INIT == "client" or core.check_player_privs(name, def.privs) then
				cmds[#cmds + 1] = format_help_line(cmd, def)
			end
		end
		table.sort(cmds)
		return true, gettext("Available commands:").."\n"..table.concat(cmds, "\n")
	elseif INIT == "game" and param == "privs" then
		local privs = {}
		for priv, def in pairs(core.registered_privileges) do
			privs[#privs + 1] = priv .. ": " .. def.description
		end
		table.sort(privs)
		return true, "Available privileges:\n"..table.concat(privs, "\n")
	else
		local cmd = param
		local def = core.registered_chatcommands[cmd]
		if not def then
			return false, gettext("Command not available: ")..cmd
		else
			return true, format_help_line(cmd, def)
		end
	end
end

if INIT == "client" then
	core.register_chatcommand("help", {
		params = gettext("[all | <cmd>]"),
		description = gettext("Get help for commands"),
		func = function(param)
			return do_help_cmd(nil, param)
		end,
	})
else
	core.register_chatcommand("help", {
		params = "[all | privs | <cmd>]",
		description = "Get help for commands or list privileges",
		func = do_help_cmd,
	})
end
"Authentication handler table not valid"); } void ScriptApiServer::readPrivileges(int index, std::set<std::string> &result) { lua_State *L = getStack(); result.clear(); lua_pushnil(L); if (index < 0) index -= 1; while (lua_next(L, index) != 0) { // key at index -2 and value at index -1 std::string key = luaL_checkstring(L, -2); bool value = readParam<bool>(L, -1); if (value) result.insert(key); // removes value, keeps key for next iteration lua_pop(L, 1); } } void ScriptApiServer::createAuth(const std::string &playername, const std::string &password) { SCRIPTAPI_PRECHECKHEADER int error_handler = PUSH_ERROR_HANDLER(L); getAuthHandler(); lua_getfield(L, -1, "create_auth"); lua_remove(L, -2); // Remove auth handler if (lua_type(L, -1) != LUA_TFUNCTION) throw LuaError("Authentication handler missing create_auth"); lua_pushstring(L, playername.c_str()); lua_pushstring(L, password.c_str()); PCALL_RES(lua_pcall(L, 2, 0, error_handler)); lua_pop(L, 1); // Pop error handler } bool ScriptApiServer::setPassword(const std::string &playername, const std::string &password) { SCRIPTAPI_PRECHECKHEADER int error_handler = PUSH_ERROR_HANDLER(L); getAuthHandler(); lua_getfield(L, -1, "set_password"); lua_remove(L, -2); // Remove auth handler if (lua_type(L, -1) != LUA_TFUNCTION) throw LuaError("Authentication handler missing set_password"); lua_pushstring(L, playername.c_str()); lua_pushstring(L, password.c_str()); PCALL_RES(lua_pcall(L, 2, 1, error_handler)); lua_remove(L, error_handler); return lua_toboolean(L, -1); } bool ScriptApiServer::on_chat_message(const std::string &name, const std::string &message) { SCRIPTAPI_PRECHECKHEADER // Get core.registered_on_chat_messages lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_on_chat_messages"); // Call callbacks lua_pushstring(L, name.c_str()); lua_pushstring(L, message.c_str()); runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC); return readParam<bool>(L, -1); } void ScriptApiServer::on_mods_loaded() { SCRIPTAPI_PRECHECKHEADER // Get registered shutdown hooks lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_on_mods_loaded"); // Call callbacks runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); } void ScriptApiServer::on_shutdown() { SCRIPTAPI_PRECHECKHEADER // Get registered shutdown hooks lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_on_shutdown"); // Call callbacks runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); } std::string ScriptApiServer::formatChatMessage(const std::string &name, const std::string &message) { SCRIPTAPI_PRECHECKHEADER // Push function onto stack lua_getglobal(L, "core"); lua_getfield(L, -1, "format_chat_message"); // Push arguments onto stack lua_pushstring(L, name.c_str()); lua_pushstring(L, message.c_str()); // Actually call the function lua_call(L, 2, 1); // Fetch return value std::string ret = lua_tostring(L, -1); lua_pop(L, 1); return ret; } u32 ScriptApiServer::allocateDynamicMediaCallback(lua_State *L, int f_idx) { if (f_idx < 0) f_idx = lua_gettop(L) + f_idx + 1; lua_getglobal(L, "core"); lua_getfield(L, -1, "dynamic_media_callbacks"); luaL_checktype(L, -1, LUA_TTABLE); // Find a randomly generated token that doesn't exist yet int tries = 100; u32 token; while (1) { token = myrand(); lua_rawgeti(L, -2, token); bool is_free = lua_isnil(L, -1); lua_pop(L, 1); if (is_free) break; if (--tries < 0) FATAL_ERROR("Ran out of callbacks IDs?!"); } // core.dynamic_media_callbacks[token] = callback_func lua_pushvalue(L, f_idx); lua_rawseti(L, -2, token); lua_pop(L, 2); verbosestream << "allocateDynamicMediaCallback() = " << token << std::endl; return token; } void ScriptApiServer::freeDynamicMediaCallback(u32 token) { SCRIPTAPI_PRECHECKHEADER verbosestream << "freeDynamicMediaCallback(" << token << ")" << std::endl; // core.dynamic_media_callbacks[token] = nil lua_getglobal(L, "core"); lua_getfield(L, -1, "dynamic_media_callbacks"); luaL_checktype(L, -1, LUA_TTABLE); lua_pushnil(L); lua_rawseti(L, -2, token); lua_pop(L, 2); } void ScriptApiServer::on_dynamic_media_added(u32 token, const char *playername) { SCRIPTAPI_PRECHECKHEADER int error_handler = PUSH_ERROR_HANDLER(L); lua_getglobal(L, "core"); lua_getfield(L, -1, "dynamic_media_callbacks"); luaL_checktype(L, -1, LUA_TTABLE); lua_rawgeti(L, -1, token); luaL_checktype(L, -1, LUA_TFUNCTION); lua_pushstring(L, playername); PCALL_RES(lua_pcall(L, 1, 0, error_handler)); }