diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/common/misc_helpers.lua | 57 | ||||
-rw-r--r-- | builtin/common/serialize.lua | 11 | ||||
-rw-r--r-- | builtin/common/strict.lua | 5 | ||||
-rw-r--r-- | builtin/fstk/ui.lua | 71 | ||||
-rw-r--r-- | builtin/game/auth.lua | 1 | ||||
-rw-r--r-- | builtin/game/chatcommands.lua | 109 | ||||
-rw-r--r-- | builtin/game/detached_inventory.lua | 1 | ||||
-rw-r--r-- | builtin/game/item.lua | 61 | ||||
-rw-r--r-- | builtin/game/item_entity.lua | 113 | ||||
-rw-r--r-- | builtin/game/misc.lua | 90 | ||||
-rw-r--r-- | builtin/game/register.lua | 73 | ||||
-rw-r--r-- | builtin/mainmenu/common.lua | 79 | ||||
-rw-r--r-- | builtin/mainmenu/init.lua | 7 | ||||
-rw-r--r-- | builtin/mainmenu/modmgr.lua | 8 | ||||
-rw-r--r-- | builtin/mainmenu/store.lua | 44 | ||||
-rw-r--r-- | builtin/mainmenu/tab_credits.lua | 87 | ||||
-rw-r--r-- | builtin/mainmenu/tab_mods.lua | 5 | ||||
-rw-r--r-- | builtin/mainmenu/tab_multiplayer.lua | 5 | ||||
-rw-r--r-- | builtin/mainmenu/tab_server.lua | 27 | ||||
-rw-r--r-- | builtin/mainmenu/tab_settings.lua | 111 | ||||
-rw-r--r-- | builtin/mainmenu/tab_simple_main.lua | 19 | ||||
-rw-r--r-- | builtin/mainmenu/tab_singleplayer.lua | 40 | ||||
-rw-r--r-- | builtin/mainmenu/tab_texturepacks.lua | 18 | ||||
-rw-r--r-- | builtin/mainmenu/textures.lua | 31 |
24 files changed, 761 insertions, 312 deletions
diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua index 39fca7d1e..bf672e6da 100644 --- a/builtin/common/misc_helpers.lua +++ b/builtin/common/misc_helpers.lua @@ -1,6 +1,11 @@ -- Minetest: builtin/misc_helpers.lua -------------------------------------------------------------------------------- +-- Localize functions to avoid table lookups (better performance). +local table_insert = table.insert +local string_sub, string_find = string.sub, string.find + +-------------------------------------------------------------------------------- function basic_dump(o) local tp = type(o) if tp == "number" then @@ -89,13 +94,13 @@ function dump2(o, name, dumped) -- the form _G["table: 0xFFFFFFF"] keyStr = string.format("_G[%q]", tostring(k)) -- Dump key table - table.insert(t, dump2(k, keyStr, dumped)) + table_insert(t, dump2(k, keyStr, dumped)) end else keyStr = basic_dump(k) end local vname = string.format("%s[%s]", name, keyStr) - table.insert(t, dump2(v, vname, dumped)) + table_insert(t, dump2(v, vname, dumped)) end return string.format("%s = {}\n%s", name, table.concat(t)) end @@ -130,7 +135,7 @@ function dump(o, indent, nested, level) local t = {} local dumped_indexes = {} for i, v in ipairs(o) do - table.insert(t, dump(v, indent, nested, level + 1)) + table_insert(t, dump(v, indent, nested, level + 1)) dumped_indexes[i] = true end for k, v in pairs(o) do @@ -139,7 +144,7 @@ function dump(o, indent, nested, level) k = "["..dump(k, indent, nested, level + 1).."]" end v = dump(v, indent, nested, level + 1) - table.insert(t, k.." = "..v) + table_insert(t, k.." = "..v) end end nested[o] = nil @@ -155,9 +160,6 @@ function dump(o, indent, nested, level) end -------------------------------------------------------------------------------- --- Localize functions to avoid table lookups (better performance). -local table_insert = table.insert -local str_sub, str_find = string.sub, string.find function string.split(str, delim, include_empty, max_splits, sep_is_pattern) delim = delim or "," max_splits = max_splits or -1 @@ -166,13 +168,13 @@ function string.split(str, delim, include_empty, max_splits, sep_is_pattern) local plain = not sep_is_pattern max_splits = max_splits + 1 repeat - local np, npe = str_find(str, delim, pos, plain) + local np, npe = string_find(str, delim, pos, plain) np, npe = (np or (len+1)), (npe or (len+1)) if (not np) or (max_splits == 1) then np = len + 1 npe = np end - local s = str_sub(str, pos, np - 1) + local s = string_sub(str, pos, np - 1) if include_empty or (s ~= "") then max_splits = max_splits - 1 table_insert(items, s) @@ -183,9 +185,22 @@ function string.split(str, delim, include_empty, max_splits, sep_is_pattern) end -------------------------------------------------------------------------------- +function table.indexof(list, val) + for i = 1, #list do + if list[i] == val then + return i + end + end + return -1 +end + +assert(table.indexof({"foo", "bar"}, "foo") == 1) +assert(table.indexof({"foo", "bar"}, "baz") == -1) + +-------------------------------------------------------------------------------- function file_exists(filename) local f = io.open(filename, "r") - if f==nil then + if f == nil then return false else f:close() @@ -298,8 +313,8 @@ function core.splittext(text,charlimit) local current_idx = 1 - local start,stop = string.find(text," ",current_idx) - local nl_start,nl_stop = string.find(text,"\n",current_idx) + local start,stop = string_find(text, " ", current_idx) + local nl_start,nl_stop = string_find(text, "\n", current_idx) local gotnewline = false if nl_start ~= nil and (start == nil or nl_start < start) then start = nl_start @@ -309,7 +324,7 @@ function core.splittext(text,charlimit) local last_line = "" while start ~= nil do if string.len(last_line) + (stop-start) > charlimit then - table.insert(retval,last_line) + table_insert(retval, last_line) last_line = "" end @@ -317,17 +332,17 @@ function core.splittext(text,charlimit) last_line = last_line .. " " end - last_line = last_line .. string.sub(text,current_idx,stop -1) + last_line = last_line .. string_sub(text, current_idx, stop - 1) if gotnewline then - table.insert(retval,last_line) + table_insert(retval, last_line) last_line = "" gotnewline = false end current_idx = stop+1 - start,stop = string.find(text," ",current_idx) - nl_start,nl_stop = string.find(text,"\n",current_idx) + start,stop = string_find(text, " ", current_idx) + nl_start,nl_stop = string_find(text, "\n", current_idx) if nl_start ~= nil and (start == nil or nl_start < start) then start = nl_start @@ -338,11 +353,11 @@ function core.splittext(text,charlimit) --add last part of text if string.len(last_line) + (string.len(text) - current_idx) > charlimit then - table.insert(retval,last_line) - table.insert(retval,string.sub(text,current_idx)) + table_insert(retval, last_line) + table_insert(retval, string_sub(text, current_idx)) else - last_line = last_line .. " " .. string.sub(text,current_idx) - table.insert(retval,last_line) + last_line = last_line .. " " .. string_sub(text, current_idx) + table_insert(retval, last_line) end return retval diff --git a/builtin/common/serialize.lua b/builtin/common/serialize.lua index 24b2a12ee..90b8b2ad6 100644 --- a/builtin/common/serialize.lua +++ b/builtin/common/serialize.lua @@ -115,11 +115,20 @@ function core.serialize(x) function dump_val(x) local tp = type(x) if x == nil then return "nil" - elseif tp == "number" then return string.format("%d", x) elseif tp == "string" then return string.format("%q", x) elseif tp == "boolean" then return x and "true" or "false" elseif tp == "function" then return string.format("loadstring(%q)", string.dump(x)) + elseif tp == "number" then + -- Serialize integers with string.format to prevent + -- scientific notation, which doesn't preserve + -- precision and breaks things like node position + -- hashes. Serialize floats normally. + if math.floor(x) == x then + return string.format("%d", x) + else + return tostring(x) + end elseif tp == "table" then local vals = {} local idx_dumped = {} diff --git a/builtin/common/strict.lua b/builtin/common/strict.lua index c353bb913..c7b86461f 100644 --- a/builtin/common/strict.lua +++ b/builtin/common/strict.lua @@ -4,6 +4,11 @@ local WARN_INIT = false +function core.global_exists(name) + return rawget(_G, name) ~= nil +end + + local function warn(message) print(os.date("%H:%M:%S: WARNING: ")..message) end diff --git a/builtin/fstk/ui.lua b/builtin/fstk/ui.lua index 708ea19cf..de8ae4d2c 100644 --- a/builtin/fstk/ui.lua +++ b/builtin/fstk/ui.lua @@ -23,7 +23,7 @@ ui.default = nil function ui.add(child) --TODO check child ui.childlist[child.name] = child - + return child.name end @@ -33,7 +33,7 @@ function ui.delete(child) if ui.childlist[child.name] == nil then return false end - + ui.childlist[child.name] = nil return true end @@ -54,17 +54,52 @@ end -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- +local function wordwrap_quickhack(str) + local res = "" + local ar = str:split("\n") + for i = 1, #ar do + local text = ar[i] + -- Hack to add word wrapping. + -- TODO: Add engine support for wrapping in formspecs + while #text > 80 do + if res ~= "" then + res = res .. "," + end + res = res .. core.formspec_escape(string.sub(text, 1, 79)) + text = string.sub(text, 80, #text) + end + if res ~= "" then + res = res .. "," + end + res = res .. core.formspec_escape(text) + end + return res +end + -------------------------------------------------------------------------------- function ui.update() local formspec = "" -- handle errors - if gamedata ~= nil and gamedata.errormessage ~= nil then - formspec = "size[12,3.2]" .. - "textarea[1,1;10,2;;ERROR: " .. - core.formspec_escape(gamedata.errormessage) .. - ";]".. - "button[4.5,2.5;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]" + if gamedata ~= nil and gamedata.reconnect_requested then + formspec = wordwrap_quickhack(gamedata.errormessage or "") + formspec = "size[12,5]" .. + "label[0.5,0;" .. fgettext("The server has requested a reconnect:") .. + "]textlist[0.2,0.8;11.5,3.5;;" .. formspec .. + "]button[6,4.6;3,0.5;btn_reconnect_no;" .. fgettext("Main menu") .. "]" .. + "button[3,4.6;3,0.5;btn_reconnect_yes;" .. fgettext("Reconnect") .. "]" + elseif gamedata ~= nil and gamedata.errormessage ~= nil then + formspec = wordwrap_quickhack(gamedata.errormessage) + local error_title + if string.find(gamedata.errormessage, "ModError") then + error_title = fgettext("An error occured in a Lua script, such as a mod:") + else + error_title = fgettext("An error occured:") + end + formspec = "size[12,5]" .. + "label[0.5,0;" .. error_title .. + "]textlist[0.2,0.8;11.5,3.5;;" .. formspec .. + "]button[4.5,4.6;3,0.5;btn_error_confirm;" .. fgettext("Ok") .. "]" else local active_toplevel_ui_elements = 0 for key,value in pairs(ui.childlist) do @@ -77,7 +112,7 @@ function ui.update() end end end - + -- no need to show addons if there ain't a toplevel element if (active_toplevel_ui_elements > 0) then for key,value in pairs(ui.childlist) do @@ -106,13 +141,6 @@ end -------------------------------------------------------------------------------- function ui.handle_buttons(fields) - - if fields["btn_error_confirm"] then - gamedata.errormessage = nil - update_menu() - return - end - for key,value in pairs(ui.childlist) do local retval = value:handle_buttons(fields) @@ -127,7 +155,7 @@ end -------------------------------------------------------------------------------- function ui.handle_events(event) - + for key,value in pairs(ui.childlist) do if value.handle_events ~= nil then @@ -146,8 +174,15 @@ end -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- core.button_handler = function(fields) - if fields["btn_error_confirm"] then + if fields["btn_reconnect_yes"] then + gamedata.reconnect_requested = false + gamedata.errormessage = nil + gamedata.do_reconnect = true + core.start() + return + elseif fields["btn_reconnect_no"] or fields["btn_error_confirm"] then gamedata.errormessage = nil + gamedata.reconnect_requested = false ui.update() return end diff --git a/builtin/game/auth.lua b/builtin/game/auth.lua index 93b009981..423eb3134 100644 --- a/builtin/game/auth.lua +++ b/builtin/game/auth.lua @@ -171,6 +171,7 @@ function core.register_authentication_handler(handler) end core.registered_auth_handler = handler core.registered_auth_handler_modname = core.get_current_modname() + handler.mod_origin = core.registered_auth_handler_modname end function core.get_auth_handler() diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua index 91b685fdf..5d317de4b 100644 --- a/builtin/game/chatcommands.lua +++ b/builtin/game/chatcommands.lua @@ -10,6 +10,7 @@ function core.register_chatcommand(cmd, def) def.params = def.params or "" def.description = def.description or "" def.privs = def.privs or {} + def.mod_origin = core.get_current_modname() or "??" core.chatcommands[cmd] = def end @@ -37,6 +38,7 @@ core.register_on_chat_message(function(name, message) end local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs) if has_privs then + core.set_last_run_mod(cmd_def.mod_origin) local success, message = cmd_def.func(name, param) if message then core.chat_send_player(name, message) @@ -189,7 +191,7 @@ core.register_chatcommand("revoke", { local revoke_privs = core.string_to_privs(revoke_priv_str) local privs = core.get_player_privs(revoke_name) for priv, _ in pairs(revoke_privs) do - if priv ~= "interact" and priv ~= "shout" and priv ~= "interact_extra" and + if priv ~= "interact" and priv ~= "shout" and not core.check_player_privs(name, {privs=true}) then return false, "Your privileges are insufficient." end @@ -229,21 +231,28 @@ core.register_chatcommand("setpassword", { if not toname then return false, "Name field required" end - local actstr = "?" + local act_str_past = "?" + local act_str_pres = "?" if not raw_password then core.set_player_password(toname, "") - actstr = "cleared" + act_str_past = "cleared" + act_str_pres = "clears" else core.set_player_password(toname, core.get_password_hash(toname, raw_password)) - actstr = "set" + act_str_past = "set" + act_str_pres = "sets" end if toname ~= name then core.chat_send_player(toname, "Your password was " - .. actstr .. " by " .. name) + .. act_str_past .. " by " .. name) end - return true, "Password of player \"" .. toname .. "\" " .. actstr + + core.log("action", name .. " " .. act_str_pres + .. " password of " .. toname .. ".") + + return true, "Password of player \"" .. toname .. "\" " .. act_str_past end, }) @@ -257,6 +266,9 @@ core.register_chatcommand("clearpassword", { return false, "Name field required" end core.set_player_password(toname, '') + + core.log("action", name .. " clears password of " .. toname .. ".") + return true, "Password of player \"" .. toname .. "\" cleared" end, }) @@ -308,7 +320,7 @@ core.register_chatcommand("teleport", { teleportee:setpos(p) return true, "Teleporting to "..core.pos_to_string(p) end - + local teleportee = nil local p = nil local target_name = nil @@ -345,7 +357,7 @@ core.register_chatcommand("teleport", { return true, "Teleporting " .. teleportee_name .. " to " .. core.pos_to_string(p) end - + local teleportee = nil local p = nil local teleportee_name = nil @@ -367,7 +379,7 @@ core.register_chatcommand("teleport", { .. " to " .. target_name .. " at " .. core.pos_to_string(p) end - + return false, 'Invalid parameters ("' .. param .. '") or player not found (see /help teleport)' end, @@ -404,13 +416,14 @@ core.register_chatcommand("set", { }) core.register_chatcommand("deleteblocks", { - params = "[here] [<pos1> <pos2>]", + params = "(here [radius]) | (<pos1> <pos2>)", description = "delete map blocks contained in area pos1 to pos2", privs = {server=true}, func = function(name, param) local p1 = {} local p2 = {} - if param == "here" then + local args = param:split(" ") + if args[1] == "here" then local player = core.get_player_by_name(name) if player == nil then core.log("error", "player is nil") @@ -418,6 +431,12 @@ core.register_chatcommand("deleteblocks", { end p1 = player:getpos() p2 = p1 + + if #args >= 2 then + local radius = tonumber(args[2]) or 0 + p1 = vector.add(p1, radius) + p2 = vector.subtract(p2, radius) + end else local pos1, pos2 = unpack(param:split(") (")) if pos1 == nil or pos2 == nil then @@ -513,22 +532,29 @@ core.register_chatcommand("giveme", { }) core.register_chatcommand("spawnentity", { - params = "<EntityName>", - description = "Spawn entity at your position", + params = "<EntityName> [<X>,<Y>,<Z>]", + description = "Spawn entity at given (or your) position", privs = {give=true, interact=true}, func = function(name, param) - local entityname = string.match(param, "(.+)$") + local entityname, p = string.match(param, "^([^ ]+) *(.*)$") if not entityname then return false, "EntityName required" end - core.log("action", ("/spawnentity invoked, entityname=%q") - :format(entityname)) + core.log("action", ("%s invokes /spawnentity, entityname=%q") + :format(name, entityname)) local player = core.get_player_by_name(name) if player == nil then core.log("error", "Unable to spawn entity, player is nil") return false, "Unable to spawn entity, player is nil" end - local p = player:getpos() + if p == "" then + p = player:getpos() + else + p = core.string_to_pos(p) + if p == nil then + return false, "Invalid parameters ('" .. param .. "')" + end + end p.y = p.y + 1 core.add_entity(p, entityname) return true, ("%q spawned."):format(entityname) @@ -662,19 +688,41 @@ core.register_chatcommand("status", { }) core.register_chatcommand("time", { - params = "<0...24000>", + params = "<0..23>:<0..59> | <0..24000>", description = "set time of day", - privs = {settime=true}, + privs = {}, func = function(name, param) if param == "" then - return false, "Missing time." - end - local newtime = tonumber(param) - if newtime == nil then - return false, "Invalid time." - end - core.set_timeofday((newtime % 24000) / 24000) - core.log("action", name .. " sets time " .. newtime) + local current_time = math.floor(core.get_timeofday() * 1440) + local minutes = current_time % 60 + local hour = (current_time - minutes) / 60 + return true, ("Current time is %d:%02d"):format(hour, minutes) + end + local player_privs = minetest.get_player_privs(name) + if not player_privs.settime then + return false, "You don't have permission to run this command " .. + "(missing privilege: settime)." + end + local hour, minute = param:match("^(%d+):(%d+)$") + if not hour then + local new_time = tonumber(param) + if not new_time then + return false, "Invalid time." + end + -- Backward compatibility. + core.set_timeofday((new_time % 24000) / 24000) + core.log("action", name .. " sets time to " .. new_time) + return true, "Time of day changed." + end + hour = tonumber(hour) + minute = tonumber(minute) + if hour < 0 or hour > 23 then + return false, "Invalid hour (must be between 0 and 23 inclusive)." + elseif minute < 0 or minute > 59 then + return false, "Invalid minute (must be between 0 and 59 inclusive)." + end + core.set_timeofday((hour * 60 + minute) / 1440) + core.log("action", ("%s sets time to %d:%02d"):format(name, hour, minute)) return true, "Time of day changed." end, }) @@ -732,7 +780,11 @@ core.register_chatcommand("kick", { if not core.kick_player(tokick, reason) then return false, "Failed to kick player " .. tokick end - core.log("action", name .. " kicked " .. tokick) + local log_reason = "" + if reason then + log_reason = " with reason \"" .. reason .. "\"" + end + core.log("action", name .. " kicks " .. tokick .. log_reason) return true, "Kicked " .. tokick end, }) @@ -788,4 +840,3 @@ core.register_chatcommand("last-login", { return false, "Last login time is unknown" end, }) - diff --git a/builtin/game/detached_inventory.lua b/builtin/game/detached_inventory.lua index e8f03b56c..b5d106b04 100644 --- a/builtin/game/detached_inventory.lua +++ b/builtin/game/detached_inventory.lua @@ -13,6 +13,7 @@ function core.create_detached_inventory(name, callbacks) stuff.on_put = callbacks.on_put stuff.on_take = callbacks.on_take end + stuff.mod_origin = core.get_current_modname() or "??" core.detached_inventories[name] = stuff return core.create_detached_inventory_raw(name) end diff --git a/builtin/game/item.lua b/builtin/game/item.lua index e136d4f4c..6628a4081 100644 --- a/builtin/game/item.lua +++ b/builtin/game/item.lua @@ -106,7 +106,7 @@ function core.facedir_to_dir(facedir) {x=0, y=1, z=0}}) --indexed into by a table of correlating facedirs - [({[0]=1, 2, 3, 4, + [({[0]=1, 2, 3, 4, 5, 2, 6, 4, 6, 2, 5, 4, 1, 5, 3, 6, @@ -238,7 +238,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2) core.log("action", placer:get_player_name() .. " places node " .. def.name .. " at " .. core.pos_to_string(place_to)) - + local oldnode = core.get_node(place_to) local newnode = {name = def.name, param1 = 0, param2 = param2} @@ -357,19 +357,37 @@ function core.item_drop(itemstack, dropper, pos) return itemstack end -function core.item_eat(hp_change, replace_with_item) - return function(itemstack, user, pointed_thing) -- closure - for _, callback in pairs(core.registered_on_item_eats) do - local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing) - if result then - return result - end +function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing) + for _, callback in pairs(core.registered_on_item_eats) do + local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing) + if result then + return result end - if itemstack:take_item() ~= nil then - user:set_hp(user:get_hp() + hp_change) - itemstack:add_item(replace_with_item) -- note: replace_with_item is optional + end + if itemstack:take_item() ~= nil then + user:set_hp(user:get_hp() + hp_change) + + if replace_with_item then + if itemstack:is_empty() then + itemstack:add_item(replace_with_item) + else + local inv = user:get_inventory() + if inv:room_for_item("main", {name=replace_with_item}) then + inv:add_item("main", replace_with_item) + else + local pos = user:getpos() + pos.y = math.floor(pos.y + 0.5) + core.add_item(pos, replace_with_item) + end + end end - return itemstack + end + return itemstack +end + +function core.item_eat(hp_change, replace_with_item) + return function(itemstack, user, pointed_thing) -- closure + return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing) end end @@ -425,7 +443,7 @@ function core.node_dig(pos, node, digger) local wielded = digger:get_wielded_item() local drops = core.get_node_drops(node.name, wielded:get_name()) - + local wdef = wielded:get_definition() local tp = wielded:get_tool_capabilities() local dp = core.get_dig_params(def.groups, tp) @@ -438,7 +456,7 @@ function core.node_dig(pos, node, digger) end end digger:set_wielded_item(wielded) - + -- Handle drops core.handle_node_drops(pos, drops, digger) @@ -449,7 +467,7 @@ function core.node_dig(pos, node, digger) -- Remove node and update core.remove_node(pos) - + -- Run callback if def.after_dig_node then -- Copy pos and node because callback can modify them @@ -461,6 +479,15 @@ function core.node_dig(pos, node, digger) -- Run script hook local _, callback for _, callback in ipairs(core.registered_on_dignodes) do + local origin = core.callback_origins[callback] + if origin then + core.set_last_run_mod(origin.mod) + --print("Running " .. tostring(callback) .. + -- " (a " .. origin.name .. " callback in " .. origin.mod .. ")") + else + --print("No data associated with callback") + end + -- Copy pos and node because callback can modify them local pos_copy = {x=pos.x, y=pos.y, z=pos.z} local node_copy = {name=node.name, param1=node.param1, param2=node.param2} @@ -507,7 +534,7 @@ core.nodedef_default = { on_dig = redef_wrapper(core, 'node_dig'), -- core.node_dig on_receive_fields = nil, - + on_metadata_inventory_move = core.node_metadata_inventory_move_allow_all, on_metadata_inventory_offer = core.node_metadata_inventory_offer_allow_all, on_metadata_inventory_take = core.node_metadata_inventory_take_allow_all, diff --git a/builtin/game/item_entity.lua b/builtin/game/item_entity.lua index d6781feca..6425a10aa 100644 --- a/builtin/game/item_entity.lua +++ b/builtin/game/item_entity.lua @@ -96,6 +96,56 @@ core.register_entity(":__builtin:item", { self:set_item(self.itemstring) end, + try_merge_with = function(self, own_stack, object, obj) + local stack = ItemStack(obj.itemstring) + if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then + local overflow = false + local count = stack:get_count() + own_stack:get_count() + local max_count = stack:get_stack_max() + if count > max_count then + overflow = true + count = count - max_count + else + self.itemstring = '' + end + local pos = object:getpos() + pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15 + object:moveto(pos, false) + local s, c + local max_count = stack:get_stack_max() + local name = stack:get_name() + if not overflow then + obj.itemstring = name .. " " .. count + s = 0.2 + 0.1 * (count / max_count) + c = s + object:set_properties({ + visual_size = {x = s, y = s}, + collisionbox = {-c, -c, -c, c, c, c} + }) + self.object:remove() + -- merging succeeded + return true + else + s = 0.4 + c = 0.3 + object:set_properties({ + visual_size = {x = s, y = s}, + collisionbox = {-c, -c, -c, c, c, c} + }) + obj.itemstring = name .. " " .. max_count + s = 0.2 + 0.1 * (count / max_count) + c = s + self.object:set_properties({ + visual_size = {x = s, y = s}, + collisionbox = {-c, -c, -c, c, c, c} + }) + self.itemstring = name .. " " .. count + end + end + -- merging didn't succeed + return false + end, + on_step = function(self, dtime) self.age = self.age + dtime if time_to_live > 0 and self.age > time_to_live then @@ -105,58 +155,29 @@ core.register_entity(":__builtin:item", { end local p = self.object:getpos() p.y = p.y - 0.5 - local nn = core.get_node(p).name + local node = core.get_node_or_nil(p) + local in_unloaded = (node == nil) + if in_unloaded then + -- Don't infinetly fall into unloaded map + self.object:setvelocity({x = 0, y = 0, z = 0}) + self.object:setacceleration({x = 0, y = 0, z = 0}) + self.physical_state = false + self.object:set_properties({physical = false}) + return + end + local nn = node.name -- If node is not registered or node is walkably solid and resting on nodebox local v = self.object:getvelocity() if not core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then if self.physical_state then local own_stack = ItemStack(self.object:get_luaentity().itemstring) - for _,object in ipairs(core.get_objects_inside_radius(p, 0.8)) do + -- Merge with close entities of the same item + for _, object in ipairs(core.get_objects_inside_radius(p, 0.8)) do local obj = object:get_luaentity() - if obj and obj.name == "__builtin:item" and obj.physical_state == false then - local stack = ItemStack(obj.itemstring) - if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then - local overflow = false - local count = stack:get_count() + own_stack:get_count() - local max_count = stack:get_stack_max() - if count>max_count then - overflow = true - count = count - max_count - else - self.itemstring = '' - end - local pos=object:getpos() - pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15 - object:moveto(pos, false) - local s, c - local max_count = stack:get_stack_max() - local name = stack:get_name() - if not overflow then - obj.itemstring = name.." "..count - s = 0.2 + 0.1 * (count / max_count) - c = s - object:set_properties({ - visual_size = {x = s, y = s}, - collisionbox = {-c, -c, -c, c, c, c} - }) - self.object:remove() - return - else - s = 0.4 - c = 0.3 - object:set_properties({ - visual_size = {x = s, y = s}, - collisionbox = {-c, -c, -c, c, c, c} - }) - obj.itemstring = name.." "..max_count - s = 0.2 + 0.1 * (count / max_count) - c = s - self.object:set_properties({ - visual_size = {x = s, y = s}, - collisionbox = {-c, -c, -c, c, c, c} - }) - self.itemstring = name.." "..count - end + if obj and obj.name == "__builtin:item" + and obj.physical_state == false then + if self:try_merge_with(own_stack, object, obj) then + return end end end diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua index c31df541d..e3b7d82bc 100644 --- a/builtin/game/misc.lua +++ b/builtin/game/misc.lua @@ -4,40 +4,83 @@ -- Misc. API functions -- -core.timers_to_add = {} -core.timers = {} -core.register_globalstep(function(dtime) - for _, timer in ipairs(core.timers_to_add) do - table.insert(core.timers, timer) - end - core.timers_to_add = {} - local index = 1 - while index <= #core.timers do - local timer = core.timers[index] - timer.time = timer.time - dtime +local timers = {} +local mintime +local function update_timers(delay) + mintime = false + local sub = 0 + for index = 1, #timers do + index = index - sub + local timer = timers[index] + timer.time = timer.time - delay if timer.time <= 0 then + core.set_last_run_mod(timer.mod_origin) timer.func(unpack(timer.args or {})) - table.remove(core.timers,index) + table.remove(timers, index) + sub = sub + 1 + elseif mintime then + mintime = math.min(mintime, timer.time) else - index = index + 1 + mintime = timer.time end end +end + +local timers_to_add +local function add_timers() + for _, timer in ipairs(timers_to_add) do + table.insert(timers, timer) + end + timers_to_add = false +end + +local delay = 0 +core.register_globalstep(function(dtime) + if not mintime then + -- abort if no timers are running + return + end + if timers_to_add then + add_timers() + end + delay = delay + dtime + if delay < mintime then + return + end + update_timers(delay) + delay = 0 end) function core.after(time, func, ...) assert(tonumber(time) and type(func) == "function", "Invalid core.after invocation") - table.insert(core.timers_to_add, {time=time, func=func, args={...}}) + if not mintime then + mintime = time + timers_to_add = {{ + time = time+delay, + func = func, + args = {...}, + mod_origin = core.get_last_run_mod(), + }} + return + end + mintime = math.min(mintime, time) + timers_to_add = timers_to_add or {} + timers_to_add[#timers_to_add+1] = { + time = time+delay, + func = func, + args = {...}, + mod_origin = core.get_last_run_mod(), + } end function core.check_player_privs(name, privs) local player_privs = core.get_player_privs(name) local missing_privileges = {} for priv, val in pairs(privs) do - if val then - if not player_privs[priv] then - table.insert(missing_privileges, priv) - end + if val + and not player_privs[priv] then + table.insert(missing_privileges, priv) end end if #missing_privileges > 0 then @@ -112,3 +155,14 @@ function core.record_protection_violation(pos, name) end end +local raillike_ids = {} +local raillike_cur_id = 0 +function core.raillike_group(name) + local id = raillike_ids[name] + if not id then + raillike_cur_id = raillike_cur_id + 1 + raillike_ids[name] = raillike_cur_id + id = raillike_cur_id + end + return id +end diff --git a/builtin/game/register.lua b/builtin/game/register.lua index f286113ec..d0e04bfc3 100644 --- a/builtin/game/register.lua +++ b/builtin/game/register.lua @@ -72,6 +72,7 @@ end function core.register_abm(spec) -- Add to core.registered_abms core.registered_abms[#core.registered_abms+1] = spec + spec.mod_origin = core.get_current_modname() or "??" end function core.register_entity(name, prototype) @@ -86,6 +87,7 @@ function core.register_entity(name, prototype) -- Add to core.registered_entities core.registered_entities[name] = prototype + prototype.mod_origin = core.get_current_modname() or "??" end function core.register_item(name, itemdef) @@ -147,6 +149,8 @@ function core.register_item(name, itemdef) end -- END Legacy stuff + itemdef.mod_origin = core.get_current_modname() or "??" + -- Disable all further modifications getmetatable(itemdef).__newindex = {} @@ -326,6 +330,8 @@ function core.override_item(name, redefinition) end +core.callback_origins = {} + function core.run_callbacks(callbacks, mode, ...) assert(type(callbacks) == "table") local cb_len = #callbacks @@ -338,6 +344,14 @@ function core.run_callbacks(callbacks, mode, ...) end local ret = nil for i = 1, cb_len do + local origin = core.callback_origins[callbacks[i]] + if origin then + core.set_last_run_mod(origin.mod) + --print("Running " .. tostring(callbacks[i]) .. + -- " (a " .. origin.name .. " callback in " .. origin.mod .. ")") + else + --print("No data associated with callback") + end local cb_ret = callbacks[i](...) if mode == 0 and i == 1 then @@ -370,13 +384,29 @@ end local function make_registration() local t = {} - local registerfunc = function(func) table.insert(t, func) end + local registerfunc = function(func) + table.insert(t, func) + core.callback_origins[func] = { + mod = core.get_current_modname() or "??", + name = debug.getinfo(1, "n").name or "??" + } + --local origin = core.callback_origins[func] + --print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func)) + end return t, registerfunc end local function make_registration_reverse() local t = {} - local registerfunc = function(func) table.insert(t, 1, func) end + local registerfunc = function(func) + table.insert(t, 1, func) + core.callback_origins[func] = { + mod = core.get_current_modname() or "??", + name = debug.getinfo(1, "n").name or "??" + } + --local origin = core.callback_origins[func] + --print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func)) + end return t, registerfunc end @@ -398,13 +428,49 @@ local function make_registration_wrap(reg_fn_name, clear_fn_name) local orig_clear_fn = core[clear_fn_name] core[clear_fn_name] = function() - list = {} + for k in pairs(list) do + list[k] = nil + end return orig_clear_fn() end return list end +core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } } + +function core.registered_on_player_hpchange(player, hp_change) + local last = false + for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do + local func = core.registered_on_player_hpchanges.modifiers[i] + hp_change, last = func(player, hp_change) + if type(hp_change) ~= "number" then + local debuginfo = debug.getinfo(func) + error("The register_on_hp_changes function has to return a number at " .. + debuginfo.short_src .. " line " .. debuginfo.linedefined) + end + if last then + break + end + end + for i, func in ipairs(core.registered_on_player_hpchanges.loggers) do + func(player, hp_change) + end + return hp_change +end + +function core.register_on_player_hpchange(func, modifier) + if modifier then + table.insert(core.registered_on_player_hpchanges.modifiers, func) + else + table.insert(core.registered_on_player_hpchanges.loggers, func) + end + core.callback_origins[func] = { + mod = core.get_current_modname() or "??", + name = debug.getinfo(1, "n").name or "??" + } +end + core.registered_biomes = make_registration_wrap("register_biome", "clear_registered_biomes") core.registered_ores = make_registration_wrap("register_ore", "clear_registered_ores") core.registered_decorations = make_registration_wrap("register_decoration", "clear_registered_decorations") @@ -429,6 +495,7 @@ core.registered_on_crafts, core.register_on_craft = make_registration() core.registered_craft_predicts, core.register_craft_predict = make_registration() core.registered_on_protection_violation, core.register_on_protection_violation = make_registration() core.registered_on_item_eats, core.register_on_item_eat = make_registration() +core.registered_on_punchplayers, core.register_on_punchplayer = make_registration() -- -- Compatibility for on_mapgen_init() diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index f32d77f2a..6266d0220 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -40,6 +40,18 @@ local function render_client_count(n) end end +local function configure_selected_world_params(idx) + local worldconfig = modmgr.get_worldconfig( + menudata.worldlist:get_list()[idx].path) + + if worldconfig.creative_mode ~= nil then + core.setting_set("creative_mode", worldconfig.creative_mode) + end + if worldconfig.enable_damage ~= nil then + core.setting_set("enable_damage", worldconfig.enable_damage) + end +end + -------------------------------------------------------------------------------- function image_column(tooltip, flagname) return "image," .. @@ -189,7 +201,6 @@ end -------------------------------------------------------------------------------- function menu_handle_key_up_down(fields,textlist,settingname) - if fields["key_up"] then local oldidx = core.get_textlist_index(textlist) @@ -197,6 +208,8 @@ function menu_handle_key_up_down(fields,textlist,settingname) local newidx = oldidx -1 core.setting_set(settingname, menudata.worldlist:get_raw_index(newidx)) + + configure_selected_world_params(newidx) end return true end @@ -208,18 +221,26 @@ function menu_handle_key_up_down(fields,textlist,settingname) local newidx = oldidx + 1 core.setting_set(settingname, menudata.worldlist:get_raw_index(newidx)) + + configure_selected_world_params(newidx) end - + return true end - + return false end -------------------------------------------------------------------------------- function asyncOnlineFavourites() - menudata.favorites = {} + if not menudata.public_known then + menudata.public_known = {{ + name = fgettext("Loading..."), + description = fgettext_ne("Try reenabling public serverlist and check your internet connection.") + }} + end + menudata.favorites = menudata.public_known core.handle_async( function(param) return core.get_favorites("online") @@ -227,32 +248,36 @@ function asyncOnlineFavourites() nil, function(result) if core.setting_getbool("public_serverlist") then - menudata.favorites = order_favorite_list(result) + local favs = order_favorite_list(result) + if favs[1] then + menudata.public_known = favs + menudata.favorites = menudata.public_known + end core.event_handler("Refresh") end end - ) + ) end -------------------------------------------------------------------------------- function text2textlist(xpos,ypos,width,height,tl_name,textlen,text,transparency) local textlines = core.splittext(text,textlen) - + local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width .. "," .. height .. ";" .. tl_name .. ";" - + for i=1, #textlines, 1 do textlines[i] = textlines[i]:gsub("\r","") retval = retval .. core.formspec_escape(textlines[i]) .. "," end - + retval = retval .. ";0;" - + if transparency then retval = retval .. "true" end - + retval = retval .. "]" return retval @@ -275,3 +300,35 @@ function is_server_protocol_compat_or_error(proto_min, proto_max) return true end +-------------------------------------------------------------------------------- +function menu_worldmt(selected, setting, value) + local world = menudata.worldlist:get_list()[selected] + if world then + local filename = world.path .. DIR_DELIM .. "world.mt" + local world_conf = Settings(filename) + + if value ~= nil then + if not world_conf:write() then + core.log("error", "Failed to write world config file") + end + world_conf:set(setting, value) + world_conf:write() + else + return world_conf:get(setting) + end + else + return nil + end +end + +function menu_worldmt_legacy(selected) + local modes_names = {"creative_mode", "enable_damage", "server_announce"} + for _, mode_name in pairs(modes_names) do + local mode_val = menu_worldmt(selected, mode_name) + if mode_val ~= nil then + core.setting_set(mode_name, mode_val) + else + menu_worldmt(selected, mode_name, core.setting_get(mode_name)) + end + end +end diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index d008ec8b0..176796bef 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -139,11 +139,8 @@ local function init_globals() tv_main:add(tab_credits) tv_main:set_global_event_handler(main_event_handler) - if PLATFORM ~= "Android" then - tv_main:set_fixed_size(true) - else - tv_main:set_fixed_size(false) - end + + tv_main:set_fixed_size(false) if not (PLATFORM == "Android") then tv_main:set_tab(core.setting_get("maintab_LAST")) diff --git a/builtin/mainmenu/modmgr.lua b/builtin/mainmenu/modmgr.lua index f2938685e..89292ed52 100644 --- a/builtin/mainmenu/modmgr.lua +++ b/builtin/mainmenu/modmgr.lua @@ -17,7 +17,7 @@ -------------------------------------------------------------------------------- function get_mods(path,retval,modpack) - local mods = core.get_dirlist(path, true) + local mods = core.get_dir_list(path, true) for i=1, #mods, 1 do if mods[i]:sub(1,1) ~= "." then @@ -94,7 +94,7 @@ function modmgr.getbasefolder(temppath) } end - local subdirs = core.get_dirlist(temppath,true) + local subdirs = core.get_dir_list(temppath, true) --only single mod or modpack allowed if #subdirs ~= 1 then @@ -321,8 +321,10 @@ function modmgr.get_worldconfig(worldpath) for key,value in pairs(worldfile:to_table()) do if key == "gameid" then worldconfig.id = value - else + elseif key:sub(0, 9) == "load_mod_" then worldconfig.global_mods[key] = core.is_yes(value) + else + worldconfig[key] = value end end diff --git a/builtin/mainmenu/store.lua b/builtin/mainmenu/store.lua index 999125d6e..ad861082d 100644 --- a/builtin/mainmenu/store.lua +++ b/builtin/mainmenu/store.lua @@ -122,35 +122,36 @@ end function modstore.showdownloading(title) local new_dlg = dialog_create("store_downloading", function(data) - return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") .. - " " .. data.title .. " " .. - fgettext("please wait...") .. "]" + return "size[6,2]label[0.25,0.75;" .. + fgettext("Downloading $1, please wait...", data.title) .. "]" end, function(this,fields) if fields["btn_hidden_close_download"] ~= nil then if fields["btn_hidden_close_download"].successfull then modstore.lastmodentry = fields["btn_hidden_close_download"] - modstore.successfulldialog() + modstore.successfulldialog(this) else + this.parent:show() + this:delete() modstore.lastmodtitle = "" end - this:delete() return true end return false end, - nil, - modstore.tv_store) + nil) + new_dlg:set_parent(modstore.tv_store) + modstore.tv_store:hide() new_dlg.data.title = title new_dlg:show() end -------------------------------------------------------------------------------- -- @function [parent=#modstore] successfulldialog -function modstore.successfulldialog() +function modstore.successfulldialog(downloading_dlg) local new_dlg = dialog_create("store_downloading", function(data) local retval = "" @@ -158,18 +159,16 @@ function modstore.successfulldialog() if modstore.lastmodentry ~= nil then retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]" retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]" - - retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]" retval = retval .. "label[3,0.75;" .. core.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]" - end - retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]" + retval = retval .. "button[2.2,1.5;1.5,0.5;btn_confirm_mod_successfull;" .. fgettext("Ok") .. "]" + return retval end, function(this,fields) if fields["btn_confirm_mod_successfull"] ~= nil then this.parent:show() - this:hide() + downloading_dlg:delete() this:delete() return true @@ -177,10 +176,10 @@ function modstore.successfulldialog() return false end, - nil, - modstore.tv_store) + nil) - new_dlg.data.title = title + new_dlg:set_parent(modstore.tv_store) + modstore.tv_store:hide() new_dlg:show() end @@ -217,7 +216,9 @@ function modstore.handle_buttons(parent, fields, name, data) end if fields["btn_modstore_close"] then + local maintab = ui.find_by_name("maintab") parent:hide() + maintab:show() return true end @@ -228,12 +229,7 @@ function modstore.handle_buttons(parent, fields, name, data) for i=1,#modstore.modlist_unsorted.data,1 do if modstore.modlist_unsorted.data[i].id == modid then local moddetails = modstore.modlist_unsorted.data[i].details - - if modstore.lastmodtitle ~= "" then - modstore.lastmodtitle = modstore.lastmodtitle .. ", " - end - - modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title + modstore.lastmodtitle = moddetails.title if not core.handle_async( function(param) @@ -281,7 +277,7 @@ function modstore.handle_buttons(parent, fields, name, data) texturename = modstore.modlist_unsorted.data[i].texturename }, function(result) - print("Result from async: " .. dump(result.successfull)) + --print("Result from async: " .. dump(result.successfull)) if result.successfull then modmgr.installmod(result.filename,result.moddetails.basename) os.remove(result.filename) @@ -299,7 +295,7 @@ function modstore.handle_buttons(parent, fields, name, data) print("ERROR: async event failed") gamedata.errormessage = "Failed to download " .. modstore.lastmodtitle end - parent:hide() + modstore.showdownloading(modstore.lastmodtitle) return true end diff --git a/builtin/mainmenu/tab_credits.lua b/builtin/mainmenu/tab_credits.lua index 2a7aa26a5..33c84f58f 100644 --- a/builtin/mainmenu/tab_credits.lua +++ b/builtin/mainmenu/tab_credits.lua @@ -25,41 +25,56 @@ tab_credits = { return "label[0.5,3.2;Minetest " .. core.get_version() .. "]" .. "label[0.5,3.5;http://minetest.net]" .. "image[0.5,1;" .. core.formspec_escape(logofile) .. "]" .. - "textlist[3.5,-0.25;8.5,5.8;list_credits;" .. - "#FFFF00" .. fgettext("Core Developers") .."," .. - "Perttu Ahola (celeron55) <celeron55@gmail.com>,".. - "Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,".. - "PilzAdam <pilzadam@minetest.net>," .. - "Lisa Milne (darkrose) <lisa@ltmnet.com>,".. - "Maciej Kasatkin (RealBadAngel) <mk@realbadangel.pl>,".. - "sfan5 <sfan5@live.de>,".. - "kahrl <kahrl@gmx.net>,".. - "sapier,".. - "ShadowNinja <shadowninja@minetest.net>,".. - "Nathanael Courant (Nore/Novatux) <nore@mesecons.net>,".. - "BlockMen,".. - "Craig Robbins (Zeno),".. - ",".. - "#FFFF00" .. fgettext("Active Contributors") .. "," .. - "TriBlade9 <triblade9@mail.com>,".. - "SmallJoker <mk939@ymail.com>,".. - "Zefram <zefram@fysh.org>,".. - "," .. - "#FFFF00" .. fgettext("Previous Contributors") .. "," .. - "Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,".. - "Jurgen Doser (doserj) <jurgen.doser@gmail.com>,".. - "Jeija <jeija@mesecons.net>,".. - "MirceaKitsune <mirceakitsune@gmail.com>,".. - "dannydark <the_skeleton_of_a_child@yahoo.co.uk>,".. - "0gb.us <0gb.us@0gb.us>,".. - "proller <proler@gmail.com>,".. - "Ilya Zhuravlev (xyz) <xyz@minetest.net>,".. - "Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,".. - "Jonathan Neuschafer <j.neuschaefer@gmx.net>,".. - "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,".. - "Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,".. - "matttpt <matttpt@gmail.com>,".. - "JacobF <queatz@gmail.com>,".. - ";0;true]" + "tablecolumns[color;text]" .. + "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. + "table[3.5,-0.25;8.5,5.8;list_credits;" .. + "#FFFF00," .. fgettext("Core Developers") .."," .. + ",Perttu Ahola (celeron55) <celeron55@gmail.com>,".. + ",Ryan Kwolek (kwolekr) <kwolekr@minetest.net>,".. + ",PilzAdam <pilzadam@minetest.net>," .. + ",sfan5 <sfan5@live.de>,".. + ",kahrl <kahrl@gmx.net>,".. + ",sapier,".. + ",ShadowNinja <shadowninja@minetest.net>,".. + ",Nathanael Courant (Nore/Ekdohibs) <nore@mesecons.net>,".. + ",BlockMen,".. + ",Craig Robbins (Zeno),".. + ",Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>,".. + ",Mat Gregory (paramat),".. + ",est31 <MTest31@outlook.com>," .. + ",,".. + "#FFFF00," .. fgettext("Active Contributors") .. "," .. + ",SmallJoker <mk939@ymail.com>," .. + ",Andrew Ward (rubenwardy) <rubenwardy@gmail.com>," .. + ",Aaron Suen <warr1024@gmail.com>," .. + ",Sokomine <wegwerf@anarres.dyndns.org>," .. + ",Břetislav Štec (TeTpaAka)," .. + ",Jean-Patrick G (kilbith) <jeanpatrick.guerrero@gmail.com>," .. + ",Rui <mrrst0914@gmail.com>," .. + ",Diego Martinez (kaeza) <kaeza@users.sf.net>," .. + ",," .. + "#FFFF00," .. fgettext("Previous Core Developers") .."," .. + ",Maciej Kasatkin (RealBadAngel) <maciej.kasatkin@o2.pl>,".. + ",Lisa Milne (darkrose) <lisa@ltmnet.com>," .. + ",proller," .. + ",Ilya Zhuravlev (xyz) <xyz@minetest.net>," .. + ",," .. + "#FFFF00," .. fgettext("Previous Contributors") .. "," .. + ",Vanessa Ezekowitz (VanessaE) <vanessaezekowitz@gmail.com>,".. + ",Jurgen Doser (doserj) <jurgen.doser@gmail.com>,".. + ",Gregory Currie (gregorycu)," .. + ",Jeija <jeija@mesecons.net>,".. + ",MirceaKitsune <mirceakitsune@gmail.com>,".. + ",dannydark <the_skeleton_of_a_child@yahoo.co.uk>,".. + ",0gb.us <0gb.us@0gb.us>,".. + ",Guiseppe Bilotta (Oblomov) <guiseppe.bilotta@gmail.com>,".. + ",Jonathan Neuschafer <j.neuschaefer@gmx.net>,".. + ",Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net>,".. + ",Constantin Wenger (SpeedProg) <constantin.wenger@googlemail.com>,".. + ",matttpt <matttpt@gmail.com>,".. + ",JacobF <queatz@gmail.com>,".. + ",TriBlade9 <triblade9@mail.com>,".. + ",Zefram <zefram@fysh.org>,".. + ";1]" end } diff --git a/builtin/mainmenu/tab_mods.lua b/builtin/mainmenu/tab_mods.lua index 901f14553..2ddc9b07c 100644 --- a/builtin/mainmenu/tab_mods.lua +++ b/builtin/mainmenu/tab_mods.lua @@ -36,7 +36,10 @@ local function get_formspec(tabview, name, tabdata) -- "label[0.8,4.2;" .. fgettext("Add mod:") .. "]" .. -- TODO Disabled due to upcoming release 0.4.8 and irrlicht messing up localization -- "button[0.75,4.85;1.8,0.5;btn_mod_mgr_install_local;".. fgettext("Local install") .. "]" .. - "button[0,4.85;5.25,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]" + +-- TODO Disabled due to service being offline, and not likely to come online again, in this form +-- "button[0,4.85;5.25,0.5;btn_modstore;".. fgettext("Online mod repository") .. "]" + "" local selected_mod = nil diff --git a/builtin/mainmenu/tab_multiplayer.lua b/builtin/mainmenu/tab_multiplayer.lua index f9ac78f17..570259718 100644 --- a/builtin/mainmenu/tab_multiplayer.lua +++ b/builtin/mainmenu/tab_multiplayer.lua @@ -202,8 +202,9 @@ local function main_button_handler(tabview, fields, name, tabdata) return true end - if fields["btn_mp_connect"] ~= nil or - fields["key_enter"] ~= nil then + if (fields["btn_mp_connect"] ~= nil or + fields["key_enter"] ~= nil) and fields["te_address"] ~= nil and + fields["te_port"] ~= nil then gamedata.playername = fields["te_name"] gamedata.password = fields["te_pwd"] diff --git a/builtin/mainmenu/tab_server.lua b/builtin/mainmenu/tab_server.lua index 1ae2a0656..d08eecc21 100644 --- a/builtin/mainmenu/tab_server.lua +++ b/builtin/mainmenu/tab_server.lua @@ -67,6 +67,9 @@ local function main_button_handler(this, fields, name, tabdata) if fields["srv_worlds"] ~= nil then local event = core.explode_textlist_event(fields["srv_worlds"]) + local selected = core.get_textlist_index("srv_worlds") + + menu_worldmt_legacy(selected) if event.type == "DCL" then world_doubleclick = true @@ -84,16 +87,25 @@ local function main_button_handler(this, fields, name, tabdata) if fields["cb_creative_mode"] then core.setting_set("creative_mode", fields["cb_creative_mode"]) + local selected = core.get_textlist_index("srv_worlds") + menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"]) + return true end if fields["cb_enable_damage"] then core.setting_set("enable_damage", fields["cb_enable_damage"]) + local selected = core.get_textlist_index("srv_worlds") + menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"]) + return true end if fields["cb_server_announce"] then core.setting_set("server_announce", fields["cb_server_announce"]) + local selected = core.get_textlist_index("srv_worlds") + menu_worldmt(selected, "server_announce", fields["cb_server_announce"]) + return true end @@ -101,12 +113,12 @@ local function main_button_handler(this, fields, name, tabdata) world_doubleclick or fields["key_enter"] then local selected = core.get_textlist_index("srv_worlds") - if selected ~= nil then + gamedata.selected_world = menudata.worldlist:get_raw_index(selected) + if selected ~= nil and gamedata.selected_world ~= 0 then gamedata.playername = fields["te_playername"] gamedata.password = fields["te_passwd"] gamedata.port = fields["te_serverport"] gamedata.address = "" - gamedata.selected_world = menudata.worldlist:get_raw_index(selected) core.setting_set("port",gamedata.port) if fields["te_serveraddr"] ~= nil then @@ -115,12 +127,17 @@ local function main_button_handler(this, fields, name, tabdata) --update last game local world = menudata.worldlist:get_raw_element(gamedata.selected_world) + if world then + local game, index = gamemgr.find_by_gameid(world.gameid) + core.setting_set("menu_last_game", game.id) + end - local game,index = gamemgr.find_by_gameid(world.gameid) - core.setting_set("menu_last_game",game.id) core.start() - return true + else + gamedata.errormessage = + fgettext("No world created or selected!") end + return true end if fields["world_create"] ~= nil then diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua index 881a63498..c17a39432 100644 --- a/builtin/mainmenu/tab_settings.lua +++ b/builtin/mainmenu/tab_settings.lua @@ -17,6 +17,17 @@ -------------------------------------------------------------------------------- +local leaves_style_labels = { + fgettext("Opaque Leaves"), + fgettext("Simple Leaves"), + fgettext("Fancy Leaves") +} + +local leaves_style = { + {leaves_style_labels[1]..","..leaves_style_labels[2]..","..leaves_style_labels[3]}, + {"opaque", "simple", "fancy"}, +} + local dd_filter_labels = { fgettext("No Filter"), fgettext("Bilinear Filter"), @@ -39,6 +50,29 @@ local mipmap = { {"", "mip_map", "anisotropic_filter"}, } +local function getLeavesStyleSettingIndex() + local style = core.setting_get("leaves_style") + if (style == leaves_style[2][3]) then + return 3 + elseif (style == leaves_style[2][2]) then + return 2 + end + return 1 +end + +local dd_antialiasing_labels = { + fgettext("None"), + fgettext("2x"), + fgettext("4x"), + fgettext("8x"), +} + +local antialiasing = { + {dd_antialiasing_labels[1]..","..dd_antialiasing_labels[2]..",".. + dd_antialiasing_labels[3]..","..dd_antialiasing_labels[4]}, + {"0", "2", "4", "8"} +} + local function getFilterSettingIndex() if (core.setting_get(filters[2][3]) == "true") then return 3 @@ -59,16 +93,23 @@ local function getMipmapSettingIndex() return 1 end -local function video_driver_fname_to_name(selected_driver) - local video_drivers = core.get_video_drivers() - - for i=1, #video_drivers do - if selected_driver == video_drivers[i].friendly_name then - return video_drivers[i].name:lower() +local function getAntialiasingSettingIndex() + local antialiasing_setting = core.setting_get("fsaa") + for i = 1, #(antialiasing[2]) do + if antialiasing_setting == antialiasing[2][i] then + return i end end + return 1 +end - return "" +local function antialiasing_fname_to_name(fname) + for i = 1, #(dd_antialiasing_labels) do + if fname == dd_antialiasing_labels[i] then + return antialiasing[2][i] + end + end + return 0 end local function dlg_confirm_reset_formspec(data) @@ -159,50 +200,31 @@ local function scrollbar_to_gui_scale(value) end local function formspec(tabview, name, tabdata) - local video_drivers = core.get_video_drivers() - local current_video_driver = core.setting_get("video_driver"):lower() - - local driver_formspec_string = "" - local driver_current_idx = 0 - - for i=2, #video_drivers do - driver_formspec_string = driver_formspec_string .. video_drivers[i].friendly_name - if i ~= #video_drivers then - driver_formspec_string = driver_formspec_string .. "," - end - - if current_video_driver == video_drivers[i].name:lower() then - driver_current_idx = i - 1 - end - end - local tab_string = - "box[0,0;3.5,3.9;#999999]" .. + "box[0,0;3.5,4.0;#999999]" .. "checkbox[0.25,0;cb_smooth_lighting;".. fgettext("Smooth Lighting") .. ";".. dump(core.setting_getbool("smooth_lighting")) .. "]".. "checkbox[0.25,0.5;cb_particles;".. fgettext("Enable Particles") .. ";" .. dump(core.setting_getbool("enable_particles")) .. "]".. "checkbox[0.25,1;cb_3d_clouds;".. fgettext("3D Clouds") .. ";" .. dump(core.setting_getbool("enable_3d_clouds")) .. "]".. - "checkbox[0.25,1.5;cb_fancy_trees;".. fgettext("Fancy Trees") .. ";" - .. dump(core.setting_getbool("new_style_leaves")) .. "]".. - "checkbox[0.25,2.0;cb_opaque_water;".. fgettext("Opaque Water") .. ";" + "checkbox[0.25,1.5;cb_opaque_water;".. fgettext("Opaque Water") .. ";" .. dump(core.setting_getbool("opaque_water")) .. "]".. - "checkbox[0.25,2.5;cb_connected_glass;".. fgettext("Connected Glass") .. ";" + "checkbox[0.25,2.0;cb_connected_glass;".. fgettext("Connected Glass") .. ";" .. dump(core.setting_getbool("connected_glass")) .. "]".. - "checkbox[0.25,3.0;cb_node_highlighting;".. fgettext("Node Highlighting") .. ";" + "checkbox[0.25,2.5;cb_node_highlighting;".. fgettext("Node Highlighting") .. ";" .. dump(core.setting_getbool("enable_node_highlighting")) .. "]".. + "dropdown[0.25,3.2;3.3;dd_leaves_style;" .. leaves_style[1][1] .. ";" + .. getLeavesStyleSettingIndex() .. "]" .. "box[3.75,0;3.75,3.45;#999999]" .. "label[3.85,0.1;".. fgettext("Texturing:") .. "]".. "dropdown[3.85,0.55;3.85;dd_filters;" .. filters[1][1] .. ";" .. getFilterSettingIndex() .. "]" .. "dropdown[3.85,1.35;3.85;dd_mipmap;" .. mipmap[1][1] .. ";" .. getMipmapSettingIndex() .. "]" .. - "label[3.85,2.15;".. fgettext("Rendering:") .. "]".. - "dropdown[3.85,2.6;3.85;dd_video_driver;" - .. driver_formspec_string .. ";" .. driver_current_idx .. "]" .. - "tooltip[dd_video_driver;" .. - fgettext("Restart minetest for driver change to take effect") .. "]" .. + "label[3.85,2.15;".. fgettext("Antialiasing:") .. "]".. + "dropdown[3.85,2.6;3.85;dd_antialiasing;" .. antialiasing[1][1] .. ";" + .. getAntialiasingSettingIndex() .. "]" .. "box[7.75,0;4,4;#999999]" .. "checkbox[8,0;cb_shaders;".. fgettext("Shaders") .. ";" .. dump(core.setting_getbool("enable_shaders")) .. "]" @@ -353,10 +375,16 @@ local function handle_settings_buttons(this, fields, tabname, tabdata) core.setting_set("touchscreen_threshold",fields["dd_touchthreshold"]) ddhandled = true end - - if fields["dd_video_driver"] then - core.setting_set("video_driver", - video_driver_fname_to_name(fields["dd_video_driver"])) + if fields["dd_leaves_style"] == leaves_style_labels[3] then + core.setting_set("leaves_style", leaves_style[2][3]) + ddhandled = true + end + if fields["dd_leaves_style"] == leaves_style_labels[2] then + core.setting_set("leaves_style", leaves_style[2][2]) + ddhandled = true + end + if fields["dd_leaves_style"] == leaves_style_labels[1] then + core.setting_set("leaves_style", leaves_style[2][1]) ddhandled = true end if fields["dd_filters"] == dd_filter_labels[1] then @@ -389,6 +417,11 @@ local function handle_settings_buttons(this, fields, tabname, tabdata) core.setting_set("anisotropic_filter", "true") ddhandled = true end + if fields["dd_antialiasing"] then + core.setting_set("fsaa", + antialiasing_fname_to_name(fields["dd_antialiasing"])) + ddhandled = true + end return ddhandled end diff --git a/builtin/mainmenu/tab_simple_main.lua b/builtin/mainmenu/tab_simple_main.lua index 995c72132..434113b5f 100644 --- a/builtin/mainmenu/tab_simple_main.lua +++ b/builtin/mainmenu/tab_simple_main.lua @@ -69,20 +69,18 @@ local function get_formspec(tabview, name, tabdata) -- separator retval = retval .. - "box[-0.3,3.75;12.4,0.1;#FFFFFF]" + "box[-0.28,3.75;12.4,0.1;#FFFFFF]" -- checkboxes retval = retval .. - "checkbox[1.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" .. + "checkbox[8.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" .. dump(core.setting_getbool("creative_mode")) .. "]".. - "checkbox[5.0,3.9;cb_damage;".. fgettext("Enable Damage") .. ";" .. - dump(core.setting_getbool("enable_damage")) .. "]" .. - "checkbox[8,3.9;cb_fly_mode;".. fgettext("Fly mode") .. ";" .. - dump(core.setting_getbool("free_move")) .. "]" + "checkbox[8.0,4.4;cb_damage;".. fgettext("Enable Damage") .. ";" .. + dump(core.setting_getbool("enable_damage")) .. "]" -- buttons retval = retval .. - "button[2.0,4.5;6,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]" .. - "button[8.25,4.5;2.5,1.5;btn_config_sp_world;" .. fgettext("Config mods") .. "]" + "button[0,3.7;8,1.5;btn_start_singleplayer;" .. fgettext("Start Singleplayer") .. "]" .. + "button[0,4.5;8,1.5;btn_config_sp_world;" .. fgettext("Config mods") .. "]" return retval end @@ -138,11 +136,6 @@ local function main_button_handler(tabview, fields, name, tabdata) return true end - if fields["cb_fly_mode"] then - core.setting_set("free_move", fields["cb_fly_mode"]) - return true - end - if fields["btn_mp_connect"] ~= nil or fields["key_enter"] ~= nil then diff --git a/builtin/mainmenu/tab_singleplayer.lua b/builtin/mainmenu/tab_singleplayer.lua index 9dc377a8f..a40918af9 100644 --- a/builtin/mainmenu/tab_singleplayer.lua +++ b/builtin/mainmenu/tab_singleplayer.lua @@ -23,9 +23,9 @@ local function current_game() end local function singleplayer_refresh_gamebar() - + local old_bar = ui.find_by_name("game_button_bar") - + if old_bar ~= nil then old_bar:delete() end @@ -38,6 +38,17 @@ local function singleplayer_refresh_gamebar() core.set_topleft_text(gamemgr.games[j].name) core.setting_set("menu_last_game",gamemgr.games[j].id) menudata.worldlist:set_filtercriteria(gamemgr.games[j].id) + local index = filterlist.get_current_index(menudata.worldlist, + tonumber(core.setting_get("mainmenu_last_selected_world"))) + if not index or index < 1 then + local selected = core.get_textlist_index("sp_worlds") + if selected ~= nil and selected < #menudata.worldlist:get_list() then + index = selected + else + index = #menudata.worldlist:get_list() + end + end + menu_worldmt_legacy(index) return true end end @@ -76,7 +87,7 @@ end local function get_formspec(tabview, name, tabdata) local retval = "" - + local index = filterlist.get_current_index(menudata.worldlist, tonumber(core.setting_get("mainmenu_last_selected_world")) ) @@ -105,14 +116,17 @@ local function main_button_handler(this, fields, name, tabdata) if fields["sp_worlds"] ~= nil then local event = core.explode_textlist_event(fields["sp_worlds"]) + local selected = core.get_textlist_index("sp_worlds") + + menu_worldmt_legacy(selected) if event.type == "DCL" then world_doubleclick = true end - if event.type == "CHG" then + if event.type == "CHG" and selected ~= nil then core.setting_set("mainmenu_last_selected_world", - menudata.worldlist:get_raw_index(core.get_textlist_index("sp_worlds"))) + menudata.worldlist:get_raw_index(selected)) return true end end @@ -123,11 +137,17 @@ local function main_button_handler(this, fields, name, tabdata) if fields["cb_creative_mode"] then core.setting_set("creative_mode", fields["cb_creative_mode"]) + local selected = core.get_textlist_index("sp_worlds") + menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"]) + return true end if fields["cb_enable_damage"] then core.setting_set("enable_damage", fields["cb_enable_damage"]) + local selected = core.get_textlist_index("sp_worlds") + menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"]) + return true end @@ -135,12 +155,14 @@ local function main_button_handler(this, fields, name, tabdata) world_doubleclick or fields["key_enter"] then local selected = core.get_textlist_index("sp_worlds") + gamedata.selected_world = menudata.worldlist:get_raw_index(selected) - if selected ~= nil then - gamedata.selected_world = menudata.worldlist:get_raw_index(selected) - gamedata.singleplayer = true - + if selected ~= nil and gamedata.selected_world ~= 0 then + gamedata.singleplayer = true core.start() + else + gamedata.errormessage = + fgettext("No world created or selected!") end return true end diff --git a/builtin/mainmenu/tab_texturepacks.lua b/builtin/mainmenu/tab_texturepacks.lua index d32c073ab..3fb7b8598 100644 --- a/builtin/mainmenu/tab_texturepacks.lua +++ b/builtin/mainmenu/tab_texturepacks.lua @@ -45,12 +45,12 @@ end -------------------------------------------------------------------------------- local function get_formspec(tabview, name, tabdata) - + local retval = "label[4,-0.25;".. fgettext("Select texture pack:") .. "]".. "textlist[4,0.25;7.5,5.0;TPs;" local current_texture_path = core.setting_get("texture_path") - local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true)) + local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true)) local index = tonumber(core.setting_get("mainmenu_last_selected_TP")) if index == nil then index = 1 end @@ -62,10 +62,18 @@ local function get_formspec(tabview, name, tabdata) return retval end - local infofile = current_texture_path ..DIR_DELIM.."info.txt" + local infofile = current_texture_path ..DIR_DELIM.."description.txt" + -- This adds backwards compatibility for old texture pack description files named + -- "info.txt", and should be removed once all such texture packs have been updated + if not file_exists(infofile) then + infofile = current_texture_path ..DIR_DELIM.."info.txt" + if file_exists(infofile) then + minetest.log("info.txt is depreciated. description.txt should be used instead."); + end + end local infotext = "" local f = io.open(infofile, "r") - if f==nil then + if not f then infotext = fgettext("No information available") else infotext = f:read("*all") @@ -94,7 +102,7 @@ local function main_button_handler(tabview, fields, name, tabdata) local index = core.get_textlist_index("TPs") core.setting_set("mainmenu_last_selected_TP", index) - local list = filter_texture_pack_list(core.get_dirlist(core.get_texturepath(), true)) + local list = filter_texture_pack_list(core.get_dir_list(core.get_texturepath(), true)) local current_index = core.get_textlist_index("TPs") if current_index ~= nil and #list >= current_index then local new_path = core.get_texturepath()..DIR_DELIM..list[current_index] diff --git a/builtin/mainmenu/textures.lua b/builtin/mainmenu/textures.lua index 56992c0c5..075f38ee0 100644 --- a/builtin/mainmenu/textures.lua +++ b/builtin/mainmenu/textures.lua @@ -129,7 +129,7 @@ function mm_texture.set_generic(identifier) end -------------------------------------------------------------------------------- -function mm_texture.set_game(identifier,gamedetails) +function mm_texture.set_game(identifier, gamedetails) if gamedetails == nil then return false @@ -137,15 +137,34 @@ function mm_texture.set_game(identifier,gamedetails) if mm_texture.texturepack ~= nil then local path = mm_texture.texturepack .. DIR_DELIM .. - gamedetails.id .. "_menu_" .. identifier .. ".png" - if core.set_background(identifier,path) then + gamedetails.id .. "_menu_" .. identifier .. ".png" + if core.set_background(identifier, path) then return true end end - local path = gamedetails.path .. DIR_DELIM .."menu" .. - DIR_DELIM .. identifier .. ".png" - if core.set_background(identifier,path) then + -- Find out how many randomized textures the subgame provides + local n = 0 + local filename + local menu_files = core.get_dir_list(gamedetails.path .. DIR_DELIM .. "menu", false) + for i = 1, #menu_files do + filename = identifier .. "." .. i .. ".png" + if table.indexof(menu_files, filename) == -1 then + n = i - 1 + break + end + end + -- Select random texture, 0 means standard texture + n = math.random(0, n) + if n == 0 then + filename = identifier .. ".png" + else + filename = identifier .. "." .. n .. ".png" + end + + local path = gamedetails.path .. DIR_DELIM .. "menu" .. + DIR_DELIM .. filename + if core.set_background(identifier, path) then return true end |