diff options
Diffstat (limited to 'builtin/common')
-rw-r--r-- | builtin/common/after.lua | 20 | ||||
-rw-r--r-- | builtin/common/filterlist.lua | 1 | ||||
-rw-r--r-- | builtin/common/information_formspecs.lua | 152 | ||||
-rw-r--r-- | builtin/common/misc_helpers.lua | 31 | ||||
-rw-r--r-- | builtin/common/serialize.lua | 1 | ||||
-rw-r--r-- | builtin/common/vector.lua | 19 |
6 files changed, 208 insertions, 16 deletions
diff --git a/builtin/common/after.lua b/builtin/common/after.lua index cdfaaab86..b314711c9 100644 --- a/builtin/common/after.lua +++ b/builtin/common/after.lua @@ -1,33 +1,41 @@ local jobs = {} local time = 0.0 +local time_next = math.huge core.register_globalstep(function(dtime) time = time + dtime - if #jobs < 1 then + if time < time_next then return end + time_next = math.huge + -- Iterate backwards so that we miss any new timers added by - -- a timer callback, and so that we don't skip the next timer - -- in the list if we remove one. + -- a timer callback. for i = #jobs, 1, -1 do local job = jobs[i] if time >= job.expire then core.set_last_run_mod(job.mod_origin) job.func(unpack(job.arg)) - table.remove(jobs, i) + local jobs_l = #jobs + jobs[i] = jobs[jobs_l] + jobs[jobs_l] = nil + elseif job.expire < time_next then + time_next = job.expire end end end) function core.after(after, func, ...) assert(tonumber(after) and type(func) == "function", - "Invalid core.after invocation") + "Invalid minetest.after invocation") + local expire = time + after jobs[#jobs + 1] = { func = func, - expire = time + after, + expire = expire, arg = {...}, mod_origin = core.get_last_run_mod() } + time_next = math.min(time_next, expire) end diff --git a/builtin/common/filterlist.lua b/builtin/common/filterlist.lua index 1ba1d8741..e30379f2f 100644 --- a/builtin/common/filterlist.lua +++ b/builtin/common/filterlist.lua @@ -250,7 +250,6 @@ end -------------------------------------------------------------------------------- function compare_worlds(world1,world2) - if world1.path ~= world2.path then return false end diff --git a/builtin/common/information_formspecs.lua b/builtin/common/information_formspecs.lua new file mode 100644 index 000000000..b977e2656 --- /dev/null +++ b/builtin/common/information_formspecs.lua @@ -0,0 +1,152 @@ +local COLOR_BLUE = "#7AF" +local COLOR_GREEN = "#7F7" +local COLOR_GRAY = "#BBB" + +local LIST_FORMSPEC = [[ + size[13,6.5] + label[0,-0.1;%s] + tablecolumns[color;tree;text;text] + table[0,0.5;12.8,5.5;list;%s;0] + button_exit[5,6;3,1;quit;%s] + ]] + +local LIST_FORMSPEC_DESCRIPTION = [[ + size[13,7.5] + label[0,-0.1;%s] + tablecolumns[color;tree;text;text] + table[0,0.5;12.8,4.8;list;%s;%i] + box[0,5.5;12.8,1.5;#000] + textarea[0.3,5.5;13.05,1.9;;;%s] + button_exit[5,7;3,1;quit;%s] + ]] + +local formspec_escape = core.formspec_escape +local check_player_privs = core.check_player_privs + + +-- CHAT COMMANDS FORMSPEC + +local mod_cmds = {} + +local function load_mod_command_tree() + mod_cmds = {} + + for name, def in pairs(core.registered_chatcommands) do + mod_cmds[def.mod_origin] = mod_cmds[def.mod_origin] or {} + local cmds = mod_cmds[def.mod_origin] + + -- Could be simplified, but avoid the priv checks whenever possible + cmds[#cmds + 1] = { name, def } + end + local sorted_mod_cmds = {} + for modname, cmds in pairs(mod_cmds) do + table.sort(cmds, function(a, b) return a[1] < b[1] end) + sorted_mod_cmds[#sorted_mod_cmds + 1] = { modname, cmds } + end + table.sort(sorted_mod_cmds, function(a, b) return a[1] < b[1] end) + mod_cmds = sorted_mod_cmds +end + +core.after(0, load_mod_command_tree) + +local function build_chatcommands_formspec(name, sel, copy) + local rows = {} + rows[1] = "#FFF,0,Command,Parameters" + + local description = "For more information, click on any entry in the list.\n" .. + "Double-click to copy the entry to the chat history." + + for i, data in ipairs(mod_cmds) do + rows[#rows + 1] = COLOR_BLUE .. ",0," .. formspec_escape(data[1]) .. "," + for j, cmds in ipairs(data[2]) do + local has_priv = check_player_privs(name, cmds[2].privs) + rows[#rows + 1] = ("%s,1,%s,%s"):format( + has_priv and COLOR_GREEN or COLOR_GRAY, + cmds[1], formspec_escape(cmds[2].params)) + if sel == #rows then + description = cmds[2].description + if copy then + core.chat_send_player(name, ("Command: %s %s"):format( + core.colorize("#0FF", "/" .. cmds[1]), cmds[2].params)) + end + end + end + end + + return LIST_FORMSPEC_DESCRIPTION:format( + "Available commands: (see also: /help <cmd>)", + table.concat(rows, ","), sel or 0, + description, "Close" + ) +end + + +-- PRIVILEGES FORMSPEC + +local function build_privs_formspec(name) + local privs = {} + for priv_name, def in pairs(core.registered_privileges) do + privs[#privs + 1] = { priv_name, def } + end + table.sort(privs, function(a, b) return a[1] < b[1] end) + + local rows = {} + rows[1] = "#FFF,0,Privilege,Description" + + local player_privs = core.get_player_privs(name) + for i, data in ipairs(privs) do + rows[#rows + 1] = ("%s,0,%s,%s"):format( + player_privs[data[1]] and COLOR_GREEN or COLOR_GRAY, + data[1], formspec_escape(data[2].description)) + end + + return LIST_FORMSPEC:format( + "Available privileges:", + table.concat(rows, ","), + "Close" + ) +end + + +-- DETAILED CHAT COMMAND INFORMATION + +core.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "__builtin:help_cmds" or fields.quit then + return + end + + local event = minetest.explode_table_event(fields.list) + if event.type ~= "INV" then + local name = player:get_player_name() + core.show_formspec(name, "__builtin:help_cmds", + build_chatcommands_formspec(name, event.row, event.type == "DCL")) + end +end) + + +local help_command = core.registered_chatcommands["help"] +local old_help_func = help_command.func + +help_command.func = function(name, param) + local admin = core.settings:get("name") + + -- If the admin ran help, put the output in the chat buffer as well to + -- work with the server terminal + if param == "privs" then + core.show_formspec(name, "__builtin:help_privs", + build_privs_formspec(name)) + if name ~= admin then + return + end + end + if param == "" or param == "all" then + core.show_formspec(name, "__builtin:help_cmds", + build_chatcommands_formspec(name)) + if name ~= admin then + return + end + end + + return old_help_func(name, param) +end + diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua index e250b0ed1..d6673a691 100644 --- a/builtin/common/misc_helpers.lua +++ b/builtin/common/misc_helpers.lua @@ -128,6 +128,7 @@ function dump(o, indent, nested, level) if t ~= "table" then return basic_dump(o) end + -- Contains table -> true/nil of currently nested tables nested = nested or {} if nested[o] then @@ -136,10 +137,11 @@ function dump(o, indent, nested, level) nested[o] = true indent = indent or "\t" level = level or 1 - local t = {} + + local ret = {} local dumped_indexes = {} for i, v in ipairs(o) do - t[#t + 1] = dump(v, indent, nested, level + 1) + ret[#ret + 1] = dump(v, indent, nested, level + 1) dumped_indexes[i] = true end for k, v in pairs(o) do @@ -148,7 +150,7 @@ function dump(o, indent, nested, level) k = "["..dump(k, indent, nested, level + 1).."]" end v = dump(v, indent, nested, level + 1) - t[#t + 1] = k.." = "..v + ret[#ret + 1] = k.." = "..v end end nested[o] = nil @@ -157,10 +159,10 @@ function dump(o, indent, nested, level) local end_indent_str = "\n"..string.rep(indent, level - 1) return string.format("{%s%s%s}", indent_str, - table.concat(t, ","..indent_str), + table.concat(ret, ","..indent_str), end_indent_str) end - return "{"..table.concat(t, ", ").."}" + return "{"..table.concat(ret, ", ").."}" end -------------------------------------------------------------------------------- @@ -244,6 +246,20 @@ function math.sign(x, tolerance) end -------------------------------------------------------------------------------- +function math.factorial(x) + assert(x % 1 == 0 and x >= 0, "factorial expects a non-negative integer") + if x >= 171 then + -- 171! is greater than the biggest double, no need to calculate + return math.huge + end + local v = 1 + for k = 2, x do + v = v * k + end + return v +end + +-------------------------------------------------------------------------------- function get_last_folder(text,count) local parts = text:split(DIR_DELIM) @@ -393,9 +409,8 @@ if INIT == "game" then end local old_itemstack = ItemStack(itemstack) - local new_itemstack, removed = core.item_place_node( - itemstack, placer, pointed_thing, param2, prevent_after_place - ) + local new_itemstack = core.item_place_node(itemstack, placer, + pointed_thing, param2, prevent_after_place) return infinitestacks and old_itemstack or new_itemstack end diff --git a/builtin/common/serialize.lua b/builtin/common/serialize.lua index 692ddd5f0..c91d2d5ce 100644 --- a/builtin/common/serialize.lua +++ b/builtin/common/serialize.lua @@ -218,4 +218,3 @@ test_in = {escape_chars="\n\r\t\v\\\"\'", non_european="θשׁ٩∂"} test_out = core.deserialize(core.serialize(test_in)) assert(test_in.escape_chars == test_out.escape_chars) assert(test_in.non_european == test_out.non_european) - diff --git a/builtin/common/vector.lua b/builtin/common/vector.lua index c3d380ed3..ca6541eb4 100644 --- a/builtin/common/vector.lua +++ b/builtin/common/vector.lua @@ -70,6 +70,25 @@ function vector.direction(pos1, pos2) }) end +function vector.angle(a, b) + local dotp = vector.dot(a, b) + local cp = vector.cross(a, b) + local crossplen = vector.length(cp) + return math.atan2(crossplen, dotp) +end + +function vector.dot(a, b) + return a.x * b.x + a.y * b.y + a.z * b.z +end + +function vector.cross(a, b) + return { + x = a.y * b.z - a.z * b.y, + y = a.z * b.x - a.x * b.z, + z = a.x * b.y - a.y * b.x + } +end + function vector.add(a, b) if type(b) == "table" then return {x = a.x + b.x, |