diff --git a/builtin/fstk/buttonbar.lua b/builtin/fstk/buttonbar.lua index eed16090d..465588324 100644 --- a/builtin/fstk/buttonbar.lua +++ b/builtin/fstk/buttonbar.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/fstk/dialog.lua b/builtin/fstk/dialog.lua index b4c93603f..df887f413 100644 --- a/builtin/fstk/dialog.lua +++ b/builtin/fstk/dialog.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --this program is distributed in the hope that it will be useful, diff --git a/builtin/fstk/tabview.lua b/builtin/fstk/tabview.lua index 3a02794ac..274f404af 100644 --- a/builtin/fstk/tabview.lua +++ b/builtin/fstk/tabview.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -30,7 +30,7 @@ local function add_tab(self,tab) assert(tab.size == nil or (type(tab.size) == table and tab.size.x ~= nil and tab.size.y ~= nil)) - assert(tab.cbf_formspec ~= nil and type(tab.cbf_formspec) == "function") + assert(tab.show or tab.cbf_formspec ~= nil and type(tab.cbf_formspec) == "function") assert(tab.cbf_button_handler == nil or type(tab.cbf_button_handler) == "function") assert(tab.cbf_events == nil or type(tab.cbf_events) == "function") @@ -38,6 +38,7 @@ local function add_tab(self,tab) local newtab = { name = tab.name, caption = tab.caption, + show = tab.show, button_handler = tab.cbf_button_handler, event_handler = tab.cbf_events, get_formspec = tab.cbf_formspec, @@ -56,37 +57,29 @@ local function add_tab(self,tab) end end -local function get_bg(tsize, tabname) - tabname = tabname or "common" - return "background[0,0;" .. tsize.width .. "," .. tsize.height .. ";" .. - core.formspec_escape(defaulttexturedir .. - "bg_" .. tabname .. ".png") .. ";true]" -end - -------------------------------------------------------------------------------- local function get_formspec(self) local formspec = "" - local name = self.tablist[self.last_tab_index].name - local tabname = name == "local" and name or name == "online" and name or nil if not self.hidden and (self.parent == nil or not self.parent.hidden) then + if self.parent == nil then local tsize = self.tablist[self.last_tab_index].tabsize or {width=self.width, height=self.height} - formspec = formspec .. - string.format("size[%f,%f,%s]",tsize.width,tsize.height, - dump(self.fixed_size)) - - formspec = formspec .. get_bg(tsize, tabname) + string.format("size[%f,%f,%s]real_coordinates[true]",tsize.width+3,tsize.height, + dump(self.fixed_size)) end formspec = formspec .. self:tab_header() + formspec = formspec .. "container[3,0]" formspec = formspec .. self.tablist[self.last_tab_index].get_formspec( - self, name, + self, + self.tablist[self.last_tab_index].name, self.tablist[self.last_tab_index].tabdata, self.tablist[self.last_tab_index].tabsize ) + formspec = formspec .. "container_end[]" end return formspec end @@ -149,51 +142,66 @@ end -------------------------------------------------------------------------------- local function tab_header(self) - local toadd = "" + local tsize = self.tablist[self.last_tab_index].tabsize or + {width=self.width, height=self.height} - for i=1,#self.tablist,1 do + local fs = { + ("box[%f,%f;%f,%f;%s]"):format(0, 0, 2.5, tsize.height, self.bgcolor) + } - if toadd ~= "" then - toadd = toadd .. "," - end + for i = 1, #self.tablist do + local tab = self.tablist[i] + local name = "tab_" .. tab.name + local y = (i - 1) * 0.8 + 0.50 + + fs[#fs + 1] = "button[0.10," + fs[#fs + 1] = tonumber(y - 0.4 ) + fs[#fs + 1] = ";2.5,1;" + fs[#fs + 1] = name + fs[#fs + 1] = ";"..tab.caption.."]" - toadd = toadd .. self.tablist[i].caption + end - return string.format("tabheader[%f,%f;%s;%s;%i;true;false]", - self.header_x, self.header_y, self.name, toadd, self.last_tab_index); + + return table.concat(fs, "") + end -------------------------------------------------------------------------------- local function switch_to_tab(self, index) - --first call on_change for tab to leave - if self.tablist[self.last_tab_index].on_change ~= nil then - self.tablist[self.last_tab_index].on_change("LEAVE", - self.current_tab, self.tablist[index].name) + local old_tab = self.tablist[self.last_tab_index] + local new_tab = self.tablist[index] + + if old_tab and old_tab.on_change ~= nil then + old_tab.on_change("LEAVE", self.current_tab, new_tab.name) + end + + if new_tab.show then + new_tab.show(old_tab.name, new_tab.name, self) + return end --update tabview data self.last_tab_index = index - local old_tab = self.current_tab - self.current_tab = self.tablist[index].name + self.current_tab = new_tab.name - if (self.autosave_tab) then - core.settings:set(self.name .. "_LAST",self.current_tab) + if self.autosave_tab then + core.settings:set(self.name .. "_LAST", self.current_tab) end - -- call for tab to enter - if self.tablist[index].on_change ~= nil then - self.tablist[index].on_change("ENTER", - old_tab,self.current_tab) + if new_tab.on_change ~= nil then + new_tab.on_change("ENTER", old_tab, self.current_tab) end end -------------------------------------------------------------------------------- -local function handle_tab_buttons(self,fields) - --save tab selection to config file - if fields[self.name] then - local index = tonumber(fields[self.name]) - switch_to_tab(self, index) - return true +local function handle_tab_buttons(self, fields) + for i = 1, #self.tablist do + local tab = self.tablist[i] + if fields["tab_" .. tab.name] then + switch_to_tab(self, i) + return true + end end return false @@ -267,6 +275,8 @@ function tabview_create(name, size, tabheaderpos) self.height = size.y self.header_x = tabheaderpos.x self.header_y = tabheaderpos.y + self.bgcolor = "#8b98a9" + self.selcolor = "#53AC56CC" setmetatable(self, tabview_metatable) @@ -280,4 +290,4 @@ function tabview_create(name, size, tabheaderpos) ui.add(self) return self -end +end \ No newline at end of file diff --git a/builtin/fstk/textures/gui_hotbar_selected.png b/builtin/fstk/textures/gui_hotbar_selected.png new file mode 100644 index 000000000..bc2601146 Binary files /dev/null and b/builtin/fstk/textures/gui_hotbar_selected.png differ diff --git a/builtin/fstk/ui.lua b/builtin/fstk/ui.lua index f6b70e4da..3ac0386ca 100644 --- a/builtin/fstk/ui.lua +++ b/builtin/fstk/ui.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -79,25 +79,6 @@ end -------------------------------------------------------------------------------- function ui.update() local formspec = "" - local restart_btn - - -- attempt auto restart - if gamedata ~= nil and gamedata.errormessage ~= nil and - core.settings:get_bool("auto_connect") == true and - tonumber(core.settings:get("connect_time")) < os.time() - 30 --[[and - not string.find(gamedata.errormessage, "Access denied")]] then - if core.settings:get("maintab_LAST") == "local" then - gamedata.singleplayer = true - gamedata.selected_world = - tonumber(core.settings:get("mainmenu_last_selected_world")) - end - core.settings:set("connect_time", os.time()) - gamedata.reconnect_requested = false - gamedata.errormessage = nil - gamedata.do_reconnect = true - core.start() - return - end -- handle errors if gamedata ~= nil and gamedata.reconnect_requested then @@ -105,7 +86,7 @@ function ui.update() 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("Close") .. "]" .. + "]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) @@ -115,17 +96,10 @@ function ui.update() else error_title = fgettext("An error occured:") end - if core.settings:get("maintab_LAST") == "local" and - tonumber(core.settings:get("connect_time")) < os.time() - 30 then - restart_btn = "]button[6,4.6;3,0.5;btn_reconnect_no;" .. fgettext("Close") .. "]" .. - "button[3,4.6;3,0.5;btn_reconnect_yes;" .. fgettext("Restart") .. "]" - else - restart_btn = "]button[4.5,4.6;3,0.5;btn_error_confirm;" .. fgettext("Close") .. "]" - end formspec = "size[12,5]" .. "label[0.5,0;" .. error_title .. "]textlist[0.2,0.8;11.5,3.5;;" .. formspec .. - restart_btn + "]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 @@ -203,12 +177,6 @@ end -------------------------------------------------------------------------------- core.button_handler = function(fields) if fields["btn_reconnect_yes"] then - if core.settings:get("maintab_LAST") == "local" then - gamedata.singleplayer = true - gamedata.selected_world = - tonumber(core.settings:get("mainmenu_last_selected_world")) - end - core.settings:set("connect_time", os.time()) gamedata.reconnect_requested = false gamedata.errormessage = nil gamedata.do_reconnect = true diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua index 6fadb95cb..7eb941775 100644 --- a/builtin/mainmenu/common.lua +++ b/builtin/mainmenu/common.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -35,7 +35,7 @@ common_update_cached_supp_proto() -------------------------------------------------------------------------------- local function render_client_count(n) - if n > 999 then return '999' + if n > 99 then return '99+' elseif n >= 0 then return tostring(n) else return '?' end end @@ -54,16 +54,12 @@ end function image_column(tooltip, flagname) return "image,tooltip=" .. core.formspec_escape(tooltip) .. "," .. "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," .. - "1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_favorite.png") .. "," .. - "2=" .. core.formspec_escape(defaulttexturedir .. "server_flags_mc.png") .. "," .. - "3=" .. core.formspec_escape(defaulttexturedir .. "server_flags_mt.png") .. "," .. - "4=" .. core.formspec_escape(defaulttexturedir .. "server_flags_damage.png") .. "," .. - "5=" .. core.formspec_escape(defaulttexturedir .. "server_flags_creative.png") .. "," .. - "6=" .. core.formspec_escape(defaulttexturedir .. "server_flags_pvp.png") .. "," .. - "14=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," .. - "13=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," .. - "12=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," .. - "11=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png") + "1=" .. core.formspec_escape(defaulttexturedir .. + (flagname and "server_flags_" .. flagname .. ".png" or "blank.png")) .. "," .. + "2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," .. + "3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," .. + "4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," .. + "5=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png") end -------------------------------------------------------------------------------- @@ -86,7 +82,7 @@ function order_favorite_list(list) end -------------------------------------------------------------------------------- -function render_serverlist_row(spec, is_favorite, is_approved) +function render_serverlist_row(spec, is_favorite) local text = "" if spec.name then text = text .. core.formspec_escape(spec.name:trim()) @@ -103,23 +99,19 @@ function render_serverlist_row(spec, is_favorite, is_approved) if is_favorite then details = "1," else - if is_approved then - details = "2," - else - details = "3," - end + details = "0," end if spec.ping then local ping = spec.ping * 1000 if ping <= 50 then - details = details .. "14," + details = details .. "2," elseif ping <= 100 then - details = details .. "13," + details = details .. "3," elseif ping <= 250 then - details = details .. "12," + details = details .. "4," else - details = details .. "11," + details = details .. "5," end else details = details .. "0," @@ -136,7 +128,7 @@ function render_serverlist_row(spec, is_favorite, is_approved) elseif clients_percent <= 60 then clients_color = '#a1e587' -- 0-60%: green elseif clients_percent <= 90 then clients_color = '#ffdc97' -- 60-90%: yellow elseif clients_percent == 100 then clients_color = '#dd5b5b' -- full server: red (darker) - else clients_color = '#ffba97' -- 90-100%: orange + else clients_color = '#ffba97' -- 90-100%: orange end details = details .. clients_color .. ',' .. @@ -149,14 +141,20 @@ function render_serverlist_row(spec, is_favorite, is_approved) details = details .. ',?,/,?,' end - if spec.damage then - details = details .. "4," + if spec.creative then + details = details .. "1," else - details = details .. "5," + details = details .. "0," + end + + if spec.damage then + details = details .. "1," + else + details = details .. "0," end if spec.pvp then - details = details .. "6," + details = details .. "1," else details = details .. "0," end @@ -191,7 +189,8 @@ function menu_render_worldlist() for i, v in ipairs(current_worldlist) do if retval ~= "" then retval = retval .. "," end - retval = retval .. core.formspec_escape(v.name) .. "" + retval = retval .. core.formspec_escape(v.name) .. + " \\[" .. core.formspec_escape(v.gameid) .. "\\]" end return retval diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua index b0524fff5..fcedadea8 100644 --- a/builtin/mainmenu/dlg_config_world.lua +++ b/builtin/mainmenu/dlg_config_world.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua new file mode 100644 index 000000000..568d37ee6 --- /dev/null +++ b/builtin/mainmenu/dlg_contentstore.lua @@ -0,0 +1,604 @@ +--Minetest +--Copyright (C) 2018 rubenwardy +-- +--This program is free software; you can redistribute it and/or modify +--it under the terms of the GNU Lesser General Public License as published by +--the Free Software Foundation; either version 2.1 of the License, or +--(at your option) any later version. +-- +--This program is distributed in the hope that it will be useful, +--but WITHOUT ANY WARRANTY; without even the implied warranty of +--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--GNU Lesser General Public License for more details. +-- +--You should have received a copy of the GNU Lesser General Public License along +--with this program; if not, write to the Free Software Foundation, Inc., +--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +local store = { packages = {}, packages_full = {} } +local package_dialog = {} + +-- Screenshot +local screenshot_dir = core.get_cache_path() .. DIR_DELIM .. "cdb" +assert(core.create_dir(screenshot_dir)) +local screenshot_downloading = {} +local screenshot_downloaded = {} + +-- Filter +local search_string = "" +local cur_page = 1 +local num_per_page = 5 +local filter_type = 1 +local filter_types_titles = { + fgettext("All packages"), + fgettext("Games"), + fgettext("Mods"), + fgettext("Texture packs"), +} + +local filter_types_type = { + nil, + "game", + "mod", + "txp", +} + + + + +local function download_package(param) + if core.download_file(param.package.url, param.filename) then + return { + package = param.package, + filename = param.filename, + successful = true, + } + else + core.log("error", "downloading " .. dump(param.package.url) .. " failed") + return { + package = param.package, + successful = false, + } + end +end + +local function start_install(calling_dialog, package) + local params = { + package = package, + filename = os.tempfolder() .. "_MODNAME_" .. package.name .. ".zip", + } + + local function callback(result) + if result.successful then + local path, msg = pkgmgr.install(result.package.type, + result.filename, result.package.name, + result.package.path) + if not path then + gamedata.errormessage = msg + else + core.log("action", "Installed package to " .. path) + + local conf_path + local name_is_title = false + if result.package.type == "mod" then + local actual_type = pkgmgr.get_folder_type(path) + if actual_type.type == "modpack" then + conf_path = path .. DIR_DELIM .. "modpack.conf" + else + conf_path = path .. DIR_DELIM .. "mod.conf" + end + elseif result.package.type == "game" then + conf_path = path .. DIR_DELIM .. "game.conf" + name_is_title = true + elseif result.package.type == "txp" then + conf_path = path .. DIR_DELIM .. "texture_pack.conf" + end + + if conf_path then + local conf = Settings(conf_path) + if name_is_title then + conf:set("name", result.package.title) + else + conf:set("title", result.package.title) + conf:set("name", result.package.name) + end + if not conf:get("description") then + conf:set("description", result.package.short_description) + end + conf:set("author", result.package.author) + conf:set("release", result.package.release) + conf:write() + end + end + os.remove(result.filename) + else + gamedata.errormessage = fgettext("Failed to download $1", package.name) + end + + if gamedata.errormessage == nil then + core.button_handler({btn_hidden_close_download=result}) + else + core.button_handler({btn_hidden_close_download={successful=false}}) + end + end + + if not core.handle_async(download_package, params, callback) then + core.log("error", "ERROR: async event failed") + gamedata.errormessage = fgettext("Failed to download $1", package.name) + end + + local new_dlg = dialog_create("store_downloading", + function(data) + return "size[7,2]label[0.25,0.75;" .. + fgettext("Downloading and installing $1, please wait...", data.title) .. "]" + end, + function(this,fields) + if fields["btn_hidden_close_download"] ~= nil then + this:delete() + return true + end + + return false + end, + nil) + + new_dlg:set_parent(calling_dialog) + new_dlg.data.title = package.title + calling_dialog:hide() + new_dlg:show() +end + +local function get_screenshot(package) + if not package.thumbnail then + return defaulttexturedir .. "no_screenshot.png" + elseif screenshot_downloading[package.thumbnail] then + return defaulttexturedir .. "loading_screenshot.png" + end + + -- Get tmp screenshot path + local filepath = screenshot_dir .. DIR_DELIM .. + package.type .. "-" .. package.author .. "-" .. package.name .. ".png" + + -- Return if already downloaded + local file = io.open(filepath, "r") + if file then + file:close() + return filepath + end + + -- Show error if we've failed to download before + if screenshot_downloaded[package.thumbnail] then + return defaulttexturedir .. "error_screenshot.png" + end + + -- Download + + local function download_screenshot(params) + return core.download_file(params.url, params.dest) + end + local function callback(success) + screenshot_downloading[package.thumbnail] = nil + screenshot_downloaded[package.thumbnail] = true + if not success then + core.log("warning", "Screenshot download failed for some reason") + end + ui.update() + end + if core.handle_async(download_screenshot, + { dest = filepath, url = package.thumbnail }, callback) then + screenshot_downloading[package.thumbnail] = true + else + core.log("error", "ERROR: async event failed") + return defaulttexturedir .. "error_screenshot.png" + end + + return defaulttexturedir .. "loading_screenshot.png" +end + + + +function package_dialog.get_formspec() + local package = package_dialog.package + + store.update_paths() + + local formspec = { + "size[9,4;true]", + "image[0,1;4.5,3;", core.formspec_escape(get_screenshot(package)), ']', + "label[3.8,1;", + minetest.colorize(mt_color_green, core.formspec_escape(package.title)), "\n", + minetest.colorize('#BFBFBF', "by " .. core.formspec_escape(package.author)), "]", + "textarea[4,2;5.3,2;;;", core.formspec_escape(package.short_description), "]", + "button[0,0;2,1;back;", fgettext("Back"), "]", + } + + if not package.path then + formspec[#formspec + 1] = "button[7,0;2,1;install;" + formspec[#formspec + 1] = fgettext("Install") + formspec[#formspec + 1] = "]" + elseif package.installed_release < package.release then + -- The install_ action also handles updating + formspec[#formspec + 1] = "button[7,0;2,1;install;" + formspec[#formspec + 1] = fgettext("Update") + formspec[#formspec + 1] = "]" + formspec[#formspec + 1] = "button[5,0;2,1;uninstall;" + formspec[#formspec + 1] = fgettext("Uninstall") + formspec[#formspec + 1] = "]" + else + formspec[#formspec + 1] = "button[7,0;2,1;uninstall;" + formspec[#formspec + 1] = fgettext("Uninstall") + formspec[#formspec + 1] = "]" + end + + return table.concat(formspec, "") +end + +function package_dialog.handle_submit(this, fields) + if fields.back then + this:delete() + return true + end + + if fields.install then + start_install(this, package_dialog.package) + return true + end + + if fields.uninstall then + local dlg_delmod = create_delete_content_dlg(package_dialog.package) + dlg_delmod:set_parent(this) + this:hide() + dlg_delmod:show() + return true + end + + return false +end + +function package_dialog.create(package) + package_dialog.package = package + return dialog_create("package_view", + package_dialog.get_formspec, + package_dialog.handle_submit, + nil) +end + +function store.load() + local tmpdir = os.tempfolder() + local target = tmpdir .. DIR_DELIM .. "packages.json" + + assert(core.create_dir(tmpdir)) + + local base_url = core.settings:get("contentdb_url") + local show_nonfree = core.settings:get_bool("show_nonfree_packages") + local url = base_url .. + "/api/packages/?type=mod&type=game&type=txp&protocol_version=" .. + core.get_max_supp_proto() + + for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do + item = item:trim() + if item ~= "" then + url = url .. "&hide=" .. item + end + end + + core.download_file(url, target) + + local file = io.open(target, "r") + if file then + store.packages_full = core.parse_json(file:read("*all")) or {} + file:close() + + for _, package in pairs(store.packages_full) do + package.url = base_url .. "/packages/" .. + package.author .. "/" .. package.name .. + "/releases/" .. package.release .. "/download/" + + local name_len = #package.name + if package.type == "game" and name_len > 5 and package.name:sub(name_len - 4) == "_game" then + package.id = package.author:lower() .. "/" .. package.name:sub(1, name_len - 5) + else + package.id = package.author:lower() .. "/" .. package.name + end + end + + store.packages = store.packages_full + store.loaded = true + end + + core.delete_dir(tmpdir) +end + +function store.update_paths() + local mod_hash = {} + pkgmgr.refresh_globals() + for _, mod in pairs(pkgmgr.global_mods:get_list()) do + if mod.author then + mod_hash[mod.author:lower() .. "/" .. mod.name] = mod + end + end + + local game_hash = {} + pkgmgr.update_gamelist() + for _, game in pairs(pkgmgr.games) do + if game.author ~= "" then + game_hash[game.author:lower() .. "/" .. game.id] = game + end + end + + local txp_hash = {} + for _, txp in pairs(pkgmgr.get_texture_packs()) do + if txp.author then + txp_hash[txp.author:lower() .. "/" .. txp.name] = txp + end + end + + for _, package in pairs(store.packages_full) do + local content + if package.type == "mod" then + content = mod_hash[package.id] + elseif package.type == "game" then + content = game_hash[package.id] + elseif package.type == "txp" then + content = txp_hash[package.id] + end + + if content then + package.path = content.path + package.installed_release = content.release or 0 + else + package.path = nil + end + end +end + +function store.filter_packages(query) + if query == "" and filter_type == 1 then + store.packages = store.packages_full + return + end + + local keywords = {} + for word in query:lower():gmatch("%S+") do + table.insert(keywords, word) + end + + local function matches_keywords(package, keywords) + for k = 1, #keywords do + local keyword = keywords[k] + + if string.find(package.name:lower(), keyword, 1, true) or + string.find(package.title:lower(), keyword, 1, true) or + string.find(package.author:lower(), keyword, 1, true) or + string.find(package.short_description:lower(), keyword, 1, true) then + return true + end + end + + return false + end + + store.packages = {} + for _, package in pairs(store.packages_full) do + if (query == "" or matches_keywords(package, keywords)) and + (filter_type == 1 or package.type == filter_types_type[filter_type]) then + store.packages[#store.packages + 1] = package + end + end + +end + +function store.get_formspec(dlgdata) + store.update_paths() + + dlgdata.pagemax = math.max(math.ceil(#store.packages / num_per_page), 1) + if cur_page > dlgdata.pagemax then + cur_page = 1 + end + + local formspec + if #store.packages_full > 0 then + formspec = { + "size[12,7;true]", + "position[0.5,0.55]", + "field[0.2,0.1;7.8,1;search_string;;", + core.formspec_escape(search_string), "]", + "field_close_on_enter[search_string;false]", + "button[7.7,-0.2;2,1;search;", + fgettext("Search"), "]", + "dropdown[9.7,-0.1;2.4;type;", + table.concat(filter_types_titles, ","), + ";", filter_type, "]", + -- "textlist[0,1;2.4,5.6;a;", + -- table.concat(taglist, ","), "]", + + -- Page nav buttons + "container[0,", + num_per_page + 1.5, "]", + "button[-0.1,0;3,1;back;", + fgettext("Back to Main Menu"), "]", + "button[7.1,0;1,1;pstart;<<]", + "button[8.1,0;1,1;pback;<]", + "label[9.2,0.2;", + tonumber(cur_page), " / ", + tonumber(dlgdata.pagemax), "]", + "button[10.1,0;1,1;pnext;>]", + "button[11.1,0;1,1;pend;>>]", + "container_end[]", + } + + if #store.packages == 0 then + formspec[#formspec + 1] = "label[4,3;" + formspec[#formspec + 1] = fgettext("No results") + formspec[#formspec + 1] = "]" + end + else + formspec = { + "size[12,7;true]", + "position[0.5,0.55]", + "label[4,3;", fgettext("No packages could be retrieved"), "]", + "button[-0.1,", + num_per_page + 1.5, + ";3,1;back;", + fgettext("Back to Main Menu"), "]", + } + end + + local start_idx = (cur_page - 1) * num_per_page + 1 + for i=start_idx, math.min(#store.packages, start_idx+num_per_page-1) do + local package = store.packages[i] + formspec[#formspec + 1] = "container[0.5," + formspec[#formspec + 1] = (i - start_idx) * 1.1 + 1 + formspec[#formspec + 1] = "]" + + -- image + formspec[#formspec + 1] = "image[-0.4,0;1.5,1;" + formspec[#formspec + 1] = core.formspec_escape(get_screenshot(package)) + formspec[#formspec + 1] = "]" + + -- title + formspec[#formspec + 1] = "label[1,-0.1;" + formspec[#formspec + 1] = core.formspec_escape( + minetest.colorize(mt_color_green, package.title) .. + minetest.colorize("#BFBFBF", " by " .. package.author)) + formspec[#formspec + 1] = "]" + + -- description + if package.path and package.installed_release < package.release then + formspec[#formspec + 1] = "textarea[1.25,0.3;7.5,1;;;" + else + formspec[#formspec + 1] = "textarea[1.25,0.3;9,1;;;" + end + formspec[#formspec + 1] = core.formspec_escape(package.short_description) + formspec[#formspec + 1] = "]" + + -- buttons + if not package.path then + formspec[#formspec + 1] = "button[9.9,0;1.5,1;install_" + formspec[#formspec + 1] = tostring(i) + formspec[#formspec + 1] = ";" + formspec[#formspec + 1] = fgettext("Install") + formspec[#formspec + 1] = "]" + else + if package.installed_release < package.release then + -- The install_ action also handles updating + formspec[#formspec + 1] = "button[8.4,0;1.5,1;install_" + formspec[#formspec + 1] = tostring(i) + formspec[#formspec + 1] = ";" + formspec[#formspec + 1] = fgettext("Update") + formspec[#formspec + 1] = "]" + end + + formspec[#formspec + 1] = "button[9.9,0;1.5,1;uninstall_" + formspec[#formspec + 1] = tostring(i) + formspec[#formspec + 1] = ";" + formspec[#formspec + 1] = fgettext("Uninstall") + formspec[#formspec + 1] = "]" + end + + --formspec[#formspec + 1] = "button[9.9,0;1.5,1;view_" + --formspec[#formspec + 1] = tostring(i) + --formspec[#formspec + 1] = ";" + --formspec[#formspec + 1] = fgettext("View") + --formspec[#formspec + 1] = "]" + + formspec[#formspec + 1] = "container_end[]" + end + + return table.concat(formspec, "") +end + +function store.handle_submit(this, fields) + if fields.search or fields.key_enter_field == "search_string" then + search_string = fields.search_string:trim() + cur_page = 1 + store.filter_packages(search_string) + return true + end + + if fields.back then + this:delete() + return true + end + + if fields.pstart then + cur_page = 1 + return true + end + + if fields.pend then + cur_page = this.data.pagemax + return true + end + + if fields.pnext then + cur_page = cur_page + 1 + if cur_page > this.data.pagemax then + cur_page = 1 + end + return true + end + + if fields.pback then + if cur_page == 1 then + cur_page = this.data.pagemax + else + cur_page = cur_page - 1 + end + return true + end + + if fields.type then + local new_type = table.indexof(filter_types_titles, fields.type) + if new_type ~= filter_type then + filter_type = new_type + store.filter_packages(search_string) + return true + end + end + + local start_idx = (cur_page - 1) * num_per_page + 1 + assert(start_idx ~= nil) + for i=start_idx, math.min(#store.packages, start_idx+num_per_page-1) do + local package = store.packages[i] + assert(package) + + if fields["install_" .. i] then + start_install(this, package) + return true + end + + if fields["uninstall_" .. i] then + local dlg_delmod = create_delete_content_dlg(package) + dlg_delmod:set_parent(this) + this:hide() + dlg_delmod:show() + return true + end + + if fields["view_" .. i] then + local dlg = package_dialog.create(package) + dlg:set_parent(this) + this:hide() + dlg:show() + return true + end + end + + return false +end + +function create_store_dlg(type) + if not store.loaded or #store.packages_full == 0 then + store.load() + end + + search_string = "" + cur_page = 1 + store.filter_packages(search_string) + + return dialog_create("store", + store.get_formspec, + store.handle_submit, + nil) +end diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua index af3470ebe..6e0cf7e2a 100644 --- a/builtin/mainmenu/dlg_create_world.lua +++ b/builtin/mainmenu/dlg_create_world.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -16,15 +16,8 @@ --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. local function create_world_formspec(dialogdata) - local mapgens = {} - local mapgens_available = core.settings:get("mapgens_available") - if mapgens_available then - for mg in string.gmatch(mapgens_available, '[^,%s]+') do - table.insert(mapgens, mg) - end - else - mapgens = core.get_mapgen_names() - end + local mapgens = core.get_mapgen_names() + local current_seed = core.settings:get("fixed_map_seed") or "" local current_mg = core.settings:get("mg_name") @@ -39,13 +32,13 @@ local function create_world_formspec(dialogdata) mglist = mglist .. v .. "," end mglist = mglist:sub(1, -2) - + local gameid = core.settings:get("menu_last_game") - + local game, gameidx = nil , 0 if gameid ~= nil then game, gameidx = gamemgr.find_by_gameid(gameid) - + if gameidx == nil then gameidx = 0 end @@ -53,22 +46,32 @@ local function create_world_formspec(dialogdata) current_seed = core.formspec_escape(current_seed) local retval = - "size[11.5,3.75,false]" .. - "background[0,0;11.5,3;" .. core.formspec_escape(defaulttexturedir .. - "bg_dialog.png") .. ";true]" .. - "label[1.5,0;" .. fgettext("World name:") .. "]".. + "size[11.5,6.5,true]" .. + "label[2,0;" .. fgettext("World name") .. "]".. "field[4.5,0.4;6,0.5;te_world_name;;]" .. - "label[1.5,1;" .. fgettext("Seed:") .. "]".. + "label[2,1;" .. fgettext("Seed") .. "]".. "field[4.5,1.4;6,0.5;te_seed;;".. current_seed .. "]" .. - "label[1.5,2;" .. fgettext("Mapgen:") .. "]".. + "label[2,2;" .. fgettext("Mapgen") .. "]".. "dropdown[4.2,2;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]" .. - "dropdown[600.2,6;6.3;games;" .. gamemgr.gamelist() .. ";1]" .. + "label[2,3;" .. fgettext("Planets") .. "]".. + "textlist[4.2,3;5.8,2.3;games;" .. gamemgr.gamelist() .. + ";" .. gameidx .. ";true]" .. - "button[3.25,3.4;2.5,0.5;world_create_confirm;" .. fgettext("Create") .. "]" .. - "button[5.75,3.4;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]" + "button[3.25,6;2.5,0.5;world_create_confirm;" .. fgettext("Create") .. "]" .. + "button[5.75,6;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]" + + if #gamemgr.games == 0 then + retval = retval .. "box[2,4;8,1;#ff8800]label[2.25,4;" .. + fgettext("You have no subgames installed.") .. "]label[2.25,4.4;" .. + fgettext("Download one from minetest.net") .. "]" + elseif #gamemgr.games == 1 and gamemgr.games[1].id == "minimal" then + retval = retval .. "box[1.75,4;8.7,1;#ff8800]label[2,4;" .. + fgettext("Warning: The minimal development test is meant for developers.") .. "]label[2,4.4;" .. + fgettext("Download a subgame, such as minetest_game, from minetest.net") .. "]" + end return retval @@ -76,21 +79,11 @@ end local function create_world_buttonhandler(this, fields) - if fields["world_create_cancel"] then - this:delete() - return true - end - if fields["world_create_confirm"] or fields["key_enter"] then local worldname = fields["te_world_name"] - local gameindex - for i,item in ipairs(gamemgr.games) do - if item.name == fields["games"] then - gameindex = i - end - end + local gameindex = core.get_textlist_index("games") if gameindex ~= nil and worldname ~= "" then @@ -112,6 +105,7 @@ local function create_world_buttonhandler(this, fields) core.settings:set("menu_last_game",gamemgr.games[gameindex].id) if this.data.update_worldlist_filter then menudata.worldlist:set_filtercriteria(gamemgr.games[gameindex].id) + mm_texture.update("singleplayer", gamemgr.games[gameindex].id) end menudata.worldlist:refresh() core.settings:set("mainmenu_last_selected_world", @@ -128,7 +122,11 @@ local function create_world_buttonhandler(this, fields) if fields["games"] then return true end - + + if fields["world_create_cancel"] then + this:delete() + return true + end return false end @@ -140,6 +138,6 @@ function create_create_world_dlg(update_worldlistfilter) create_world_buttonhandler, nil) retval.update_worldlist_filter = update_worldlistfilter - + return retval end diff --git a/builtin/mainmenu/dlg_delete_content.lua b/builtin/mainmenu/dlg_delete_content.lua new file mode 100644 index 000000000..a24171541 --- /dev/null +++ b/builtin/mainmenu/dlg_delete_content.lua @@ -0,0 +1,75 @@ +--Minetest +--Copyright (C) 2014 sapier +-- +--This program is free software; you can redistribute it and/or modify +--it under the terms of the GNU Lesser General Public License as published by +--the Free Software Foundation; either version 2.1 of the License, or +--(at your option) any later version. +-- +--This program is distributed in the hope that it will be useful, +--but WITHOUT ANY WARRANTY; without even the implied warranty of +--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--GNU Lesser General Public License for more details. +-- +--You should have received a copy of the GNU Lesser General Public License along +--with this program; if not, write to the Free Software Foundation, Inc., +--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +-------------------------------------------------------------------------------- + +local function delete_content_formspec(dialogdata) + local retval = + "size[11.5,4.5,true]" .. + "label[2,2;" .. + fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name) .. "]".. + "style[dlg_delete_content_confirm;bgcolor=red]" .. + "button[3.25,3.5;2.5,0.5;dlg_delete_content_confirm;" .. fgettext("Delete") .. "]" .. + "button[5.75,3.5;2.5,0.5;dlg_delete_content_cancel;" .. fgettext("Cancel") .. "]" + + return retval +end + +-------------------------------------------------------------------------------- +local function delete_content_buttonhandler(this, fields) + if fields["dlg_delete_content_confirm"] ~= nil then + + if this.data.content.path ~= nil and + this.data.content.path ~= "" and + this.data.content.path ~= core.get_modpath() and + this.data.content.path ~= core.get_gamepath() and + this.data.content.path ~= core.get_texturepath() then + if not core.delete_dir(this.data.content.path) then + gamedata.errormessage = fgettext("pkgmgr: failed to delete \"$1\"", this.data.content.path) + end + + if this.data.content.type == "game" then + pkgmgr.update_gamelist() + else + pkgmgr.refresh_globals() + end + else + gamedata.errormessage = fgettext("pkgmgr: invalid path \"$1\"", this.data.content.path) + end + this:delete() + return true + end + + if fields["dlg_delete_content_cancel"] then + this:delete() + return true + end + + return false +end + +-------------------------------------------------------------------------------- +function create_delete_content_dlg(content) + assert(content.name) + + local retval = dialog_create("dlg_delete_content", + delete_content_formspec, + delete_content_buttonhandler, + nil) + retval.data.content = content + return retval +end diff --git a/builtin/mainmenu/dlg_delete_mod.lua b/builtin/mainmenu/dlg_delete_mod.lua index ef428aa98..2efd70414 100644 --- a/builtin/mainmenu/dlg_delete_mod.lua +++ b/builtin/mainmenu/dlg_delete_mod.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/dlg_delete_world.lua b/builtin/mainmenu/dlg_delete_world.lua index 06751b905..df1091033 100644 --- a/builtin/mainmenu/dlg_delete_world.lua +++ b/builtin/mainmenu/dlg_delete_world.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -18,13 +18,11 @@ local function delete_world_formspec(dialogdata) local retval = - "size[11.5,3.75,false]" .. - "background[0,0;11.5,3;" .. core.formspec_escape(defaulttexturedir .. - "bg_dialog.png") .. ";true]" .. - "label[5,1.4;" .. fgettext("Delete World") .. "]" .. - "label[5,1.8;" .. fgettext("\"$1\"?", dialogdata.delete_name) .. "]" .. - "button[3.25,3.4;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" .. - "button[5.75,3.4;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]" + "size[10,2.5,true]" .. + "label[0.5,0.5;" .. + fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" .. + "button[0.5,1.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" .. + "button[7.0,1.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]" return retval end diff --git a/builtin/mainmenu/dlg_rename_modpack.lua b/builtin/mainmenu/dlg_rename_modpack.lua index 1012f84dc..959c65d9b 100644 --- a/builtin/mainmenu/dlg_rename_modpack.lua +++ b/builtin/mainmenu/dlg_rename_modpack.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua index 95ac6d6cd..206ce1620 100644 --- a/builtin/mainmenu/dlg_settings_advanced.lua +++ b/builtin/mainmenu/dlg_settings_advanced.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/gamemgr.lua b/builtin/mainmenu/gamemgr.lua index 611f7e506..fd6025fcd 100644 --- a/builtin/mainmenu/gamemgr.lua +++ b/builtin/mainmenu/gamemgr.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 3eb9afba0..159399326 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -24,8 +24,8 @@ mt_color_dark_green = "#25C191" local menupath = core.get_mainmenu_path() local basepath = core.get_builtin_path() -defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" .. DIR_DELIM -local use_simple_menu = (PLATFORM == "Android" or PLATFORM == "iOS") +defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" .. + DIR_DELIM .. "pack" .. DIR_DELIM dofile(basepath .. DIR_DELIM .. "common" .. DIR_DELIM .. "async_event.lua") dofile(basepath .. DIR_DELIM .. "common" .. DIR_DELIM .. "filterlist.lua") @@ -35,29 +35,29 @@ dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "tabview.lua") dofile(basepath .. DIR_DELIM .. "fstk" .. DIR_DELIM .. "ui.lua") dofile(menupath .. DIR_DELIM .. "common.lua") dofile(menupath .. DIR_DELIM .. "gamemgr.lua") +dofile(menupath .. DIR_DELIM .. "modmgr.lua") +dofile(menupath .. DIR_DELIM .. "store.lua") dofile(menupath .. DIR_DELIM .. "textures.lua") -dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua") ---dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua") -dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua") ---dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua") dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua") - -if not use_simple_menu then - dofile(menupath .. DIR_DELIM .. "modmgr.lua") --- dofile(menupath .. DIR_DELIM .. "store.lua") - dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua") +dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua") +if PLATFORM ~= "Android" then + dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua") + dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua") + dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua") + dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua") end local tabs = {} ---tabs.mods = dofile(menupath .. DIR_DELIM .. "tab_mods.lua") +tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua") +tabs.mods = dofile(menupath .. DIR_DELIM .. "tab_mods.lua") tabs.credits = dofile(menupath .. DIR_DELIM .. "tab_credits.lua") -tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua") -tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua") ---tabs.server = dofile(menupath .. DIR_DELIM .. "tab_server.lua") -if not use_simple_menu then - tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua") +if PLATFORM == "Android" then + tabs.simple_main = dofile(menupath .. DIR_DELIM .. "tab_simple_main.lua") +else + tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua") + tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua") tabs.texturepacks = dofile(menupath .. DIR_DELIM .. "tab_texturepacks.lua") end @@ -74,60 +74,95 @@ local function init_globals() -- Init gamedata gamedata.worldindex = 0 - menudata.worldlist = filterlist.create( - core.get_worlds, - compare_worlds, - -- Unique id comparison function - function(element, uid) - return element.name == uid - end, - -- Filter function - function(element, gameid) - return element.gameid == gameid + if PLATFORM == "Android" then + local world_list = core.get_worlds() + local world_index + + local found_singleplayerworld = false + for i, world in ipairs(world_list) do + if world.name == "singleplayerworld" then + found_singleplayerworld = true + world_index = i + break + end end - ) - menudata.worldlist:add_sort_mechanism("alphabetic", sort_worlds_alphabetic) - menudata.worldlist:set_sortmode("alphabetic") + if not found_singleplayerworld then + core.create_world("singleplayerworld", 1) - mm_texture.init() + world_list = core.get_worlds() - -- Create main tabview - local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = 0}) + for i, world in ipairs(world_list) do + if world.name == "singleplayerworld" then + world_index = i + break + end + end + end - tv_main:add(tabs.local_game) - tv_main:add(tabs.play_online) + gamedata.worldindex = world_index + else + menudata.worldlist = filterlist.create( + core.get_worlds, + compare_worlds, + -- Unique id comparison function + function(element, uid) + return element.name == uid + end, + -- Filter function + function(element, gameid) + return element.gameid == gameid + end + ) - if not use_simple_menu then - tv_main:add(tabs.settings) - tv_main:add(tabs.texturepacks) + menudata.worldlist:add_sort_mechanism("alphabetic", sort_worlds_alphabetic) + menudata.worldlist:set_sortmode("alphabetic") + + if not core.settings:get("menu_last_game") then + local default_game = core.settings:get("default_game") or "minetest" + core.settings:set("menu_last_game", default_game) + end + + mm_texture.init() + end + + -- Create main tabview + local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = -3}) + + if PLATFORM == "Android" then + tv_main:add(tabs.simple_main) + tv_main:add(tabs.settings) + else + tv_main:set_autosave_tab(true) + tv_main:add(tabs.local_game) + tv_main:add(tabs.play_online) + tv_main:add(tabs.settings) +-- tv_main:add(tabs.mods) +-- tv_main:add(tabs.texturepacks) + end - --tv_main:add(tabs.mods) tv_main:add(tabs.credits) - tv_main:set_autosave_tab(true) tv_main:set_global_event_handler(main_event_handler) tv_main:set_fixed_size(false) - local last_tab = core.settings:get("maintab_LAST") - if last_tab and tv_main.current_tab ~= last_tab then - tv_main:set_tab(last_tab) + if PLATFORM ~= "Android" then + tv_main:set_tab(core.settings:get("maintab_LAST")) end ui.set_default("maintab") tv_main:show() -- Create modstore ui - --if use_simple_menu then - -- modstore.init({x = 12, y = 6}, 3, 2) - --else - -- modstore.init({x = 12, y = 8}, 4, 3) - --end + if PLATFORM == "Android" then + modstore.init({x = 12, y = 6}, 3, 2) + else + modstore.init({x = 12, y = 8}, 4, 3) + end ui.update() - minetest.set_clouds(false) - mm_texture.set_dirt_bg() + core.sound_play("main_menu", true) end init_globals() diff --git a/builtin/mainmenu/init_simple.lua b/builtin/mainmenu/init_simple.lua new file mode 100644 index 000000000..298bd834e --- /dev/null +++ b/builtin/mainmenu/init_simple.lua @@ -0,0 +1,4 @@ +-- helper file to be able to debug the simple menu on PC +-- without messing around with actual menu code! +PLATFORM = "Android" +dofile("builtin/mainmenu/init.lua") diff --git a/builtin/mainmenu/modmgr.lua b/builtin/mainmenu/modmgr.lua index 9c8076f40..dee048982 100644 --- a/builtin/mainmenu/modmgr.lua +++ b/builtin/mainmenu/modmgr.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua new file mode 100644 index 000000000..dee4dabbb --- /dev/null +++ b/builtin/mainmenu/pkgmgr.lua @@ -0,0 +1,789 @@ +--Minetest +--Copyright (C) 2013 sapier +-- +--This program is free software; you can redistribute it and/or modify +--it under the terms of the GNU Lesser General Public License as published by +--the Free Software Foundation; either version 2.1 of the License, or +--(at your option) any later version. +-- +--This program is distributed in the hope that it will be useful, +--but WITHOUT ANY WARRANTY; without even the implied warranty of +--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--GNU Lesser General Public License for more details. +-- +--You should have received a copy of the GNU Lesser General Public License along +--with this program; if not, write to the Free Software Foundation, Inc., +--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +-------------------------------------------------------------------------------- +function get_mods(path,retval,modpack) + local mods = core.get_dir_list(path, true) + + for _, name in ipairs(mods) do + if name:sub(1, 1) ~= "." then + local prefix = path .. DIR_DELIM .. name + local toadd = { + dir_name = name, + parent_dir = path, + } + retval[#retval + 1] = toadd + + -- Get config file + local mod_conf + local modpack_conf = io.open(prefix .. DIR_DELIM .. "modpack.conf") + if modpack_conf then + toadd.is_modpack = true + modpack_conf:close() + + mod_conf = Settings(prefix .. DIR_DELIM .. "modpack.conf"):to_table() + if mod_conf.name then + name = mod_conf.name + toadd.is_name_explicit = true + end + else + mod_conf = Settings(prefix .. DIR_DELIM .. "mod.conf"):to_table() + if mod_conf.name then + name = mod_conf.name + toadd.is_name_explicit = true + end + end + + -- Read from config + toadd.name = name + toadd.author = mod_conf.author + toadd.release = tonumber(mod_conf.release or "0") + toadd.path = prefix + toadd.type = "mod" + + -- Check modpack.txt + -- Note: modpack.conf is already checked above + local modpackfile = io.open(prefix .. DIR_DELIM .. "modpack.txt") + if modpackfile then + modpackfile:close() + toadd.is_modpack = true + end + + -- Deal with modpack contents + if modpack and modpack ~= "" then + toadd.modpack = modpack + elseif toadd.is_modpack then + toadd.type = "modpack" + toadd.is_modpack = true + get_mods(prefix, retval, name) + end + end + end +end + +--modmanager implementation +pkgmgr = {} + +function pkgmgr.get_texture_packs() + local txtpath = core.get_texturepath() + local list = core.get_dir_list(txtpath, true) + local retval = {} + + local current_texture_path = core.settings:get("texture_path") + + for _, item in ipairs(list) do + if item ~= "base" then + local name = item + + local path = txtpath .. DIR_DELIM .. item .. DIR_DELIM + if path == current_texture_path then + name = fgettext("$1 (Enabled)", name) + end + + local conf = Settings(path .. "texture_pack.conf") + + retval[#retval + 1] = { + name = item, + author = conf:get("author"), + release = tonumber(conf:get("release") or "0"), + list_name = name, + type = "txp", + path = path, + enabled = path == current_texture_path, + } + end + end + + table.sort(retval, function(a, b) + return a.name > b.name + end) + + return retval +end + +-------------------------------------------------------------------------------- +function pkgmgr.extract(modfile) + if modfile.type == "zip" then + local tempfolder = os.tempfolder() + + if tempfolder ~= nil and + tempfolder ~= "" then + core.create_dir(tempfolder) + if core.extract_zip(modfile.name,tempfolder) then + return tempfolder + end + end + end + return nil +end + +function pkgmgr.get_folder_type(path) + local testfile = io.open(path .. DIR_DELIM .. "init.lua","r") + if testfile ~= nil then + testfile:close() + return { type = "mod", path = path } + end + + testfile = io.open(path .. DIR_DELIM .. "modpack.conf","r") + if testfile ~= nil then + testfile:close() + return { type = "modpack", path = path } + end + + testfile = io.open(path .. DIR_DELIM .. "modpack.txt","r") + if testfile ~= nil then + testfile:close() + return { type = "modpack", path = path } + end + + testfile = io.open(path .. DIR_DELIM .. "game.conf","r") + if testfile ~= nil then + testfile:close() + return { type = "game", path = path } + end + + testfile = io.open(path .. DIR_DELIM .. "texture_pack.conf","r") + if testfile ~= nil then + testfile:close() + return { type = "txp", path = path } + end + + return nil +end + +------------------------------------------------------------------------------- +function pkgmgr.get_base_folder(temppath) + if temppath == nil then + return { type = "invalid", path = "" } + end + + local ret = pkgmgr.get_folder_type(temppath) + if ret then + return ret + end + + local subdirs = core.get_dir_list(temppath, true) + if #subdirs == 1 then + ret = pkgmgr.get_folder_type(temppath .. DIR_DELIM .. subdirs[1]) + if ret then + return ret + else + return { type = "invalid", path = temppath .. DIR_DELIM .. subdirs[1] } + end + end + + return nil +end + +-------------------------------------------------------------------------------- +function pkgmgr.isValidModname(modpath) + if modpath:find("-") ~= nil then + return false + end + + return true +end + +-------------------------------------------------------------------------------- +function pkgmgr.parse_register_line(line) + local pos1 = line:find("\"") + local pos2 = nil + if pos1 ~= nil then + pos2 = line:find("\"",pos1+1) + end + + if pos1 ~= nil and pos2 ~= nil then + local item = line:sub(pos1+1,pos2-1) + + if item ~= nil and + item ~= "" then + local pos3 = item:find(":") + + if pos3 ~= nil then + local retval = item:sub(1,pos3-1) + if retval ~= nil and + retval ~= "" then + return retval + end + end + end + end + return nil +end + +-------------------------------------------------------------------------------- +function pkgmgr.parse_dofile_line(modpath,line) + local pos1 = line:find("\"") + local pos2 = nil + if pos1 ~= nil then + pos2 = line:find("\"",pos1+1) + end + + if pos1 ~= nil and pos2 ~= nil then + local filename = line:sub(pos1+1,pos2-1) + + if filename ~= nil and + filename ~= "" and + filename:find(".lua") then + return pkgmgr.identify_modname(modpath,filename) + end + end + return nil +end + +-------------------------------------------------------------------------------- +function pkgmgr.identify_modname(modpath,filename) + local testfile = io.open(modpath .. DIR_DELIM .. filename,"r") + if testfile ~= nil then + local line = testfile:read() + + while line~= nil do + local modname = nil + + if line:find("minetest.register_tool") then + modname = pkgmgr.parse_register_line(line) + end + + if line:find("minetest.register_craftitem") then + modname = pkgmgr.parse_register_line(line) + end + + + if line:find("minetest.register_node") then + modname = pkgmgr.parse_register_line(line) + end + + if line:find("dofile") then + modname = pkgmgr.parse_dofile_line(modpath,line) + end + + if modname ~= nil then + testfile:close() + return modname + end + + line = testfile:read() + end + testfile:close() + end + + return nil +end +-------------------------------------------------------------------------------- +function pkgmgr.render_packagelist(render_list) + local retval = "" + + if render_list == nil then + if pkgmgr.global_mods == nil then + pkgmgr.refresh_globals() + end + render_list = pkgmgr.global_mods + end + + local list = render_list:get_list() + local last_modpack = nil + local retval = {} + for i, v in ipairs(list) do + local color = "" + if v.is_modpack then + local rawlist = render_list:get_raw_list() + color = mt_color_dark_green + + for j = 1, #rawlist, 1 do + if rawlist[j].modpack == list[i].name and + not rawlist[j].enabled then + -- Modpack not entirely enabled so showing as grey + color = mt_color_grey + break + end + end + elseif v.is_game_content or v.type == "game" then + color = mt_color_blue + elseif v.enabled or v.type == "txp" then + color = mt_color_green + end + + retval[#retval + 1] = color + if v.modpack ~= nil or v.loc == "game" then + retval[#retval + 1] = "1" + else + retval[#retval + 1] = "0" + end + retval[#retval + 1] = core.formspec_escape(v.list_name or v.name) + end + + return table.concat(retval, ",") +end + +-------------------------------------------------------------------------------- +function pkgmgr.get_dependencies(path) + if path == nil then + return {}, {} + end + + local info = core.get_content_info(path) + return info.depends or {}, info.optional_depends or {} +end + +----------- tests whether all of the mods in the modpack are enabled ----------- +function pkgmgr.is_modpack_entirely_enabled(data, name) + local rawlist = data.list:get_raw_list() + for j = 1, #rawlist do + if rawlist[j].modpack == name and not rawlist[j].enabled then + return false + end + end + return true +end + +---------- toggles or en/disables a mod or modpack ----------------------------- +function pkgmgr.enable_mod(this, toset) + local mod = this.data.list:get_list()[this.data.selected_mod] + + -- game mods can't be enabled or disabled + if mod.is_game_content then + return + end + + -- toggle or en/disable the mod + if not mod.is_modpack then + if toset == nil then + mod.enabled = not mod.enabled + else + mod.enabled = toset + end + return + end + + -- toggle or en/disable every mod in the modpack, interleaved unsupported + local list = this.data.list:get_raw_list() + for i = 1, #list do + if list[i].modpack == mod.name then + if toset == nil then + toset = not list[i].enabled + end + list[i].enabled = toset + end + end +end + +-------------------------------------------------------------------------------- +function pkgmgr.get_worldconfig(worldpath) + local filename = worldpath .. + DIR_DELIM .. "world.mt" + + local worldfile = Settings(filename) + + local worldconfig = {} + worldconfig.global_mods = {} + worldconfig.game_mods = {} + + for key,value in pairs(worldfile:to_table()) do + if key == "gameid" then + worldconfig.id = value + elseif key:sub(0, 9) == "load_mod_" then + -- Compatibility: Check against "nil" which was erroneously used + -- as value for fresh configured worlds + worldconfig.global_mods[key] = value ~= "false" and value ~= "nil" + and value + else + worldconfig[key] = value + end + end + + --read gamemods + local gamespec = pkgmgr.find_by_gameid(worldconfig.id) + pkgmgr.get_game_mods(gamespec, worldconfig.game_mods) + + return worldconfig +end + +-------------------------------------------------------------------------------- +function pkgmgr.install_dir(type, path, basename, targetpath) + local basefolder = pkgmgr.get_base_folder(path) + + -- There's no good way to detect a texture pack, so let's just assume + -- it's correct for now. + if type == "txp" then + if basefolder and basefolder.type ~= "invalid" and basefolder.type ~= "txp" then + return nil, fgettext("Unable to install a $1 as a texture pack", basefolder.type) + end + + local from = basefolder and basefolder.path or path + if targetpath then + core.delete_dir(targetpath) + core.create_dir(targetpath) + else + targetpath = core.get_texturepath() .. DIR_DELIM .. basename + end + if not core.copy_dir(from, targetpath) then + return nil, + fgettext("Failed to install $1 to $2", basename, targetpath) + end + return targetpath, nil + + elseif not basefolder then + return nil, fgettext("Unable to find a valid mod or modpack") + end + + -- + -- Get destination + -- + if basefolder.type == "modpack" then + if type ~= "mod" then + return nil, fgettext("Unable to install a modpack as a $1", type) + end + + -- Get destination name for modpack + if targetpath then + core.delete_dir(targetpath) + core.create_dir(targetpath) + else + local clean_path = nil + if basename ~= nil then + clean_path = basename + end + if not clean_path then + clean_path = get_last_folder(cleanup_path(basefolder.path)) + end + if clean_path then + targetpath = core.get_modpath() .. DIR_DELIM .. clean_path + else + return nil, + fgettext("Install Mod: Unable to find suitable folder name for modpack $1", + modfilename) + end + end + elseif basefolder.type == "mod" then + if type ~= "mod" then + return nil, fgettext("Unable to install a mod as a $1", type) + end + + if targetpath then + core.delete_dir(targetpath) + core.create_dir(targetpath) + else + local targetfolder = basename + if targetfolder == nil then + targetfolder = pkgmgr.identify_modname(basefolder.path, "init.lua") + end + + -- If heuristic failed try to use current foldername + if targetfolder == nil then + targetfolder = get_last_folder(basefolder.path) + end + + if targetfolder ~= nil and pkgmgr.isValidModname(targetfolder) then + targetpath = core.get_modpath() .. DIR_DELIM .. targetfolder + else + return nil, fgettext("Install Mod: Unable to find real mod name for: $1", modfilename) + end + end + + elseif basefolder.type == "game" then + if type ~= "game" then + return nil, fgettext("Unable to install a game as a $1", type) + end + + if targetpath then + core.delete_dir(targetpath) + core.create_dir(targetpath) + else + targetpath = core.get_gamepath() .. DIR_DELIM .. basename + end + end + + -- Copy it + if not core.copy_dir(basefolder.path, targetpath) then + return nil, + fgettext("Failed to install $1 to $2", basename, targetpath) + end + + if basefolder.type == "game" then + pkgmgr.update_gamelist() + else + pkgmgr.refresh_globals() + end + + return targetpath, nil +end + +-------------------------------------------------------------------------------- +function pkgmgr.install(type, modfilename, basename, dest) + local archive_info = pkgmgr.identify_filetype(modfilename) + local path = pkgmgr.extract(archive_info) + + if path == nil then + return nil, + fgettext("Install: file: \"$1\"", archive_info.name) .. "\n" .. + fgettext("Install: Unsupported file type \"$1\" or broken archive", + archive_info.type) + end + + local targetpath, msg = pkgmgr.install_dir(type, path, basename, dest) + core.delete_dir(path) + return targetpath, msg +end + +-------------------------------------------------------------------------------- +function pkgmgr.preparemodlist(data) + local retval = {} + + local global_mods = {} + local game_mods = {} + + --read global mods + local modpath = core.get_modpath() + + if modpath ~= nil and + modpath ~= "" then + get_mods(modpath,global_mods) + end + + for i=1,#global_mods,1 do + global_mods[i].type = "mod" + global_mods[i].loc = "global" + retval[#retval + 1] = global_mods[i] + end + + --read game mods + local gamespec = pkgmgr.find_by_gameid(data.gameid) + pkgmgr.get_game_mods(gamespec, game_mods) + + if #game_mods > 0 then + -- Add title + retval[#retval + 1] = { + type = "game", + is_game_content = true, + name = fgettext("$1 mods", gamespec.name), + path = gamespec.path + } + end + + for i=1,#game_mods,1 do + game_mods[i].type = "mod" + game_mods[i].loc = "game" + game_mods[i].is_game_content = true + retval[#retval + 1] = game_mods[i] + end + + if data.worldpath == nil then + return retval + end + + --read world mod configuration + local filename = data.worldpath .. + DIR_DELIM .. "world.mt" + + local worldfile = Settings(filename) + + for key,value in pairs(worldfile:to_table()) do + if key:sub(1, 9) == "load_mod_" then + key = key:sub(10) + local element = nil + for i=1,#retval,1 do + if retval[i].name == key and + not retval[i].is_modpack then + element = retval[i] + break + end + end + if element ~= nil then + element.enabled = value ~= "false" and value ~= "nil" and value + else + core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found") + end + end + end + + return retval +end + +function pkgmgr.compare_package(a, b) + return a and b and a.name == b.name and a.path == b.path +end + +-------------------------------------------------------------------------------- +function pkgmgr.comparemod(elem1,elem2) + if elem1 == nil or elem2 == nil then + return false + end + if elem1.name ~= elem2.name then + return false + end + if elem1.is_modpack ~= elem2.is_modpack then + return false + end + if elem1.type ~= elem2.type then + return false + end + if elem1.modpack ~= elem2.modpack then + return false + end + + if elem1.path ~= elem2.path then + return false + end + + return true +end + +-------------------------------------------------------------------------------- +function pkgmgr.mod_exists(basename) + + if pkgmgr.global_mods == nil then + pkgmgr.refresh_globals() + end + + if pkgmgr.global_mods:raw_index_by_uid(basename) > 0 then + return true + end + + return false +end + +-------------------------------------------------------------------------------- +function pkgmgr.get_global_mod(idx) + + if pkgmgr.global_mods == nil then + return nil + end + + if idx == nil or idx < 1 or + idx > pkgmgr.global_mods:size() then + return nil + end + + return pkgmgr.global_mods:get_list()[idx] +end + +-------------------------------------------------------------------------------- +function pkgmgr.refresh_globals() + local function is_equal(element,uid) --uid match + if element.name == uid then + return true + end + end + pkgmgr.global_mods = filterlist.create(pkgmgr.preparemodlist, + pkgmgr.comparemod, is_equal, nil, {}) + pkgmgr.global_mods:add_sort_mechanism("alphabetic", sort_mod_list) + pkgmgr.global_mods:set_sortmode("alphabetic") +end + +-------------------------------------------------------------------------------- +function pkgmgr.identify_filetype(name) + + if name:sub(-3):lower() == "zip" then + return { + name = name, + type = "zip" + } + end + + if name:sub(-6):lower() == "tar.gz" or + name:sub(-3):lower() == "tgz"then + return { + name = name, + type = "tgz" + } + end + + if name:sub(-6):lower() == "tar.bz2" then + return { + name = name, + type = "tbz" + } + end + + if name:sub(-2):lower() == "7z" then + return { + name = name, + type = "7z" + } + end + + return { + name = name, + type = "ukn" + } +end + + +-------------------------------------------------------------------------------- +function pkgmgr.find_by_gameid(gameid) + for i=1,#pkgmgr.games,1 do + if pkgmgr.games[i].id == gameid then + return pkgmgr.games[i], i + end + end + return nil, nil +end + +-------------------------------------------------------------------------------- +function pkgmgr.get_game_mods(gamespec, retval) + if gamespec ~= nil and + gamespec.gamemods_path ~= nil and + gamespec.gamemods_path ~= "" then + get_mods(gamespec.gamemods_path, retval) + end +end + +-------------------------------------------------------------------------------- +function pkgmgr.get_game_modlist(gamespec) + local retval = "" + local game_mods = {} + pkgmgr.get_game_mods(gamespec, game_mods) + for i=1,#game_mods,1 do + if retval ~= "" then + retval = retval.."," + end + retval = retval .. game_mods[i].name + end + return retval +end + +-------------------------------------------------------------------------------- +function pkgmgr.get_game(index) + if index > 0 and index <= #pkgmgr.games then + return pkgmgr.games[index] + end + + return nil +end + +-------------------------------------------------------------------------------- +function pkgmgr.update_gamelist() + pkgmgr.games = core.get_games() +end + +-------------------------------------------------------------------------------- +function pkgmgr.gamelist() + local retval = "" + if #pkgmgr.games > 0 then + retval = retval .. core.formspec_escape(pkgmgr.games[1].name) + + for i=2,#pkgmgr.games,1 do + retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].name) + end + end + return retval +end + +-------------------------------------------------------------------------------- +-- read initial data +-------------------------------------------------------------------------------- +pkgmgr.update_gamelist() diff --git a/builtin/mainmenu/store.lua b/builtin/mainmenu/store.lua index 43eb7565c..59391f8bc 100644 --- a/builtin/mainmenu/store.lua +++ b/builtin/mainmenu/store.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -29,7 +29,7 @@ function modstore.init(size, unsortedmods, searchmods) modstore.modsperpage = modstore.mods_on_unsorted_page modstore.basetexturedir = core.get_texturepath() .. DIR_DELIM .. "base" .. - DIR_DELIM + DIR_DELIM .. "pack" .. DIR_DELIM modstore.lastmodtitle = "" modstore.last_search = "" diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua new file mode 100644 index 000000000..336730bf4 --- /dev/null +++ b/builtin/mainmenu/tab_content.lua @@ -0,0 +1,209 @@ +--Minetest +--Copyright (C) 2014 sapier +--Copyright (C) 2018 rubenwardy +-- +--This program is free software; you can redistribute it and/or modify +--it under the terms of the GNU Lesser General Public License as published by +--the Free Software Foundation; either version 2.1 of the License, or +--(at your option) any later version. +-- +--This program is distributed in the hope that it will be useful, +--but WITHOUT ANY WARRANTY; without even the implied warranty of +--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--GNU Lesser General Public License for more details. +-- +--You should have received a copy of the GNU Lesser General Public License along +--with this program; if not, write to the Free Software Foundation, Inc., +--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +local packages_raw +local packages + +-------------------------------------------------------------------------------- +local function get_formspec(tabview, name, tabdata) + if pkgmgr.global_mods == nil then + pkgmgr.refresh_globals() + end + if pkgmgr.games == nil then + pkgmgr.update_gamelist() + end + + if packages == nil then + packages_raw = {} + table.insert_all(packages_raw, pkgmgr.games) + table.insert_all(packages_raw, pkgmgr.get_texture_packs()) + table.insert_all(packages_raw, pkgmgr.global_mods:get_list()) + + local function get_data() + return packages_raw + end + + local function is_equal(element, uid) --uid match + return (element.type == "game" and element.id == uid) or + element.name == uid + end + + packages = filterlist.create(get_data, pkgmgr.compare_package, + is_equal, nil, {}) + end + + if tabdata.selected_pkg == nil then + tabdata.selected_pkg = 1 + end + + + local retval = + "label[0.05,-0.25;".. fgettext("Installed Packages:") .. "]" .. + "tablecolumns[color;tree;text]" .. + "table[0,0.25;5.1,4.3;pkglist;" .. + pkgmgr.render_packagelist(packages) .. + ";" .. tabdata.selected_pkg .. "]" .. + "button[0,4.85;5.25,0.5;btn_contentdb;".. fgettext("Browse online content") .. "]" + + + local selected_pkg + if filterlist.size(packages) >= tabdata.selected_pkg then + selected_pkg = packages:get_list()[tabdata.selected_pkg] + end + + if selected_pkg ~= nil then + --check for screenshot beeing available + local screenshotfilename = selected_pkg.path .. DIR_DELIM .. "screenshot.png" + local screenshotfile, error = io.open(screenshotfilename, "r") + + local modscreenshot + if error == nil then + screenshotfile:close() + modscreenshot = screenshotfilename + end + + if modscreenshot == nil then + modscreenshot = defaulttexturedir .. "no_screenshot.png" + end + + local info = core.get_content_info(selected_pkg.path) + local desc = fgettext("No package description available") + if info.description and info.description:trim() ~= "" then + desc = info.description + end + + retval = retval .. + "image[5.5,0;3,2;" .. core.formspec_escape(modscreenshot) .. "]" .. + "label[8.25,0.6;" .. core.formspec_escape(selected_pkg.name) .. "]" .. + "box[5.5,2.2;6.15,2.35;#000]" + + if selected_pkg.type == "mod" then + if selected_pkg.is_modpack then + retval = retval .. + "button[8.65,4.65;3.25,1;btn_mod_mgr_rename_modpack;" .. + fgettext("Rename") .. "]" + else + --show dependencies + desc = desc .. "\n\n" + local toadd_hard = table.concat(info.depends or {}, "\n") + local toadd_soft = table.concat(info.optional_depends or {}, "\n") + if toadd_hard == "" and toadd_soft == "" then + desc = desc .. fgettext("No dependencies.") + else + if toadd_hard ~= "" then + desc = desc ..fgettext("Dependencies:") .. + "\n" .. toadd_hard + end + if toadd_soft ~= "" then + if toadd_hard ~= "" then + desc = desc .. "\n\n" + end + desc = desc .. fgettext("Optional dependencies:") .. + "\n" .. toadd_soft + end + end + end + + else + if selected_pkg.type == "txp" then + if selected_pkg.enabled then + retval = retval .. + "button[8.65,4.65;3.25,1;btn_mod_mgr_disable_txp;" .. + fgettext("Disable Texture Pack") .. "]" + else + retval = retval .. + "button[8.65,4.65;3.25,1;btn_mod_mgr_use_txp;" .. + fgettext("Use Texture Pack") .. "]" + end + end + end + + retval = retval .. "textarea[5.85,2.2;6.35,2.9;;" .. + fgettext("Information:") .. ";" .. desc .. "]" + + if core.may_modify_path(selected_pkg.path) then + retval = retval .. + "button[5.5,4.65;3.25,1;btn_mod_mgr_delete_mod;" .. + fgettext("Uninstall Package") .. "]" + end + end + return retval +end + +-------------------------------------------------------------------------------- +local function handle_buttons(tabview, fields, tabname, tabdata) + if fields["pkglist"] ~= nil then + local event = core.explode_table_event(fields["pkglist"]) + tabdata.selected_pkg = event.row + return true + end + + if fields["btn_contentdb"] ~= nil then + local dlg = create_store_dlg() + dlg:set_parent(tabview) + tabview:hide() + dlg:show() + packages = nil + return true + end + + if fields["btn_mod_mgr_rename_modpack"] ~= nil then + local mod = packages:get_list()[tabdata.selected_pkg] + local dlg_renamemp = create_rename_modpack_dlg(mod) + dlg_renamemp:set_parent(tabview) + tabview:hide() + dlg_renamemp:show() + packages = nil + return true + end + + if fields["btn_mod_mgr_delete_mod"] ~= nil then + local mod = packages:get_list()[tabdata.selected_pkg] + local dlg_delmod = create_delete_content_dlg(mod) + dlg_delmod:set_parent(tabview) + tabview:hide() + dlg_delmod:show() + packages = nil + return true + end + + if fields.btn_mod_mgr_use_txp then + local txp = packages:get_list()[tabdata.selected_pkg] + core.settings:set("texture_path", txp.path) + packages = nil + return true + end + + + if fields.btn_mod_mgr_disable_txp then + core.settings:set("texture_path", "") + packages = nil + return true + end + + return false +end + +-------------------------------------------------------------------------------- +return { + name = "content", + caption = fgettext("Content"), + cbf_formspec = get_formspec, + cbf_button_handler = handle_buttons, + on_change = pkgmgr.update_gamelist +} diff --git a/builtin/mainmenu/tab_credits.lua b/builtin/mainmenu/tab_credits.lua index 4112a9c63..de2a622a4 100644 --- a/builtin/mainmenu/tab_credits.lua +++ b/builtin/mainmenu/tab_credits.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -17,75 +17,42 @@ -------------------------------------------------------------------------------- -local blockcolor_developers = { - "MrChiantos", +local engine = { + "Minetest 5.0.1 : celeron55, Core Devs and Community Minetest", } -local multicraft_developers = { - "Maksim Gamarnik (MoNTE48) ", - "Bektur Mambetov (ubulem) ", - "Alexander Zavrin (Ransom.00)", - "sfan5 ", - "Stuart Jones (stujones11) ", - "Jean-Patrick Guerrero (kilbith) ", - "And other people who helped make the world better!", +local developers = { + "Mrchiantos", } -local core_developers = { - "Perttu Ahola (celeron55) ", - "sfan5 ", - "ShadowNinja ", - "Nathanaël Courant (Nore/Ekdohibs) ", - "Loic Blot (nerzhul/nrz) ", - "paramat", - "Craig Robbins (Zeno) ", - "Auke Kok (sofar) ", - "rubenwardy ", - "Krock/SmallJoker ", +local contributors = { + +"Animal Model : AspireMint", +"Ships Spawn Mod : SokoMine", +"Furnitures Mod : Gerold55", +"Slope Simple : Nigel", +"Awards : RubenWardy", +"Mainmenu : RubenWardy (I have use Pr 5.0 Modify for 0.4)", +"SurfBoard : Archfan7411", +"Airboat : Paramat", +"DriftCar : Paramat", +"Spaceship : Paramat (Code) & SpaceShip'Model (Viktor Hahn )", +"Textures 16px : Peak (Since 1.46.4b)", +"Trampoline : hkzorman", +"Mobs mod : TenPlus1", +"Player Model : Quaternius (Human Low Poly / Since 1.53)", +"Player Model b3d : Kroukuk", +"Trees : Kenney.nl (Since 1.53)", +"Hdb Model (Homedecor) : Vanessa", +"Hovercraft : Stuart Jones ", +"HotAirBallons : Me Me and Me // mbb (Flying Carpet - Wuzzy)", +"ComboBlock : Pithydon", +"ComboBlock & ComboStair Model : Nathan (MinetestVideo)", +"Header and Logo : LMD, azekill_DIABLO & MrChiantos", +"Inventory Icons : Xenon (xenonca)", + } -local active_contributors = { - "red-001 [CSM & Menu fixes]", - "Dániel Juhász (juhdanad) [Audiovisuals: lighting]", - "numberZero [Audiovisuals: meshgen]", - "Lars Hofhansl [Occulusion culling, fixes]", - "Jean-Patrick G (kilbith) [Audiovisuals]", - "Vincent Glize (Dumbeldor) [CSM]", - "bigfoot547 [CSM]", - "Rogier [Fixes]", - "Wuzzy [Audiovisuals]", - "Shara/Ezhh [Settings]", -} - -local previous_core_developers = { - "BlockMen", - "Maciej Kasatkin (RealBadAngel) [RIP]", - "Lisa Milne (darkrose) ", - "proller", - "Ilya Zhuravlev (xyz) ", - "PilzAdam ", - "est31 ", - "kahrl ", - "Ryan Kwolek (kwolekr) ", - "sapier", -} - -local previous_contributors = { - "Gregory Currie (gregorycu) [optimisation]", - "Diego Martínez (kaeza) ", - "T4im [Profiler]", - "TeTpaAka [Hand overriding, nametag colors]", - "HybridDog [Fixes]", - "Duane Robertson [MGValleys]", - "neoascetic [OS X Fixes]", - "TriBlade9 [Audiovisuals]", - "Jurgen Doser (doserj) [Fixes]", - "MirceaKitsune [Audiovisuals]", - "Guiseppe Bilotta (Oblomov) [Fixes]", - "matttpt [Fixes]", - "Nils Dagsson Moskopp (erlehmann) [Minetest Logo]", - "Jeija [HTTP, particles]", -} local function buildCreditList(source) local ret = {} @@ -99,26 +66,20 @@ return { name = "credits", caption = fgettext("Credits"), cbf_formspec = function(tabview, name, tabdata) - local version = core.get_version() - return "label[0.1,-0.1;Blockcolor Open Source Project, ver. " .. version.string .. "]" .. - "label[0.1,0.3;Copyright (c) 2018-2019 BlockColor Development Team]" .. - "label[0.1,0.7;Home page: https://github.com/MrChiantos/]" .. - "label[0.1,1.1;Licence: LGPLv3.0+ and CC-BY-SA 3.0]" .. + local logofile = defaulttexturedir .. "logo.png" + local version = core.get_version() + return "image[0.25,1;" .. core.formspec_escape(logofile) .. "]" .. "tablecolumns[color;text]" .. - "tableoptions[background=#999999;highlight=#00000000;border=true]" .. - "table[0,1.6;11.8,3.8;list_credits;" .. - "#FFFF00," .. fgettext("BlockColor Developers") .. ",," .. - buildCreditList(blockcolor_developers) .. ",,," .. - "#FFFF00," .. fgettext("MultiCraft Developers") .. ",," .. - buildCreditList(multicraft_developers) .. ",,," .. - "#FFFF00," .. fgettext("Minetest Developers") .. ",," .. - buildCreditList(core_developers) .. ",,," .. - "#FFFF00," .. fgettext("Active Contributors") .. ",," .. - buildCreditList(active_contributors) .. ",,," .. - "#FFFF00," .. fgettext("Previous Core Developers") ..",," .. - buildCreditList(previous_core_developers) .. ",,," .. - "#FFFF00," .. fgettext("Previous Contributors") .. ",," .. - buildCreditList(previous_contributors) .. "," .. - ";1]" + "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. + "table[5,0;6.75,6.05;list_credits;" .. + "#FFFF00," .. fgettext("Engine") .. ",," .. + buildCreditList(engine) .. "," .. + ",," .. + "#FFFF00," .. fgettext("Developers") .. ",," .. + buildCreditList(developers) .. "," .. + ",," .. + "#FFFF00," .. fgettext("Contributors") .. ",," .. + buildCreditList(contributors) .. "," + ..";1]" end } diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua index 0bb15330c..fc7a18ce6 100644 --- a/builtin/mainmenu/tab_local.lua +++ b/builtin/mainmenu/tab_local.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -22,6 +22,68 @@ local function current_game() return 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 + + local function game_buttonbar_button_handler(fields) + for key,value in pairs(fields) do + for j=1,#gamemgr.games,1 do + if ("game_btnbar_" .. gamemgr.games[j].id == key) then + mm_texture.update("singleplayer", gamemgr.games[j]) + core.set_topleft_text(gamemgr.games[j].name) + core.settings: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.settings: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 + end + end + + local btnbar = buttonbar_create("game_button_bar", + game_buttonbar_button_handler, + {x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15}) + + for i=1,#gamemgr.games,1 do + local btn_name = "game_btnbar_" .. gamemgr.games[i].id + + local image = nil + local text = nil + local tooltip = core.formspec_escape(gamemgr.games[i].name) + + if gamemgr.games[i].menuicon_path ~= nil and + gamemgr.games[i].menuicon_path ~= "" then + image = core.formspec_escape(gamemgr.games[i].menuicon_path) + else + + local part1 = gamemgr.games[i].id:sub(1,5) + local part2 = gamemgr.games[i].id:sub(6,10) + local part3 = gamemgr.games[i].id:sub(11) + + text = part1 .. "\n" .. part2 + if part3 ~= nil and + part3 ~= "" then + text = text .. "\n" .. part3 + end + end + btnbar:add_button(btn_name, text, image, tooltip) + end +end local function get_formspec(tabview, name, tabdata) local retval = "" @@ -30,32 +92,49 @@ local function get_formspec(tabview, name, tabdata) tonumber(core.settings:get("mainmenu_last_selected_world")) ) - retval = retval .. - "image_button[0,4.84;3.31,0.92;" .. - core.formspec_escape(defaulttexturedir .. - "blank.png") .. ";world_delete;;true;false]" .. - "image_button[3.14,4.84;3.3,0.92;" .. - core.formspec_escape(defaulttexturedir .. - "blank.png") .. ";world_create;;true;false]" - - local creative_mode = core.settings:get_bool("creative_mode") - retval = retval .. - "image_button[6.72,1.43;4.96,1.41;" .. - core.formspec_escape(defaulttexturedir .. - "blank.png") .. ";play;;true;false]" .. - "image_button[7.33,3.09;3.73,0.86;" .. - core.formspec_escape(defaulttexturedir .. - "local_creative_" .. - tostring(creative_mode) .. "_btn.png") .. - ";cb_creative_mode;;true;false]" .. - "textlist[-0.01,0;6.28,4.64;sp_worlds;" .. + "button[4,4.15;2.6,0.5;world_delete;".. fgettext("Delete") .. "]" .. + "button[6.5,4.15;2.8,0.5;world_create;".. fgettext("New") .. "]" .. + "button[9.2,4.15;2.55,0.5;world_configure;".. fgettext("Configure") .. "]" .. + "label[4,-0.25;".. fgettext("Select World:") .. "]".. + "checkbox[0.25,0.15;cb_server;".. fgettext("Host Server") ..";" .. + dump(core.settings:get_bool("enable_server")) .. "]" .. + "textlist[4,0.25;7.5,3.7;sp_worlds;" .. menu_render_worldlist() .. - ";" .. index .. ";true]" + ";" .. index .. "]" + + if core.settings:get_bool("enable_server") then + retval = retval .. + "button[8.5,5;3.25,0.5;play;".. fgettext("Host Game") .. "]" .. + "checkbox[0.25,0.8;cb_server_announce;" .. fgettext("Announce Server") .. ";" .. + dump(core.settings:get_bool("server_announce")) .. "]" .. + "label[0.25,1.9.2;" .. fgettext("Name/Password") .. "]" .. + "field[0.55,3;3.5,0.5;te_playername;;" .. + core.formspec_escape(core.settings:get("name")) .. "]" .. + "pwdfield[0.55,3.8;3.5,0.5;te_passwd;]" + + local bind_addr = core.settings:get("bind_address") + if bind_addr ~= nil and bind_addr ~= "" then + retval = retval .. + "field[0.55,4.0;2.25,0.5;te_serveraddr;" .. fgettext("Bind Address") .. ";" .. + core.formspec_escape(core.settings:get("bind_address")) .. "]" .. + "field[2.8,5.2;1.25,0.5;te_serverport;" .. fgettext("Port") .. ";" .. + core.formspec_escape(core.settings:get("port")) .. "]" + else + retval = retval .. + "field[0.55,5.2;3.5,0.5;te_serverport;" .. fgettext("Server Port") .. ";" .. + core.formspec_escape(core.settings:get("port")) .. "]" + end + else + retval = retval .. + "button[8.5,5;3.25,0.5;play;".. fgettext("Play Game") .. "]" + end + return retval end local function main_button_handler(this, fields, name, tabdata) + assert(name == "local") local world_doubleclick = false @@ -81,14 +160,6 @@ local function main_button_handler(this, fields, name, tabdata) return true end - if fields.cb_creative_mode then - local creative_mode = core.settings:get_bool("creative_mode") - core.settings:set("creative_mode", tostring((not creative_mode))) - core.settings:set("enable_damage", tostring(creative_mode)) - - return true - end - if fields["cb_server"] then core.settings:set("enable_server", fields["cb_server"]) @@ -106,7 +177,6 @@ local function main_button_handler(this, fields, name, tabdata) if fields["play"] ~= nil or world_doubleclick or fields["key_enter"] then local selected = core.get_textlist_index("sp_worlds") gamedata.selected_world = menudata.worldlist:get_raw_index(selected) - core.settings:set("maintab_LAST", "local") if core.settings:get_bool("enable_server") then if selected ~= nil and gamedata.selected_world ~= 0 then @@ -115,7 +185,6 @@ local function main_button_handler(this, fields, name, tabdata) gamedata.port = fields["te_serverport"] gamedata.address = "" - core.settings:set_bool("auto_connect", false) core.settings:set("port",gamedata.port) if fields["te_serveraddr"] ~= nil then core.settings:set("bind_address",fields["te_serveraddr"]) @@ -136,8 +205,6 @@ local function main_button_handler(this, fields, name, tabdata) else if selected ~= nil and gamedata.selected_world ~= 0 then gamedata.singleplayer = true - core.settings:set_bool("auto_connect", true) - core.settings:set("connect_time", os.time()) core.start() else gamedata.errormessage = @@ -152,6 +219,7 @@ local function main_button_handler(this, fields, name, tabdata) create_world_dlg:set_parent(this) this:hide() create_world_dlg:show() + mm_texture.update("singleplayer",current_game()) return true end @@ -168,6 +236,7 @@ local function main_button_handler(this, fields, name, tabdata) delete_world_dlg:set_parent(this) this:hide() delete_world_dlg:show() + mm_texture.update("singleplayer",current_game()) end end @@ -185,6 +254,7 @@ local function main_button_handler(this, fields, name, tabdata) configdialog:set_parent(this) this:hide() configdialog:show() + mm_texture.update("singleplayer",current_game()) end end @@ -193,12 +263,34 @@ local function main_button_handler(this, fields, name, tabdata) end local function on_change(type, old_tab, new_tab) + local buttonbar = ui.find_by_name("game_button_bar") + + if ( buttonbar == nil ) then + singleplayer_refresh_gamebar() + buttonbar = ui.find_by_name("game_button_bar") + end + + if (type == "ENTER") then + local game = current_game() + + if game then + menudata.worldlist:set_filtercriteria(game.id) + core.set_topleft_text(game.name) + mm_texture.update("singleplayer",game) + end + buttonbar:hide() + else + menudata.worldlist:set_filtercriteria(nil) + buttonbar:hide() + core.set_topleft_text("") + mm_texture.update(new_tab,nil) + end end -------------------------------------------------------------------------------- return { name = "local", - caption = fgettext("Singleplayer"), + caption = fgettext("Local Game"), cbf_formspec = get_formspec, cbf_button_handler = main_button_handler, on_change = on_change diff --git a/builtin/mainmenu/tab_mods.lua b/builtin/mainmenu/tab_mods.lua index 1be6bd796..7f95355a9 100644 --- a/builtin/mainmenu/tab_mods.lua +++ b/builtin/mainmenu/tab_mods.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index a480f6582..543638784 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -33,59 +33,40 @@ local function get_formspec(tabview, name, tabdata) local retval = -- Search - "field[0.2,0.1;5.71,1;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" .. - "image_button[5.52,-0.13;0.83,0.83;" .. core.formspec_escape(defaulttexturedir .. "search.png") - .. ";btn_mp_search;" .. "]" .. - "image_button[6.26,-0.13;0.83,0.83;" .. core.formspec_escape(defaulttexturedir .. "refresh.png") - .. ";btn_mp_refresh;;;true]" .. + --"field[0.15,0.35;6.05,0.27;te_search;;"..core.formspec_escape(tabdata.search_for).."]".. + --"button[5.8,0.1;2,0.1;btn_mp_search;" .. fgettext("Search") .. "]" .. -- Address / Port - "label[7.1,-0.3;" .. fgettext("Address:") .. "]" .. - "label[10.22,-0.3;" .. fgettext("Port:") .. "]" .. - "field[7.4,0.6;3.2,0.5;te_address;;" .. + "label[0.75,0.25;" .. fgettext("Address / Port") .. "]" .. + "field[1,1.15;3.25,0.5;te_address;;" .. core.formspec_escape(core.settings:get("address")) .. "]" .. - "field[10.5,0.6;1.85,0.5;te_port;;" .. + "field[4.1,1.15;1.4,0.5;te_port;;" .. core.formspec_escape(core.settings:get("remote_port")) .. "]" .. -- Name / Password - "label[7.1,0.85;" .. fgettext("Name:") .. "]" .. - "label[10.22,0.85;" .. fgettext("Password:") .. "]" .. - "field[7.4,1.75;3.2,0.5;te_name;;" .. + "label[0.75,1.65;" .. fgettext("Name / Password") .. " : ]" .. + "field[1,2.55;2.9,0.5;te_name;;" .. core.formspec_escape(core.settings:get("name")) .. "]" .. - "pwdfield[10.5,1.8;1.86,0.39;te_pwd;]" .. + "pwdfield[3.73,2.55;1.77,0.5;te_pwd;]" .. -- Description Background - "box[7.1,2.1;4.8,2.65;#999999]".. + "box[0,0;11.5,5.5;#999999]".. -- Connect - "button[9.4,5.045;2.7,0.505;btn_mp_connect;" .. fgettext("Connect") .. "]" + "button[9,4;2,0.5;btn_mp_connect;" .. fgettext("Connect") .. "]" if tabdata.fav_selected and fav_selected then if gamedata.fav then - retval = retval .. "image_button[7.1,4.91;0.83,0.83;" .. core.formspec_escape(defaulttexturedir .. "trash.png") - .. ";btn_delete_favorite;;;true]" + retval = retval .. "button[7.75,5.15;2.3,0.5;btn_delete_favorite;" .. + fgettext("Del. Favorite") .. "]" end if fav_selected.description then - retval = retval .. "textarea[7.5,2.3;4.8,2.9;;" .. + retval = retval .. "textarea[8.1,2.3;4.23,2.9;;" .. core.formspec_escape((gamedata.serverdescription or ""), true) .. ";]" end end - --favourites - retval = retval .. - "tableoptions[background=#00000000;border=false]" .. - "tablecolumns[" .. - image_column(fgettext("Favorite"), "favorite") .. ",align=center;" .. - image_column(fgettext("Ping")) .. ",padding=0.25;" .. - "color,span=3;" .. - "text,align=right;" .. -- clients - "text,align=center,padding=0.25;" .. -- "/" - "text,align=right,padding=0.25;" .. -- clients_max - image_column(fgettext("Server mode"), "damage") .. ",padding=0.25;" .. - image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" .. - "color,span=1;" .. - "text,padding=0.25]" .. - "table[-0.09,0.7;7,4.9;favourites;" + if menudata.search_result then for i = 1, #menudata.search_result do @@ -103,29 +84,26 @@ local function get_formspec(tabview, name, tabdata) retval = retval .. "," end - retval = retval .. render_serverlist_row(server, server.is_favorite, - server.server_id ~= nil) + retval = retval .. render_serverlist_row(server, server.is_favorite) end elseif #menudata.favorites > 0 then local favs = core.get_favorites("local") if #favs > 0 then for i = 1, #favs do - for j = 1, #menudata.favorites do - if menudata.favorites[j].address == favs[i].address and - menudata.favorites[j].port == favs[i].port then - table.insert(menudata.favorites, i, table.remove(menudata.favorites, j)) - end + for j = 1, #menudata.favorites do + if menudata.favorites[j].address == favs[i].address and + menudata.favorites[j].port == favs[i].port then + table.insert(menudata.favorites, i, table.remove(menudata.favorites, j)) end + end if favs[i].address ~= menudata.favorites[i].address then table.insert(menudata.favorites, i, favs[i]) end end end - retval = retval .. render_serverlist_row(menudata.favorites[1], (#favs > 0), - menudata.favorites[1].server_id ~= nil) + retval = retval .. render_serverlist_row(menudata.favorites[1], (#favs > 0)) for i = 2, #menudata.favorites do - retval = retval .. "," .. render_serverlist_row(menudata.favorites[i], - (i <= #favs), menudata.favorites[i].server_id ~= nil) + retval = retval .. "," .. render_serverlist_row(menudata.favorites[i], (i <= #favs)) end end @@ -244,7 +222,7 @@ local function main_button_handler(tabview, fields, name, tabdata) asyncOnlineFavourites() tabdata.fav_selected = nil - core.settings:set("address", "") + core.settings:set("address", "Blockcolor.net") core.settings:set("remote_port", "30000") return true end @@ -308,11 +286,6 @@ local function main_button_handler(tabview, fields, name, tabdata) return true end - if fields.btn_mp_refresh then - asyncOnlineFavourites() - return true - end - if (fields.btn_mp_connect or fields.key_enter) and fields.te_address ~= "" and fields.te_port then gamedata.playername = fields.te_name @@ -340,17 +313,6 @@ local function main_button_handler(tabview, fields, name, tabdata) gamedata.serverdescription = "" end - local auto_connect = false - for _, server in pairs(serverlist) do - if server.server_id and server.address == gamedata.address then - auto_connect = true - break - end - end - - core.settings:set_bool("auto_connect", auto_connect) - core.settings:set("connect_time", os.time()) - core.settings:set("maintab_LAST", "online") core.settings:set("address", fields.te_address) core.settings:set("remote_port", fields.te_port) @@ -368,7 +330,7 @@ end -------------------------------------------------------------------------------- return { name = "online", - caption = fgettext("Multiplayer"), + caption = fgettext("Play Online"), cbf_formspec = get_formspec, cbf_button_handler = main_button_handler, on_change = on_change diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua index c23cbe4a2..52bc8ead1 100644 --- a/builtin/mainmenu/tab_settings.lua +++ b/builtin/mainmenu/tab_settings.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -122,6 +122,58 @@ local function antialiasing_fname_to_name(fname) return 0 end +local function dlg_confirm_reset_formspec(data) + return "size[8,3]" .. + "label[1,1;" .. fgettext("Are you sure to reset your singleplayer world?") .. "]" .. + "button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;" .. fgettext("Yes") .. "]" .. + "button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;" .. fgettext("No") .. "]" +end + +local function dlg_confirm_reset_btnhandler(this, fields, dialogdata) + + if fields["dlg_reset_singleplayer_confirm"] ~= nil then + local worldlist = core.get_worlds() + local found_singleplayerworld = false + + for i = 1, #worldlist do + if worldlist[i].name == "singleplayerworld" then + found_singleplayerworld = true + gamedata.worldindex = i + end + end + + if found_singleplayerworld then + core.delete_world(gamedata.worldindex) + end + + core.create_world("singleplayerworld", 1) + worldlist = core.get_worlds() + found_singleplayerworld = false + + for i = 1, #worldlist do + if worldlist[i].name == "singleplayerworld" then + found_singleplayerworld = true + gamedata.worldindex = i + end + end + end + + this.parent:show() + this:hide() + this:delete() + return true +end + +local function showconfirm_reset(tabview) + local new_dlg = dialog_create("reset_spworld", + dlg_confirm_reset_formspec, + dlg_confirm_reset_btnhandler, + nil) + new_dlg:set_parent(tabview) + tabview:hide() + new_dlg:show() +end + local function formspec(tabview, name, tabdata) local tab_string = "box[0,0;3.75,4.5;#999999]" .. @@ -155,7 +207,11 @@ local function formspec(tabview, name, tabdata) "checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders") .. ";" .. dump(core.settings:get_bool("enable_shaders")) .. "]" - if PLATFORM ~= "Android" or PLATFORM ~= "iOS" then + if PLATFORM == "Android" then + tab_string = tab_string .. + "button[8,4.75;4.1,1;btn_reset_singleplayer;" + .. fgettext("Reset singleplayer world") .. "]" + else tab_string = tab_string .. "button[8,4.75;4,1;btn_change_keys;" .. fgettext("Change keys") .. "]" @@ -287,6 +343,10 @@ local function handle_settings_buttons(this, fields, tabname, tabdata) core.settings:set("touchtarget", fields["cb_touchscreen_target"]) return true end + if fields["btn_reset_singleplayer"] then + showconfirm_reset(this) + return true + end --Note dropdowns have to be handled LAST! local ddhandled = false diff --git a/builtin/mainmenu/tab_simple_main.lua b/builtin/mainmenu/tab_simple_main.lua new file mode 100644 index 000000000..de4ae1751 --- /dev/null +++ b/builtin/mainmenu/tab_simple_main.lua @@ -0,0 +1,220 @@ +--Minetest +--Copyright (C) 2013 sapier +-- +--This program is free software; you can redistribute it and/or modify +--it under the terms of the GNU Lesser General Public License as published by +--the Free Software Foundation; either version 2.1 of the License, or +--(at your option) any later version. +-- +--This program is distributed in the hope that it will be useful, +--but WITHOUT ANY WARRANTY; without even the implied warranty of +--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--GNU Lesser General Public License for more details. +-- +--You should have received a copy of the GNU Lesser General Public License along +--with this program; if not, write to the Free Software Foundation, Inc., +--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +-------------------------------------------------------------------------------- +local function get_formspec(tabview, name, tabdata) + -- Update the cached supported proto info, + -- it may have changed after a change by the settings menu. + common_update_cached_supp_proto() + local fav_selected = menudata.favorites[tabdata.fav_selected] + + local retval = + "label[9.5,0;".. fgettext("Name / Password") .. "]" .. + "field[0.25,3.35;5.5,0.5;te_address;;" .. + core.formspec_escape(core.settings:get("address")) .."]" .. + "field[5.75,3.35;2.25,0.5;te_port;;" .. + core.formspec_escape(core.settings:get("remote_port")) .."]" .. + "button[10,2.6;2,1.5;btn_mp_connect;".. fgettext("Connect") .. "]" .. + "field[9.8,1;2.6,0.5;te_name;;" .. + core.formspec_escape(core.settings:get("name")) .."]" .. + "pwdfield[9.8,2;2.6,0.5;te_pwd;]" + + + if tabdata.fav_selected and fav_selected then + if gamedata.fav then + retval = retval .. "button[7.7,2.6;2.3,1.5;btn_delete_favorite;" .. + fgettext("Del. Favorite") .. "]" + end + end + + retval = retval .. "tablecolumns[" .. + image_column(fgettext("Favorite"), "favorite") .. ";" .. + image_column(fgettext("Ping"), "") .. ",padding=0.25;" .. + "color,span=3;" .. + "text,align=right;" .. -- clients + "text,align=center,padding=0.25;" .. -- "/" + "text,align=right,padding=0.25;" .. -- clients_max + image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" .. + image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" .. + image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" .. + "color,span=1;" .. + "text,padding=1]" .. -- name + "table[-0.05,0;9.2,2.75;favourites;" + + if #menudata.favorites > 0 then + local favs = core.get_favorites("local") + if #favs > 0 then + for i = 1, #favs do + for j = 1, #menudata.favorites do + if menudata.favorites[j].address == favs[i].address and + menudata.favorites[j].port == favs[i].port then + table.insert(menudata.favorites, i, + table.remove(menudata.favorites, j)) + end + end + if favs[i].address ~= menudata.favorites[i].address then + table.insert(menudata.favorites, i, favs[i]) + end + end + end + retval = retval .. render_serverlist_row(menudata.favorites[1], (#favs > 0)) + for i = 2, #menudata.favorites do + retval = retval .. "," .. render_serverlist_row(menudata.favorites[i], (i <= #favs)) + end + end + + if tabdata.fav_selected then + retval = retval .. ";" .. tabdata.fav_selected .. "]" + else + retval = retval .. ";0]" + end + + -- separator + retval = retval .. "box[-0.28,3.75;12.4,0.1;#FFFFFF]" + + -- checkboxes + retval = retval .. + "checkbox[8.0,3.9;cb_creative;".. fgettext("Creative Mode") .. ";" .. + dump(core.settings:get_bool("creative_mode")) .. "]".. + "checkbox[8.0,4.4;cb_damage;".. fgettext("Enable Damage") .. ";" .. + dump(core.settings:get_bool("enable_damage")) .. "]" + -- buttons + retval = retval .. + "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 + +-------------------------------------------------------------------------------- +local function main_button_handler(tabview, fields, name, tabdata) + if fields.btn_start_singleplayer then + gamedata.selected_world = gamedata.worldindex + gamedata.singleplayer = true + core.start() + return true + end + + if fields.favourites then + local event = core.explode_table_event(fields.favourites) + if event.type == "CHG" then + if event.row <= #menudata.favorites then + gamedata.fav = false + local favs = core.get_favorites("local") + local fav = menudata.favorites[event.row] + local address = fav.address + local port = fav.port + gamedata.serverdescription = fav.description + + for i = 1, #favs do + if fav.address == favs[i].address and + fav.port == favs[i].port then + gamedata.fav = true + end + end + + if address and port then + core.settings:set("address", address) + core.settings:set("remote_port", port) + end + tabdata.fav_selected = event.row + end + return true + end + end + + if fields.btn_delete_favorite then + local current_favourite = core.get_table_index("favourites") + if not current_favourite then return end + + core.delete_favorite(current_favourite) + asyncOnlineFavourites() + tabdata.fav_selected = nil + + core.settings:set("address", "") + core.settings:set("remote_port", "30000") + return true + end + + if fields.cb_creative then + core.settings:set("creative_mode", fields.cb_creative) + return true + end + + if fields.cb_damage then + core.settings:set("enable_damage", fields.cb_damage) + return true + end + + if fields.btn_mp_connect or fields.key_enter then + gamedata.playername = fields.te_name + gamedata.password = fields.te_pwd + gamedata.address = fields.te_address + gamedata.port = fields.te_port + local fav_idx = core.get_textlist_index("favourites") + + if fav_idx and fav_idx <= #menudata.favorites and + menudata.favorites[fav_idx].address == fields.te_address and + menudata.favorites[fav_idx].port == fields.te_port then + local fav = menudata.favorites[fav_idx] + gamedata.servername = fav.name + gamedata.serverdescription = fav.description + + if menudata.favorites_is_public and + not is_server_protocol_compat_or_error( + fav.proto_min, fav.proto_max) then + return true + end + else + gamedata.servername = "" + gamedata.serverdescription = "" + end + + gamedata.selected_world = 0 + + core.settings:set("address", fields.te_address) + core.settings:set("remote_port", fields.te_port) + + core.start() + return true + end + + if fields.btn_config_sp_world then + local configdialog = create_configure_world_dlg(1) + if configdialog then + configdialog:set_parent(tabview) + tabview:hide() + configdialog:show() + end + return true + end +end + +-------------------------------------------------------------------------------- +local function on_activate(type,old_tab,new_tab) + if type == "LEAVE" then return end + asyncOnlineFavourites() +end + +-------------------------------------------------------------------------------- +return { + name = "main", + caption = fgettext("Main"), + cbf_formspec = get_formspec, + cbf_button_handler = main_button_handler, + on_change = on_activate +} diff --git a/builtin/mainmenu/tab_texturepacks.lua b/builtin/mainmenu/tab_texturepacks.lua index 6af1a0793..2957481cf 100644 --- a/builtin/mainmenu/tab_texturepacks.lua +++ b/builtin/mainmenu/tab_texturepacks.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, diff --git a/builtin/mainmenu/textures.lua b/builtin/mainmenu/textures.lua index c39f3d140..9ba4ade7e 100644 --- a/builtin/mainmenu/textures.lua +++ b/builtin/mainmenu/textures.lua @@ -3,7 +3,7 @@ -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by ---the Free Software Foundation; either version 3.0 of the License, or +--the Free Software Foundation; either version 2.1 of the License, or --(at your option) any later version. -- --This program is distributed in the hope that it will be useful, @@ -20,7 +20,8 @@ mm_texture = {} -------------------------------------------------------------------------------- function mm_texture.init() - mm_texture.defaulttexturedir = core.get_texturepath() .. DIR_DELIM .. "base" .. DIR_DELIM + mm_texture.defaulttexturedir = core.get_texturepath() .. DIR_DELIM .. "base" .. + DIR_DELIM .. "pack" .. DIR_DELIM mm_texture.basetexturedir = mm_texture.defaulttexturedir mm_texture.texturepack = core.settings:get("texture_path") @@ -171,7 +172,14 @@ function mm_texture.set_game(identifier, gamedetails) end function mm_texture.set_dirt_bg() + if mm_texture.texturepack ~= nil then + local path = mm_texture.texturepack .. DIR_DELIM .."default_dirt.png" + if core.set_background("background", path, true, 128) then + return true + end + end + -- Use universal fallback texture in textures/base/pack - local minimalpath = defaulttexturedir .. "bg.png" - core.set_background("background", minimalpath, true, 256) + local minimalpath = defaulttexturedir .. "menu_bg.png" + core.set_background("background", minimalpath, true, 128) end