mirror of
https://github.com/MCLx86/xtreemtest.git
synced 2025-12-06 15:35:32 +01:00
Initial commit
This commit is contained in:
32
builtin/mainmenu/async_event.lua
Normal file
32
builtin/mainmenu/async_event.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
core.async_jobs = {}
|
||||
|
||||
local function handle_job(jobid, serialized_retval)
|
||||
local retval = core.deserialize(serialized_retval)
|
||||
assert(type(core.async_jobs[jobid]) == "function")
|
||||
core.async_jobs[jobid](retval)
|
||||
core.async_jobs[jobid] = nil
|
||||
end
|
||||
|
||||
core.async_event_handler = handle_job
|
||||
|
||||
function core.handle_async(func, parameter, callback)
|
||||
-- Serialize function
|
||||
local serialized_func = string.dump(func)
|
||||
|
||||
assert(serialized_func ~= nil)
|
||||
|
||||
-- Serialize parameters
|
||||
local serialized_param = core.serialize(parameter)
|
||||
|
||||
if serialized_param == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local jobid = core.do_async_callback(serialized_func, serialized_param)
|
||||
|
||||
core.async_jobs[jobid] = callback
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
246
builtin/mainmenu/common.lua
Normal file
246
builtin/mainmenu/common.lua
Normal file
@@ -0,0 +1,246 @@
|
||||
--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.
|
||||
|
||||
-- Global menu data
|
||||
menudata = {}
|
||||
|
||||
-- Local cached values
|
||||
local min_supp_proto, max_supp_proto
|
||||
|
||||
function common_update_cached_supp_proto()
|
||||
min_supp_proto = core.get_min_supp_proto()
|
||||
max_supp_proto = core.get_max_supp_proto()
|
||||
end
|
||||
common_update_cached_supp_proto()
|
||||
|
||||
-- Menu helper functions
|
||||
|
||||
local function render_client_count(n)
|
||||
if n > 999 then return '99+'
|
||||
elseif n >= 0 then return tostring(n)
|
||||
else return '?' end
|
||||
end
|
||||
|
||||
local function configure_selected_world_params(idx)
|
||||
local worldconfig = pkgmgr.get_worldconfig(menudata.worldlist:get_list()[idx].path)
|
||||
if worldconfig.creative_mode then
|
||||
core.settings:set("creative_mode", worldconfig.creative_mode)
|
||||
end
|
||||
if worldconfig.enable_damage then
|
||||
core.settings:set("enable_damage", worldconfig.enable_damage)
|
||||
end
|
||||
end
|
||||
|
||||
function render_serverlist_row(spec)
|
||||
local text = ""
|
||||
if spec.name then
|
||||
text = text .. core.formspec_escape(spec.name:trim())
|
||||
elseif spec.address then
|
||||
text = text .. core.formspec_escape(spec.address:trim())
|
||||
if spec.port then
|
||||
text = text .. ":" .. spec.port
|
||||
end
|
||||
end
|
||||
|
||||
local grey_out = not spec.is_compatible
|
||||
|
||||
local details = {}
|
||||
|
||||
if spec.lag or spec.ping then
|
||||
local lag = (spec.lag or 0) * 1000 + (spec.ping or 0) * 250
|
||||
if lag <= 125 then
|
||||
table.insert(details, "1")
|
||||
elseif lag <= 175 then
|
||||
table.insert(details, "2")
|
||||
elseif lag <= 250 then
|
||||
table.insert(details, "3")
|
||||
else
|
||||
table.insert(details, "4")
|
||||
end
|
||||
else
|
||||
table.insert(details, "0")
|
||||
end
|
||||
|
||||
table.insert(details, ",")
|
||||
|
||||
local color = (grey_out and "#aaaaaa") or ((spec.is_favorite and "#ddddaa") or "#ffffff")
|
||||
if spec.clients and (spec.clients_max or 0) > 0 then
|
||||
local clients_percent = 100 * spec.clients / spec.clients_max
|
||||
|
||||
-- Choose a color depending on how many clients are connected
|
||||
-- (relatively to clients_max)
|
||||
local clients_color
|
||||
if grey_out then clients_color = '#aaaaaa'
|
||||
elseif spec.clients == 0 then clients_color = '' -- 0 players: default/white
|
||||
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
|
||||
end
|
||||
|
||||
table.insert(details, clients_color)
|
||||
table.insert(details, render_client_count(spec.clients) .. " / " ..
|
||||
render_client_count(spec.clients_max))
|
||||
else
|
||||
table.insert(details, color)
|
||||
table.insert(details, "?")
|
||||
end
|
||||
|
||||
if spec.creative then
|
||||
table.insert(details, "1") -- creative icon
|
||||
else
|
||||
table.insert(details, "0")
|
||||
end
|
||||
|
||||
if spec.pvp then
|
||||
table.insert(details, "2") -- pvp icon
|
||||
elseif spec.damage then
|
||||
table.insert(details, "1") -- heart icon
|
||||
else
|
||||
table.insert(details, "0")
|
||||
end
|
||||
|
||||
table.insert(details, color)
|
||||
table.insert(details, text)
|
||||
|
||||
return table.concat(details, ",")
|
||||
end
|
||||
---------------------------------------------------------------------------------
|
||||
os.tmpname = function()
|
||||
error('do not use') -- instead use core.get_temp_path()
|
||||
end
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function menu_render_worldlist()
|
||||
local retval = {}
|
||||
local current_worldlist = menudata.worldlist:get_list()
|
||||
|
||||
for i, v in ipairs(current_worldlist) do
|
||||
retval[#retval+1] = core.formspec_escape(v.name)
|
||||
end
|
||||
|
||||
return table.concat(retval, ",")
|
||||
end
|
||||
|
||||
function menu_handle_key_up_down(fields, textlist, settingname)
|
||||
local oldidx, newidx = core.get_textlist_index(textlist), 1
|
||||
if fields.key_up or fields.key_down then
|
||||
if fields.key_up and oldidx and oldidx > 1 then
|
||||
newidx = oldidx - 1
|
||||
elseif fields.key_down and oldidx and
|
||||
oldidx < menudata.worldlist:size() then
|
||||
newidx = oldidx + 1
|
||||
end
|
||||
core.settings:set(settingname, menudata.worldlist:get_raw_index(newidx))
|
||||
configure_selected_world_params(newidx)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
|
||||
local textlines = core.wrap_text(text, textlen, true)
|
||||
local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
|
||||
"," .. height .. ";" .. tl_name .. ";"
|
||||
|
||||
for i = 1, #textlines do
|
||||
textlines[i] = textlines[i]:gsub("\r", "")
|
||||
retval = retval .. core.formspec_escape(textlines[i]) .. ","
|
||||
end
|
||||
|
||||
retval = retval .. ";0;"
|
||||
if transparency then retval = retval .. "true" end
|
||||
retval = retval .. "]"
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
function is_server_protocol_compat(server_proto_min, server_proto_max)
|
||||
if (not server_proto_min) or (not server_proto_max) then
|
||||
-- There is no info. Assume the best and act as if we would be compatible.
|
||||
return true
|
||||
end
|
||||
return min_supp_proto <= server_proto_max and max_supp_proto >= server_proto_min
|
||||
end
|
||||
|
||||
function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
|
||||
if not is_server_protocol_compat(server_proto_min, server_proto_max) then
|
||||
local server_prot_ver_info, client_prot_ver_info
|
||||
local s_p_min = server_proto_min
|
||||
local s_p_max = server_proto_max
|
||||
|
||||
if s_p_min ~= s_p_max then
|
||||
server_prot_ver_info = fgettext_ne("Server supports protocol versions between $1 and $2. ",
|
||||
s_p_min, s_p_max)
|
||||
else
|
||||
server_prot_ver_info = fgettext_ne("Server enforces protocol version $1. ",
|
||||
s_p_min)
|
||||
end
|
||||
if min_supp_proto ~= max_supp_proto then
|
||||
client_prot_ver_info= fgettext_ne("We support protocol versions between version $1 and $2.",
|
||||
min_supp_proto, max_supp_proto)
|
||||
else
|
||||
client_prot_ver_info = fgettext_ne("We only support protocol version $1.", min_supp_proto)
|
||||
end
|
||||
gamedata.errormessage = fgettext_ne("Protocol version mismatch. ")
|
||||
.. server_prot_ver_info
|
||||
.. client_prot_ver_info
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function menu_worldmt(selected, setting, value)
|
||||
local world = menudata.worldlist:get_list()[selected]
|
||||
if world then
|
||||
local filename = world.path .. DIR_DELIM .. "world.mt"
|
||||
local world_conf = Settings(filename)
|
||||
|
||||
if value then
|
||||
if not world_conf:write() then
|
||||
core.log("error", "Failed to write world config file")
|
||||
end
|
||||
world_conf:set(setting, value)
|
||||
world_conf:write()
|
||||
else
|
||||
return world_conf:get(setting)
|
||||
end
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function menu_worldmt_legacy(selected)
|
||||
local modes_names = {"creative_mode", "enable_damage", "server_announce"}
|
||||
for _, mode_name in pairs(modes_names) do
|
||||
local mode_val = menu_worldmt(selected, mode_name)
|
||||
if mode_val then
|
||||
core.settings:set(mode_name, mode_val)
|
||||
else
|
||||
menu_worldmt(selected, mode_name, core.settings:get(mode_name))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function confirmation_formspec(message, confirm_id, confirm_label, cancel_id, cancel_label)
|
||||
return "size[10,2.5,true]" ..
|
||||
"label[0.5,0.5;" .. message .. "]" ..
|
||||
"style[" .. confirm_id .. ";bgcolor=red]" ..
|
||||
"button[0.5,1.5;2.5,0.5;" .. confirm_id .. ";" .. confirm_label .. "]" ..
|
||||
"button[7.0,1.5;2.5,0.5;" .. cancel_id .. ";" .. cancel_label .. "]"
|
||||
end
|
||||
409
builtin/mainmenu/dlg_config_world.lua
Normal file
409
builtin/mainmenu/dlg_config_world.lua
Normal file
@@ -0,0 +1,409 @@
|
||||
--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 enabled_all = false
|
||||
|
||||
local function modname_valid(name)
|
||||
return not name:find("[^a-z0-9_]")
|
||||
end
|
||||
|
||||
local function init_data(data)
|
||||
data.list = filterlist.create(
|
||||
pkgmgr.preparemodlist,
|
||||
pkgmgr.comparemod,
|
||||
function(element, uid)
|
||||
if element.name == uid then
|
||||
return true
|
||||
end
|
||||
end,
|
||||
function(element, criteria)
|
||||
if criteria.hide_game and
|
||||
element.is_game_content then
|
||||
return false
|
||||
end
|
||||
|
||||
if criteria.hide_modpackcontents and
|
||||
element.modpack ~= nil then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end,
|
||||
{
|
||||
worldpath = data.worldspec.path,
|
||||
gameid = data.worldspec.gameid
|
||||
})
|
||||
|
||||
if data.selected_mod > data.list:size() then
|
||||
data.selected_mod = 0
|
||||
end
|
||||
|
||||
data.list:set_filtercriteria({
|
||||
hide_game = data.hide_gamemods,
|
||||
hide_modpackcontents = data.hide_modpackcontents
|
||||
})
|
||||
data.list:add_sort_mechanism("alphabetic", sort_mod_list)
|
||||
data.list:set_sortmode("alphabetic")
|
||||
end
|
||||
|
||||
|
||||
-- Returns errors errors and a list of all enabled mods (inc. game and world mods)
|
||||
--
|
||||
-- `with_errors` is a table from mod virtual path to `{ type = "error" | "warning" }`.
|
||||
-- `enabled_mods_by_name` is a table from mod virtual path to `true`.
|
||||
--
|
||||
-- @param world_path Path to the world
|
||||
-- @param all_mods List of mods, with `enabled` property.
|
||||
-- @returns with_errors, enabled_mods_by_name
|
||||
local function check_mod_configuration(world_path, all_mods)
|
||||
-- Build up lookup tables for enabled mods and all mods by vpath
|
||||
local enabled_mod_paths = {}
|
||||
local all_mods_by_vpath = {}
|
||||
for _, mod in ipairs(all_mods) do
|
||||
if mod.type == "mod" then
|
||||
all_mods_by_vpath[mod.virtual_path] = mod
|
||||
end
|
||||
if mod.enabled then
|
||||
enabled_mod_paths[mod.virtual_path] = mod.path
|
||||
end
|
||||
end
|
||||
|
||||
-- Use the engine's mod configuration code to resolve dependencies and return any errors
|
||||
local config_status = core.check_mod_configuration(world_path, enabled_mod_paths)
|
||||
|
||||
-- Build the list of enabled mod virtual paths
|
||||
local enabled_mods_by_name = {}
|
||||
for _, mod in ipairs(config_status.satisfied_mods) do
|
||||
assert(mod.virtual_path ~= "")
|
||||
enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
|
||||
end
|
||||
for _, mod in ipairs(config_status.unsatisfied_mods) do
|
||||
assert(mod.virtual_path ~= "")
|
||||
enabled_mods_by_name[mod.name] = all_mods_by_vpath[mod.virtual_path] or mod
|
||||
end
|
||||
|
||||
-- Build the table of errors
|
||||
local with_error = {}
|
||||
for _, mod in ipairs(config_status.unsatisfied_mods) do
|
||||
local error = { type = "warning" }
|
||||
with_error[mod.virtual_path] = error
|
||||
|
||||
for _, depname in ipairs(mod.unsatisfied_depends) do
|
||||
if not enabled_mods_by_name[depname] then
|
||||
error.type = "error"
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return with_error, enabled_mods_by_name
|
||||
end
|
||||
|
||||
local function get_formspec(data)
|
||||
if not data.list then
|
||||
init_data(data)
|
||||
end
|
||||
|
||||
local all_mods = data.list:get_list()
|
||||
local with_error, enabled_mods_by_name = check_mod_configuration(data.worldspec.path, all_mods)
|
||||
|
||||
local mod = all_mods[data.selected_mod] or {name = ""}
|
||||
|
||||
local retval =
|
||||
"size[11.5,7.5,true]" ..
|
||||
"label[0.5,0;" .. fgettext("World:") .. "]" ..
|
||||
"label[1.75,0;" .. data.worldspec.name .. "]"
|
||||
|
||||
if mod.is_modpack or mod.type == "game" then
|
||||
local info = core.formspec_escape(
|
||||
core.get_content_info(mod.path).description)
|
||||
if info == "" then
|
||||
if mod.is_modpack then
|
||||
info = fgettext("No modpack description provided.")
|
||||
else
|
||||
info = fgettext("No game description provided.")
|
||||
end
|
||||
end
|
||||
retval = retval ..
|
||||
"textarea[0.25,0.7;5.75,7.2;;" .. info .. ";]"
|
||||
else
|
||||
local hard_deps, soft_deps = pkgmgr.get_dependencies(mod.path)
|
||||
|
||||
-- Add error messages to dep lists
|
||||
if mod.enabled or mod.is_game_content then
|
||||
for i, dep_name in ipairs(hard_deps) do
|
||||
local dep = enabled_mods_by_name[dep_name]
|
||||
if not dep then
|
||||
hard_deps[i] = mt_color_red .. dep_name .. " " .. fgettext("(Unsatisfied)")
|
||||
elseif with_error[dep.virtual_path] then
|
||||
hard_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
|
||||
else
|
||||
hard_deps[i] = mt_color_green .. dep_name
|
||||
end
|
||||
end
|
||||
for i, dep_name in ipairs(soft_deps) do
|
||||
local dep = enabled_mods_by_name[dep_name]
|
||||
if dep and with_error[dep.virtual_path] then
|
||||
soft_deps[i] = mt_color_orange .. dep_name .. " " .. fgettext("(Enabled, has error)")
|
||||
elseif dep then
|
||||
soft_deps[i] = mt_color_green .. dep_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local hard_deps_str = table.concat(hard_deps, ",")
|
||||
local soft_deps_str = table.concat(soft_deps, ",")
|
||||
|
||||
retval = retval ..
|
||||
"label[0,0.7;" .. fgettext("Mod:") .. "]" ..
|
||||
"label[0.75,0.7;" .. mod.name .. "]"
|
||||
|
||||
if hard_deps_str == "" then
|
||||
if soft_deps_str == "" then
|
||||
retval = retval ..
|
||||
"label[0,1.25;" ..
|
||||
fgettext("No (optional) dependencies") .. "]"
|
||||
else
|
||||
retval = retval ..
|
||||
"label[0,1.25;" .. fgettext("No hard dependencies") ..
|
||||
"]" ..
|
||||
"label[0,1.75;" .. fgettext("Optional dependencies:") ..
|
||||
"]" ..
|
||||
"textlist[0,2.25;5,4;world_config_optdepends;" ..
|
||||
soft_deps_str .. ";0]"
|
||||
end
|
||||
else
|
||||
if soft_deps_str == "" then
|
||||
retval = retval ..
|
||||
"label[0,1.25;" .. fgettext("Dependencies:") .. "]" ..
|
||||
"textlist[0,1.75;5,4;world_config_depends;" ..
|
||||
hard_deps_str .. ";0]" ..
|
||||
"label[0,6;" .. fgettext("No optional dependencies") .. "]"
|
||||
else
|
||||
retval = retval ..
|
||||
"label[0,1.25;" .. fgettext("Dependencies:") .. "]" ..
|
||||
"textlist[0,1.75;5,2.125;world_config_depends;" ..
|
||||
hard_deps_str .. ";0]" ..
|
||||
"label[0,3.9;" .. fgettext("Optional dependencies:") ..
|
||||
"]" ..
|
||||
"textlist[0,4.375;5,1.8;world_config_optdepends;" ..
|
||||
soft_deps_str .. ";0]"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"button[3.25,7;2.5,0.5;btn_config_world_save;" ..
|
||||
fgettext("Save") .. "]" ..
|
||||
"button[5.75,7;2.5,0.5;btn_config_world_cancel;" ..
|
||||
fgettext("Cancel") .. "]" ..
|
||||
"button[9,7;2.5,0.5;btn_config_world_cdb;" ..
|
||||
fgettext("Find More Mods") .. "]"
|
||||
|
||||
if mod.name ~= "" and not mod.is_game_content then
|
||||
if mod.is_modpack then
|
||||
if pkgmgr.is_modpack_entirely_enabled(data, mod.name) then
|
||||
retval = retval ..
|
||||
"button[5.5,0.125;3,0.5;btn_mp_disable;" ..
|
||||
fgettext("Disable modpack") .. "]"
|
||||
else
|
||||
retval = retval ..
|
||||
"button[5.5,0.125;3,0.5;btn_mp_enable;" ..
|
||||
fgettext("Enable modpack") .. "]"
|
||||
end
|
||||
else
|
||||
retval = retval ..
|
||||
"checkbox[5.5,-0.125;cb_mod_enable;" .. fgettext("enabled") ..
|
||||
";" .. tostring(mod.enabled) .. "]"
|
||||
end
|
||||
end
|
||||
if enabled_all then
|
||||
retval = retval ..
|
||||
"button[8.95,0.125;2.5,0.5;btn_disable_all_mods;" ..
|
||||
fgettext("Disable all") .. "]"
|
||||
else
|
||||
retval = retval ..
|
||||
"button[8.95,0.125;2.5,0.5;btn_enable_all_mods;" ..
|
||||
fgettext("Enable all") .. "]"
|
||||
end
|
||||
|
||||
local use_technical_names = core.settings:get_bool("show_technical_names")
|
||||
|
||||
return retval ..
|
||||
"tablecolumns[color;tree;image,align=inline,width=1.5,0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") ..
|
||||
",1=" .. core.formspec_escape(defaulttexturedir .. "checkbox_16_white.png") ..
|
||||
",2=" .. core.formspec_escape(defaulttexturedir .. "error_icon_orange.png") ..
|
||||
",3=" .. core.formspec_escape(defaulttexturedir .. "error_icon_red.png") .. ";text]" ..
|
||||
"table[5.5,0.75;5.75,6;world_config_modlist;" ..
|
||||
pkgmgr.render_packagelist(data.list, use_technical_names, with_error) .. ";" .. data.selected_mod .."]"
|
||||
end
|
||||
|
||||
local function handle_buttons(this, fields)
|
||||
if fields.world_config_modlist then
|
||||
local event = core.explode_table_event(fields.world_config_modlist)
|
||||
this.data.selected_mod = event.row
|
||||
core.settings:set("world_config_selected_mod", event.row)
|
||||
|
||||
if event.type == "DCL" then
|
||||
pkgmgr.enable_mod(this)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.key_enter then
|
||||
pkgmgr.enable_mod(this)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.cb_mod_enable ~= nil then
|
||||
pkgmgr.enable_mod(this, core.is_yes(fields.cb_mod_enable))
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_mp_enable ~= nil or
|
||||
fields.btn_mp_disable then
|
||||
pkgmgr.enable_mod(this, fields.btn_mp_enable ~= nil)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_config_world_save then
|
||||
local filename = this.data.worldspec.path .. DIR_DELIM .. "world.mt"
|
||||
|
||||
local worldfile = Settings(filename)
|
||||
local mods = worldfile:to_table()
|
||||
|
||||
local rawlist = this.data.list:get_raw_list()
|
||||
local was_set = {}
|
||||
|
||||
for i = 1, #rawlist do
|
||||
local mod = rawlist[i]
|
||||
if not mod.is_modpack and
|
||||
not mod.is_game_content then
|
||||
if modname_valid(mod.name) then
|
||||
if mod.enabled then
|
||||
worldfile:set("load_mod_" .. mod.name, mod.virtual_path)
|
||||
was_set[mod.name] = true
|
||||
elseif not was_set[mod.name] then
|
||||
worldfile:set("load_mod_" .. mod.name, "false")
|
||||
end
|
||||
elseif mod.enabled then
|
||||
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..
|
||||
"d \"$1\" as it contains disallowed characters. " ..
|
||||
"Only characters [a-z0-9_] are allowed.",
|
||||
mod.name)
|
||||
end
|
||||
mods["load_mod_" .. mod.name] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove mods that are not present anymore
|
||||
for key in pairs(mods) do
|
||||
if key:sub(1, 9) == "load_mod_" then
|
||||
worldfile:remove(key)
|
||||
end
|
||||
end
|
||||
|
||||
if not worldfile:write() then
|
||||
core.log("error", "Failed to write world config file")
|
||||
end
|
||||
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_config_world_cancel then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_config_world_cdb then
|
||||
this.data.list = nil
|
||||
|
||||
local dlg = create_store_dlg("mod")
|
||||
dlg:set_parent(this)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_enable_all_mods then
|
||||
local list = this.data.list:get_raw_list()
|
||||
|
||||
-- When multiple copies of a mod are installed, we need to avoid enabling multiple of them
|
||||
-- at a time. So lets first collect all the enabled mods, and then use this to exclude
|
||||
-- multiple enables.
|
||||
|
||||
local was_enabled = {}
|
||||
for i = 1, #list do
|
||||
if not list[i].is_game_content
|
||||
and not list[i].is_modpack and list[i].enabled then
|
||||
was_enabled[list[i].name] = true
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, #list do
|
||||
if not list[i].is_game_content and not list[i].is_modpack and
|
||||
not was_enabled[list[i].name] then
|
||||
list[i].enabled = true
|
||||
was_enabled[list[i].name] = true
|
||||
end
|
||||
end
|
||||
|
||||
enabled_all = true
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_disable_all_mods then
|
||||
local list = this.data.list:get_raw_list()
|
||||
|
||||
for i = 1, #list do
|
||||
if not list[i].is_game_content
|
||||
and not list[i].is_modpack then
|
||||
list[i].enabled = false
|
||||
end
|
||||
end
|
||||
enabled_all = false
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function create_configure_world_dlg(worldidx)
|
||||
local dlg = dialog_create("sp_config_world", get_formspec, handle_buttons)
|
||||
|
||||
dlg.data.selected_mod = tonumber(
|
||||
core.settings:get("world_config_selected_mod")) or 0
|
||||
|
||||
dlg.data.worldspec = core.get_worlds()[worldidx]
|
||||
if not dlg.data.worldspec then
|
||||
dlg:delete()
|
||||
return
|
||||
end
|
||||
|
||||
dlg.data.worldconfig = pkgmgr.get_worldconfig(dlg.data.worldspec.path)
|
||||
|
||||
if not dlg.data.worldconfig or not dlg.data.worldconfig.id or
|
||||
dlg.data.worldconfig.id == "" then
|
||||
dlg:delete()
|
||||
return
|
||||
end
|
||||
|
||||
return dlg
|
||||
end
|
||||
1062
builtin/mainmenu/dlg_contentstore.lua
Normal file
1062
builtin/mainmenu/dlg_contentstore.lua
Normal file
File diff suppressed because it is too large
Load Diff
488
builtin/mainmenu/dlg_create_world.lua
Normal file
488
builtin/mainmenu/dlg_create_world.lua
Normal file
@@ -0,0 +1,488 @@
|
||||
--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 table_to_flags(ftable)
|
||||
-- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
|
||||
local str = {}
|
||||
for flag, is_set in pairs(ftable) do
|
||||
str[#str + 1] = is_set and flag or ("no" .. flag)
|
||||
end
|
||||
return table.concat(str, ",")
|
||||
end
|
||||
|
||||
-- Same as check_flag but returns a string
|
||||
local function strflag(flags, flag)
|
||||
return (flags[flag] == true) and "true" or "false"
|
||||
end
|
||||
|
||||
local cb_caverns = { "caverns", fgettext("Caverns"),
|
||||
fgettext("Very large caverns deep in the underground") }
|
||||
|
||||
local flag_checkboxes = {
|
||||
v5 = {
|
||||
cb_caverns,
|
||||
},
|
||||
v7 = {
|
||||
cb_caverns,
|
||||
{ "ridges", fgettext("Rivers"), fgettext("Sea level rivers") },
|
||||
{ "mountains", fgettext("Mountains") },
|
||||
{ "floatlands", fgettext("Floatlands (experimental)"),
|
||||
fgettext("Floating landmasses in the sky") },
|
||||
},
|
||||
carpathian = {
|
||||
cb_caverns,
|
||||
{ "rivers", fgettext("Rivers"), fgettext("Sea level rivers") },
|
||||
},
|
||||
valleys = {
|
||||
{ "altitude_chill", fgettext("Altitude chill"),
|
||||
fgettext("Reduces heat with altitude") },
|
||||
{ "altitude_dry", fgettext("Altitude dry"),
|
||||
fgettext("Reduces humidity with altitude") },
|
||||
{ "humid_rivers", fgettext("Humid rivers"),
|
||||
fgettext("Increases humidity around rivers") },
|
||||
{ "vary_river_depth", fgettext("Vary river depth"),
|
||||
fgettext("Low humidity and high heat causes shallow or dry rivers") },
|
||||
},
|
||||
flat = {
|
||||
cb_caverns,
|
||||
{ "hills", fgettext("Hills") },
|
||||
{ "lakes", fgettext("Lakes") },
|
||||
},
|
||||
fractal = {
|
||||
{ "terrain", fgettext("Additional terrain"),
|
||||
fgettext("Generate non-fractal terrain: Oceans and underground") },
|
||||
},
|
||||
v6 = {
|
||||
{ "trees", fgettext("Trees and jungle grass") },
|
||||
{ "flat", fgettext("Flat terrain") },
|
||||
{ "mudflow", fgettext("Mud flow"), fgettext("Terrain surface erosion") },
|
||||
-- Biome settings are in mgv6_biomes below
|
||||
},
|
||||
}
|
||||
|
||||
local mgv6_biomes = {
|
||||
{
|
||||
fgettext("Temperate, Desert, Jungle, Tundra, Taiga"),
|
||||
{jungles = true, snowbiomes = true}
|
||||
},
|
||||
{
|
||||
fgettext("Temperate, Desert, Jungle"),
|
||||
{jungles = true, snowbiomes = false}
|
||||
},
|
||||
{
|
||||
fgettext("Temperate, Desert"),
|
||||
{jungles = false, snowbiomes = false}
|
||||
},
|
||||
}
|
||||
|
||||
local function create_world_formspec(dialogdata)
|
||||
|
||||
-- Point the player to ContentDB when no games are found
|
||||
if #pkgmgr.games == 0 then
|
||||
return "size[8,2.5,true]" ..
|
||||
"style[label_button;border=false]" ..
|
||||
"button[0.5,0.5;7,0.5;label_button;" ..
|
||||
fgettext("You have no games installed.") .. "]" ..
|
||||
"button[0.5,1.5;2.5,0.5;world_create_open_cdb;" .. fgettext("Install a game") .. "]" ..
|
||||
"button[5.0,1.5;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
|
||||
end
|
||||
|
||||
local current_mg = dialogdata.mg
|
||||
local mapgens = core.get_mapgen_names()
|
||||
|
||||
local gameid = core.settings:get("menu_last_game")
|
||||
|
||||
local flags = dialogdata.flags
|
||||
|
||||
local game = pkgmgr.find_by_gameid(gameid)
|
||||
if game == nil then
|
||||
-- should never happen but just pick the first game
|
||||
game = pkgmgr.get_game(1)
|
||||
core.settings:set("menu_last_game", game.id)
|
||||
end
|
||||
|
||||
local disallowed_mapgen_settings = {}
|
||||
if game ~= nil then
|
||||
local gameconfig = Settings(game.path.."/game.conf")
|
||||
|
||||
local allowed_mapgens = (gameconfig:get("allowed_mapgens") or ""):split()
|
||||
for key, value in pairs(allowed_mapgens) do
|
||||
allowed_mapgens[key] = value:trim()
|
||||
end
|
||||
|
||||
local disallowed_mapgens = (gameconfig:get("disallowed_mapgens") or ""):split()
|
||||
for key, value in pairs(disallowed_mapgens) do
|
||||
disallowed_mapgens[key] = value:trim()
|
||||
end
|
||||
|
||||
if #allowed_mapgens > 0 then
|
||||
for i = #mapgens, 1, -1 do
|
||||
if table.indexof(allowed_mapgens, mapgens[i]) == -1 then
|
||||
table.remove(mapgens, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #disallowed_mapgens > 0 then
|
||||
for i = #mapgens, 1, -1 do
|
||||
if table.indexof(disallowed_mapgens, mapgens[i]) > 0 then
|
||||
table.remove(mapgens, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ds = (gameconfig:get("disallowed_mapgen_settings") or ""):split()
|
||||
for _, value in pairs(ds) do
|
||||
disallowed_mapgen_settings[value:trim()] = true
|
||||
end
|
||||
end
|
||||
|
||||
local mglist = ""
|
||||
local selindex
|
||||
do -- build the list of mapgens
|
||||
local i = 1
|
||||
local first_mg
|
||||
for k, v in pairs(mapgens) do
|
||||
if not first_mg then
|
||||
first_mg = v
|
||||
end
|
||||
if current_mg == v then
|
||||
selindex = i
|
||||
end
|
||||
i = i + 1
|
||||
mglist = mglist .. core.formspec_escape(v) .. ","
|
||||
end
|
||||
if not selindex then
|
||||
selindex = 1
|
||||
current_mg = first_mg
|
||||
end
|
||||
mglist = mglist:sub(1, -2)
|
||||
end
|
||||
|
||||
-- The logic of the flag element IDs is as follows:
|
||||
-- "flag_main_foo-bar-baz" controls dialogdata.flags["main"]["foo_bar_baz"]
|
||||
-- see the buttonhandler for the implementation of this
|
||||
|
||||
local mg_main_flags = function(mapgen, y)
|
||||
if mapgen == "singlenode" then
|
||||
return "", y
|
||||
end
|
||||
if disallowed_mapgen_settings["mg_flags"] then
|
||||
return "", y
|
||||
end
|
||||
|
||||
local form = "checkbox[0," .. y .. ";flag_main_caves;" ..
|
||||
fgettext("Caves") .. ";"..strflag(flags.main, "caves").."]"
|
||||
y = y + 0.5
|
||||
|
||||
form = form .. "checkbox[0,"..y..";flag_main_dungeons;" ..
|
||||
fgettext("Dungeons") .. ";"..strflag(flags.main, "dungeons").."]"
|
||||
y = y + 0.5
|
||||
|
||||
local d_name = fgettext("Decorations")
|
||||
local d_tt
|
||||
if mapgen == "v6" then
|
||||
d_tt = fgettext("Structures appearing on the terrain (no effect on trees and jungle grass created by v6)")
|
||||
else
|
||||
d_tt = fgettext("Structures appearing on the terrain, typically trees and plants")
|
||||
end
|
||||
form = form .. "checkbox[0,"..y..";flag_main_decorations;" ..
|
||||
d_name .. ";" ..
|
||||
strflag(flags.main, "decorations").."]" ..
|
||||
"tooltip[flag_mg_decorations;" ..
|
||||
d_tt ..
|
||||
"]"
|
||||
y = y + 0.5
|
||||
|
||||
form = form .. "tooltip[flag_main_caves;" ..
|
||||
fgettext("Network of tunnels and caves")
|
||||
.. "]"
|
||||
return form, y
|
||||
end
|
||||
|
||||
local mg_specific_flags = function(mapgen, y)
|
||||
if not flag_checkboxes[mapgen] then
|
||||
return "", y
|
||||
end
|
||||
if disallowed_mapgen_settings["mg"..mapgen.."_spflags"] then
|
||||
return "", y
|
||||
end
|
||||
local form = ""
|
||||
for _, tab in pairs(flag_checkboxes[mapgen]) do
|
||||
local id = "flag_"..mapgen.."_"..tab[1]:gsub("_", "-")
|
||||
form = form .. ("checkbox[0,%f;%s;%s;%s]"):
|
||||
format(y, id, tab[2], strflag(flags[mapgen], tab[1]))
|
||||
|
||||
if tab[3] then
|
||||
form = form .. "tooltip["..id..";"..tab[3].."]"
|
||||
end
|
||||
y = y + 0.5
|
||||
end
|
||||
|
||||
if mapgen ~= "v6" then
|
||||
-- No special treatment
|
||||
return form, y
|
||||
end
|
||||
-- Special treatment for v6 (add biome widgets)
|
||||
|
||||
-- Biome type (jungles, snowbiomes)
|
||||
local biometype
|
||||
if flags.v6.snowbiomes == true then
|
||||
biometype = 1
|
||||
elseif flags.v6.jungles == true then
|
||||
biometype = 2
|
||||
else
|
||||
biometype = 3
|
||||
end
|
||||
y = y + 0.3
|
||||
|
||||
form = form .. "label[0,"..(y+0.1)..";" .. fgettext("Biomes") .. "]"
|
||||
y = y + 0.6
|
||||
|
||||
form = form .. "dropdown[0,"..y..";6.3;mgv6_biomes;"
|
||||
for b=1, #mgv6_biomes do
|
||||
form = form .. mgv6_biomes[b][1]
|
||||
if b < #mgv6_biomes then
|
||||
form = form .. ","
|
||||
end
|
||||
end
|
||||
form = form .. ";" .. biometype.. "]"
|
||||
|
||||
-- biomeblend
|
||||
y = y + 0.55
|
||||
form = form .. "checkbox[0,"..y..";flag_v6_biomeblend;" ..
|
||||
fgettext("Biome blending") .. ";"..strflag(flags.v6, "biomeblend").."]" ..
|
||||
"tooltip[flag_v6_biomeblend;" ..
|
||||
fgettext("Smooth transition between biomes") .. "]"
|
||||
|
||||
return form, y
|
||||
end
|
||||
|
||||
local y_start = 0.0
|
||||
local y = y_start
|
||||
local str_flags, str_spflags
|
||||
local label_flags, label_spflags = "", ""
|
||||
y = y + 0.3
|
||||
str_flags, y = mg_main_flags(current_mg, y)
|
||||
if str_flags ~= "" then
|
||||
label_flags = "label[0,"..y_start..";" .. fgettext("Mapgen flags") .. "]"
|
||||
y_start = y + 0.4
|
||||
else
|
||||
y_start = 0.0
|
||||
end
|
||||
y = y_start + 0.3
|
||||
str_spflags = mg_specific_flags(current_mg, y)
|
||||
if str_spflags ~= "" then
|
||||
label_spflags = "label[0,"..y_start..";" .. fgettext("Mapgen-specific flags") .. "]"
|
||||
end
|
||||
|
||||
local retval =
|
||||
"size[12.25,7,true]" ..
|
||||
|
||||
-- Left side
|
||||
"container[0,0]"..
|
||||
"field[0.3,0.6;6,0.5;te_world_name;" ..
|
||||
fgettext("World name") ..
|
||||
";" .. core.formspec_escape(dialogdata.worldname) .. "]" ..
|
||||
"set_focus[te_world_name;false]"
|
||||
|
||||
if not disallowed_mapgen_settings["seed"] then
|
||||
|
||||
retval = retval .. "field[0.3,1.7;6,0.5;te_seed;" ..
|
||||
fgettext("Seed") ..
|
||||
";".. core.formspec_escape(dialogdata.seed) .. "]"
|
||||
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"label[0,2;" .. fgettext("Mapgen") .. "]"..
|
||||
"dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]"
|
||||
|
||||
-- Warning if only devtest is installed
|
||||
if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
|
||||
retval = retval ..
|
||||
"container[0,3.5]" ..
|
||||
"box[0,0;5.8,1.7;#ff8800]" ..
|
||||
"textarea[0.4,0.1;6,1.8;;;"..
|
||||
fgettext("Development Test is meant for developers.") .. "]" ..
|
||||
"button[1,1;4,0.5;world_create_open_cdb;" .. fgettext("Install another game") .. "]" ..
|
||||
"container_end[]"
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"container_end[]" ..
|
||||
|
||||
-- Right side
|
||||
"container[6.2,0]"..
|
||||
label_flags .. str_flags ..
|
||||
label_spflags .. str_spflags ..
|
||||
"container_end[]"..
|
||||
|
||||
-- Menu buttons
|
||||
"button[3.25,6.5;3,0.5;world_create_confirm;" .. fgettext("Create") .. "]" ..
|
||||
"button[6.25,6.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
|
||||
|
||||
return retval
|
||||
|
||||
end
|
||||
|
||||
local function create_world_buttonhandler(this, fields)
|
||||
|
||||
if fields["world_create_open_cdb"] then
|
||||
local dlg = create_store_dlg("game")
|
||||
dlg:set_parent(this.parent)
|
||||
this:delete()
|
||||
this.parent:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["world_create_confirm"] or
|
||||
fields["key_enter"] then
|
||||
|
||||
local worldname = fields["te_world_name"]
|
||||
local game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
|
||||
|
||||
local message
|
||||
if game == nil then
|
||||
message = fgettext("No game selected")
|
||||
end
|
||||
|
||||
if message == nil then
|
||||
-- For unnamed worlds use the generated name 'world<number>',
|
||||
-- where the number increments: it is set to 1 larger than the largest
|
||||
-- generated name number found.
|
||||
if worldname == "" then
|
||||
local worldnum_max = 0
|
||||
for _, world in ipairs(menudata.worldlist:get_list()) do
|
||||
if world.name:match("^world%d+$") then
|
||||
local worldnum = tonumber(world.name:sub(6))
|
||||
worldnum_max = math.max(worldnum_max, worldnum)
|
||||
end
|
||||
end
|
||||
worldname = "world" .. worldnum_max + 1
|
||||
end
|
||||
|
||||
if menudata.worldlist:uid_exists_raw(worldname) then
|
||||
message = fgettext("A world named \"$1\" already exists", worldname)
|
||||
end
|
||||
end
|
||||
|
||||
if message == nil then
|
||||
this.data.seed = fields["te_seed"] or ""
|
||||
this.data.mg = fields["dd_mapgen"]
|
||||
|
||||
-- actual names as used by engine
|
||||
local settings = {
|
||||
fixed_map_seed = this.data.seed,
|
||||
mg_name = this.data.mg,
|
||||
mg_flags = table_to_flags(this.data.flags.main),
|
||||
mgv5_spflags = table_to_flags(this.data.flags.v5),
|
||||
mgv6_spflags = table_to_flags(this.data.flags.v6),
|
||||
mgv7_spflags = table_to_flags(this.data.flags.v7),
|
||||
mgfractal_spflags = table_to_flags(this.data.flags.fractal),
|
||||
mgcarpathian_spflags = table_to_flags(this.data.flags.carpathian),
|
||||
mgvalleys_spflags = table_to_flags(this.data.flags.valleys),
|
||||
mgflat_spflags = table_to_flags(this.data.flags.flat),
|
||||
}
|
||||
message = core.create_world(worldname, gameindex, settings)
|
||||
end
|
||||
|
||||
if message == nil then
|
||||
core.settings:set("menu_last_game", game.id)
|
||||
menudata.worldlist:set_filtercriteria(game.id)
|
||||
menudata.worldlist:refresh()
|
||||
core.settings:set("mainmenu_last_selected_world",
|
||||
menudata.worldlist:raw_index_by_uid(worldname))
|
||||
end
|
||||
|
||||
gamedata.errormessage = message
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
this.data.worldname = fields["te_world_name"]
|
||||
this.data.seed = fields["te_seed"] or ""
|
||||
|
||||
if fields["games"] then
|
||||
local gameindex = core.get_textlist_index("games")
|
||||
core.settings:set("menu_last_game", pkgmgr.games[gameindex].id)
|
||||
return true
|
||||
end
|
||||
|
||||
for k,v in pairs(fields) do
|
||||
local split = string.split(k, "_", nil, 3)
|
||||
if split and split[1] == "flag" then
|
||||
-- We replaced the underscore of flag names with a dash.
|
||||
local flag = string.gsub(split[3], "-", "_")
|
||||
local ftable = this.data.flags[split[2]]
|
||||
assert(ftable)
|
||||
ftable[flag] = v == "true"
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if fields["world_create_cancel"] then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["mgv6_biomes"] then
|
||||
local entry = core.formspec_escape(fields["mgv6_biomes"])
|
||||
for b=1, #mgv6_biomes do
|
||||
if entry == mgv6_biomes[b][1] then
|
||||
local ftable = this.data.flags.v6
|
||||
ftable.jungles = mgv6_biomes[b][2].jungles
|
||||
ftable.snowbiomes = mgv6_biomes[b][2].snowbiomes
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if fields["dd_mapgen"] then
|
||||
this.data.mg = fields["dd_mapgen"]
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function create_create_world_dlg()
|
||||
local retval = dialog_create("sp_create_world",
|
||||
create_world_formspec,
|
||||
create_world_buttonhandler,
|
||||
nil)
|
||||
retval.data = {
|
||||
worldname = "",
|
||||
-- settings the world is created with:
|
||||
seed = core.settings:get("fixed_map_seed") or "",
|
||||
mg = core.settings:get("mg_name"),
|
||||
flags = {
|
||||
main = core.settings:get_flags("mg_flags"),
|
||||
v5 = core.settings:get_flags("mgv5_spflags"),
|
||||
v6 = core.settings:get_flags("mgv6_spflags"),
|
||||
v7 = core.settings:get_flags("mgv7_spflags"),
|
||||
fractal = core.settings:get_flags("mgfractal_spflags"),
|
||||
carpathian = core.settings:get_flags("mgcarpathian_spflags"),
|
||||
valleys = core.settings:get_flags("mgvalleys_spflags"),
|
||||
flat = core.settings:get_flags("mgflat_spflags"),
|
||||
}
|
||||
}
|
||||
|
||||
return retval
|
||||
end
|
||||
70
builtin/mainmenu/dlg_delete_content.lua
Normal file
70
builtin/mainmenu/dlg_delete_content.lua
Normal file
@@ -0,0 +1,70 @@
|
||||
--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)
|
||||
return confirmation_formspec(
|
||||
fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name),
|
||||
'dlg_delete_content_confirm', fgettext("Delete"),
|
||||
'dlg_delete_content_cancel', fgettext("Cancel"))
|
||||
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
|
||||
58
builtin/mainmenu/dlg_delete_world.lua
Normal file
58
builtin/mainmenu/dlg_delete_world.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
--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_world_formspec(dialogdata)
|
||||
return confirmation_formspec(
|
||||
fgettext("Delete World \"$1\"?", dialogdata.delete_name),
|
||||
'world_delete_confirm', fgettext("Delete"),
|
||||
'world_delete_cancel', fgettext("Cancel"))
|
||||
end
|
||||
|
||||
local function delete_world_buttonhandler(this, fields)
|
||||
if fields["world_delete_confirm"] then
|
||||
if this.data.delete_index > 0 and
|
||||
this.data.delete_index <= #menudata.worldlist:get_raw_list() then
|
||||
core.delete_world(this.data.delete_index)
|
||||
menudata.worldlist:refresh()
|
||||
end
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["world_delete_cancel"] then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function create_delete_world_dlg(name_to_del, index_to_del)
|
||||
assert(name_to_del ~= nil and type(name_to_del) == "string" and name_to_del ~= "")
|
||||
assert(index_to_del ~= nil and type(index_to_del) == "number")
|
||||
|
||||
local retval = dialog_create("delete_world",
|
||||
delete_world_formspec,
|
||||
delete_world_buttonhandler,
|
||||
nil)
|
||||
retval.data.delete_name = name_to_del
|
||||
retval.data.delete_index = index_to_del
|
||||
|
||||
return retval
|
||||
end
|
||||
123
builtin/mainmenu/dlg_register.lua
Normal file
123
builtin/mainmenu/dlg_register.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
--Minetest
|
||||
--Copyright (C) 2022 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 function register_formspec(dialogdata)
|
||||
local title = fgettext("Joining $1", dialogdata.server and dialogdata.server.name or dialogdata.address)
|
||||
local buttons_y = 4 + 1.3
|
||||
if dialogdata.error then
|
||||
buttons_y = buttons_y + 0.8
|
||||
end
|
||||
|
||||
local retval = {
|
||||
"formspec_version[4]",
|
||||
"size[8,", tostring(buttons_y + 1.175), "]",
|
||||
"set_focus[", (dialogdata.name ~= "" and "password" or "name"), "]",
|
||||
"label[0.375,0.8;", title, "]",
|
||||
"field[0.375,1.575;7.25,0.8;name;", core.formspec_escape(fgettext("Name")), ";",
|
||||
core.formspec_escape(dialogdata.name), "]",
|
||||
"pwdfield[0.375,2.875;7.25,0.8;password;", core.formspec_escape(fgettext("Password")), "]",
|
||||
"pwdfield[0.375,4.175;7.25,0.8;password_2;", core.formspec_escape(fgettext("Confirm Password")), "]"
|
||||
}
|
||||
|
||||
if dialogdata.error then
|
||||
table.insert_all(retval, {
|
||||
"box[0.375,", tostring(buttons_y - 0.9), ";7.25,0.6;darkred]",
|
||||
"label[0.625,", tostring(buttons_y - 0.6), ";", core.formspec_escape(dialogdata.error), "]",
|
||||
})
|
||||
end
|
||||
|
||||
table.insert_all(retval, {
|
||||
"container[0.375,", tostring(buttons_y), "]",
|
||||
"button[0,0;2.5,0.8;dlg_register_confirm;", fgettext("Register"), "]",
|
||||
"button[4.75,0;2.5,0.8;dlg_register_cancel;", fgettext("Cancel"), "]",
|
||||
"container_end[]",
|
||||
})
|
||||
|
||||
return table.concat(retval, "")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function register_buttonhandler(this, fields)
|
||||
this.data.name = fields.name
|
||||
this.data.error = nil
|
||||
|
||||
if fields.dlg_register_confirm or fields.key_enter then
|
||||
if fields.name == "" then
|
||||
this.data.error = fgettext("Missing name")
|
||||
return true
|
||||
end
|
||||
if fields.password ~= fields.password_2 then
|
||||
this.data.error = fgettext("Passwords do not match")
|
||||
return true
|
||||
end
|
||||
|
||||
gamedata.playername = fields.name
|
||||
gamedata.password = fields.password
|
||||
gamedata.address = this.data.address
|
||||
gamedata.port = this.data.port
|
||||
gamedata.allow_login_or_register = "register"
|
||||
gamedata.selected_world = 0
|
||||
|
||||
assert(gamedata.address and gamedata.port)
|
||||
|
||||
local server = this.data.server
|
||||
if server then
|
||||
serverlistmgr.add_favorite(server)
|
||||
gamedata.servername = server.name
|
||||
gamedata.serverdescription = server.description
|
||||
else
|
||||
gamedata.servername = ""
|
||||
gamedata.serverdescription = ""
|
||||
|
||||
serverlistmgr.add_favorite({
|
||||
address = gamedata.address,
|
||||
port = gamedata.port,
|
||||
})
|
||||
end
|
||||
|
||||
core.settings:set("name", fields.name)
|
||||
core.settings:set("address", gamedata.address)
|
||||
core.settings:set("remote_port", gamedata.port)
|
||||
|
||||
core.start()
|
||||
end
|
||||
|
||||
if fields["dlg_register_cancel"] then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function create_register_dialog(address, port, server)
|
||||
assert(address)
|
||||
assert(type(port) == "number")
|
||||
|
||||
local retval = dialog_create("dlg_register",
|
||||
register_formspec,
|
||||
register_buttonhandler,
|
||||
nil)
|
||||
retval.data.address = address
|
||||
retval.data.port = port
|
||||
retval.data.server = server
|
||||
retval.data.name = core.settings:get("name") or ""
|
||||
return retval
|
||||
end
|
||||
73
builtin/mainmenu/dlg_rename_modpack.lua
Normal file
73
builtin/mainmenu/dlg_rename_modpack.lua
Normal file
@@ -0,0 +1,73 @@
|
||||
--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 rename_modpack_formspec(dialogdata)
|
||||
local retval =
|
||||
"size[11.5,4.5,true]" ..
|
||||
"button[3.25,3.5;2.5,0.5;dlg_rename_modpack_confirm;"..
|
||||
fgettext("Accept") .. "]" ..
|
||||
"button[5.75,3.5;2.5,0.5;dlg_rename_modpack_cancel;"..
|
||||
fgettext("Cancel") .. "]"
|
||||
|
||||
local input_y = 2
|
||||
if dialogdata.mod.is_name_explicit then
|
||||
retval = retval .. "textarea[1,0.2;10,2;;;" ..
|
||||
fgettext("This modpack has an explicit name given in its modpack.conf " ..
|
||||
"which will override any renaming here.") .. "]"
|
||||
input_y = 2.5
|
||||
end
|
||||
retval = retval ..
|
||||
"field[2.5," .. input_y .. ";7,0.5;te_modpack_name;" ..
|
||||
fgettext("Rename Modpack:") .. ";" .. dialogdata.mod.dir_name .. "]"
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function rename_modpack_buttonhandler(this, fields)
|
||||
if fields["dlg_rename_modpack_confirm"] ~= nil then
|
||||
local oldpath = this.data.mod.path
|
||||
local targetpath = this.data.mod.parent_dir .. DIR_DELIM .. fields["te_modpack_name"]
|
||||
os.rename(oldpath, targetpath)
|
||||
pkgmgr.refresh_globals()
|
||||
pkgmgr.selected_mod = pkgmgr.global_mods:get_current_index(
|
||||
pkgmgr.global_mods:raw_index_by_uid(fields["te_modpack_name"]))
|
||||
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["dlg_rename_modpack_cancel"] then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function create_rename_modpack_dlg(modpack)
|
||||
|
||||
local retval = dialog_create("dlg_delete_mod",
|
||||
rename_modpack_formspec,
|
||||
rename_modpack_buttonhandler,
|
||||
nil)
|
||||
retval.data.mod = modpack
|
||||
return retval
|
||||
end
|
||||
1137
builtin/mainmenu/dlg_settings_advanced.lua
Normal file
1137
builtin/mainmenu/dlg_settings_advanced.lua
Normal file
File diff suppressed because it is too large
Load Diff
172
builtin/mainmenu/dlg_version_info.lua
Normal file
172
builtin/mainmenu/dlg_version_info.lua
Normal file
@@ -0,0 +1,172 @@
|
||||
--[[
|
||||
Minetest
|
||||
Copyright (C) 2018-2020 SmallJoker, 2022 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.
|
||||
]]
|
||||
|
||||
if not core.get_http_api then
|
||||
function check_new_version()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local function version_info_formspec(data)
|
||||
local cur_ver = core.get_version()
|
||||
local title = fgettext("A new $1 version is available", cur_ver.project)
|
||||
local message =
|
||||
fgettext("Installed version: $1\nNew version: $2\n" ..
|
||||
"Visit $3 to find out how to get the newest version and stay up to date" ..
|
||||
" with features and bugfixes.",
|
||||
cur_ver.string, data.new_version or "", data.url or "")
|
||||
|
||||
local fs = {
|
||||
"formspec_version[3]",
|
||||
"size[12.8,7]",
|
||||
"style_type[label;textcolor=#0E0]",
|
||||
"label[0.5,0.8;", core.formspec_escape(title), "]",
|
||||
"textarea[0.4,1.6;12,3.4;;;",
|
||||
core.formspec_escape(message), "]",
|
||||
"container[0.4,5.8]",
|
||||
"button[0.0,0;4.0,0.8;version_check_visit;", fgettext("Visit website"), "]",
|
||||
"button[4.5,0;3.5,0.8;version_check_remind;", fgettext("Later"), "]",
|
||||
"button[8.5.5,0;3.5,0.8;version_check_never;", fgettext("Never"), "]",
|
||||
"container_end[]",
|
||||
}
|
||||
|
||||
return table.concat(fs, "")
|
||||
end
|
||||
|
||||
local function version_info_buttonhandler(this, fields)
|
||||
if fields.version_check_remind then
|
||||
-- Erase last known, user will be reminded again at next check
|
||||
core.settings:set("update_last_known", "")
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
if fields.version_check_never then
|
||||
core.settings:set("update_last_checked", "disabled")
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
if fields.version_check_visit then
|
||||
if type(this.data.url) == "string" then
|
||||
core.open_url(this.data.url)
|
||||
end
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function create_version_info_dlg(new_version, url)
|
||||
assert(type(new_version) == "string")
|
||||
assert(type(url) == "string")
|
||||
|
||||
local retval = dialog_create("version_info",
|
||||
version_info_formspec,
|
||||
version_info_buttonhandler,
|
||||
nil)
|
||||
|
||||
retval.data.new_version = new_version
|
||||
retval.data.url = url
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
local function get_current_version_code()
|
||||
-- Format: Major.Minor.Patch
|
||||
-- Convert to MMMNNNPPP
|
||||
local cur_string = core.get_version().string
|
||||
local cur_major, cur_minor, cur_patch = cur_string:match("^(%d+).(%d+).(%d+)")
|
||||
|
||||
if not cur_patch then
|
||||
core.log("error", "Failed to parse version numbers (invalid tag format?)")
|
||||
return
|
||||
end
|
||||
|
||||
return (cur_major * 1000 + cur_minor) * 1000 + cur_patch
|
||||
end
|
||||
|
||||
local function on_version_info_received(json)
|
||||
local maintab = ui.find_by_name("maintab")
|
||||
if maintab.hidden then
|
||||
-- Another dialog is open, abort.
|
||||
return
|
||||
end
|
||||
|
||||
local known_update = tonumber(core.settings:get("update_last_known")) or 0
|
||||
|
||||
-- Format: MMNNPPP (Major, Minor, Patch)
|
||||
local new_number = type(json.latest) == "table" and json.latest.version_code
|
||||
if type(new_number) ~= "number" then
|
||||
core.log("error", "Failed to read version number (invalid response?)")
|
||||
return
|
||||
end
|
||||
|
||||
local cur_number = get_current_version_code()
|
||||
if new_number <= known_update or new_number < cur_number then
|
||||
return
|
||||
end
|
||||
|
||||
-- Also consider updating from 1.2.3-dev to 1.2.3
|
||||
if new_number == cur_number and not core.get_version().is_dev then
|
||||
return
|
||||
end
|
||||
|
||||
core.settings:set("update_last_known", tostring(new_number))
|
||||
|
||||
-- Show version info dialog (once)
|
||||
maintab:hide()
|
||||
|
||||
local version_info_dlg = create_version_info_dlg(json.latest.version, json.latest.url)
|
||||
version_info_dlg:set_parent(maintab)
|
||||
version_info_dlg:show()
|
||||
|
||||
ui.update()
|
||||
end
|
||||
|
||||
function check_new_version()
|
||||
local url = core.settings:get("update_information_url")
|
||||
if core.settings:get("update_last_checked") == "disabled" or
|
||||
url == "" then
|
||||
-- Never show any updates
|
||||
return
|
||||
end
|
||||
|
||||
local time_now = os.time()
|
||||
local time_checked = tonumber(core.settings:get("update_last_checked")) or 0
|
||||
if time_now - time_checked < 2 * 24 * 3600 then
|
||||
-- Check interval of 2 entire days
|
||||
return
|
||||
end
|
||||
|
||||
core.settings:set("update_last_checked", tostring(time_now))
|
||||
|
||||
core.handle_async(function(params)
|
||||
local http = core.get_http_api()
|
||||
return http.fetch_sync(params)
|
||||
end, { url = url }, function(result)
|
||||
local json = result.succeeded and core.parse_json(result.data)
|
||||
if type(json) ~= "table" or not json.latest then
|
||||
core.log("error", "Failed to read JSON output from " .. url ..
|
||||
", status code = " .. result.code)
|
||||
return
|
||||
end
|
||||
|
||||
on_version_info_received(json)
|
||||
end)
|
||||
end
|
||||
203
builtin/mainmenu/game_theme.lua
Normal file
203
builtin/mainmenu/game_theme.lua
Normal file
@@ -0,0 +1,203 @@
|
||||
--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.
|
||||
|
||||
|
||||
mm_game_theme = {}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.init()
|
||||
mm_game_theme.defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
|
||||
DIR_DELIM .. "pack" .. DIR_DELIM
|
||||
mm_game_theme.basetexturedir = mm_game_theme.defaulttexturedir
|
||||
|
||||
mm_game_theme.texturepack = core.settings:get("texture_path")
|
||||
|
||||
mm_game_theme.gameid = nil
|
||||
|
||||
mm_game_theme.music_handle = nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.update(tab,gamedetails)
|
||||
if tab ~= "singleplayer" then
|
||||
mm_game_theme.reset()
|
||||
return
|
||||
end
|
||||
|
||||
if gamedetails == nil then
|
||||
return
|
||||
end
|
||||
|
||||
mm_game_theme.update_game(gamedetails)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.reset()
|
||||
mm_game_theme.gameid = nil
|
||||
local have_bg = false
|
||||
local have_overlay = mm_game_theme.set_generic("overlay")
|
||||
|
||||
if not have_overlay then
|
||||
have_bg = mm_game_theme.set_generic("background")
|
||||
end
|
||||
|
||||
mm_game_theme.clear("header")
|
||||
mm_game_theme.clear("footer")
|
||||
core.set_clouds(false)
|
||||
|
||||
mm_game_theme.set_generic("footer")
|
||||
mm_game_theme.set_generic("header")
|
||||
|
||||
if not have_bg then
|
||||
if core.settings:get_bool("menu_clouds") then
|
||||
core.set_clouds(true)
|
||||
else
|
||||
mm_game_theme.set_dirt_bg()
|
||||
end
|
||||
end
|
||||
|
||||
if mm_game_theme.music_handle ~= nil then
|
||||
core.sound_stop(mm_game_theme.music_handle)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.update_game(gamedetails)
|
||||
if mm_game_theme.gameid == gamedetails.id then
|
||||
return
|
||||
end
|
||||
|
||||
local have_bg = false
|
||||
local have_overlay = mm_game_theme.set_game("overlay",gamedetails)
|
||||
|
||||
if not have_overlay then
|
||||
have_bg = mm_game_theme.set_game("background",gamedetails)
|
||||
end
|
||||
|
||||
mm_game_theme.clear("header")
|
||||
mm_game_theme.clear("footer")
|
||||
core.set_clouds(false)
|
||||
|
||||
if not have_bg then
|
||||
|
||||
if core.settings:get_bool("menu_clouds") then
|
||||
core.set_clouds(true)
|
||||
else
|
||||
mm_game_theme.set_dirt_bg()
|
||||
end
|
||||
end
|
||||
|
||||
mm_game_theme.set_game("footer",gamedetails)
|
||||
mm_game_theme.set_game("header",gamedetails)
|
||||
|
||||
mm_game_theme.gameid = gamedetails.id
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.clear(identifier)
|
||||
core.set_background(identifier,"")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.set_generic(identifier)
|
||||
--try texture pack first
|
||||
if mm_game_theme.texturepack ~= nil then
|
||||
local path = mm_game_theme.texturepack .. DIR_DELIM .."menu_" ..
|
||||
identifier .. ".png"
|
||||
if core.set_background(identifier,path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if mm_game_theme.defaulttexturedir ~= nil then
|
||||
local path = mm_game_theme.defaulttexturedir .. DIR_DELIM .."menu_" ..
|
||||
identifier .. ".png"
|
||||
if core.set_background(identifier,path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.set_game(identifier, gamedetails)
|
||||
|
||||
if gamedetails == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
mm_game_theme.set_music(gamedetails)
|
||||
|
||||
if mm_game_theme.texturepack ~= nil then
|
||||
local path = mm_game_theme.texturepack .. DIR_DELIM ..
|
||||
gamedetails.id .. "_menu_" .. identifier .. ".png"
|
||||
if core.set_background(identifier, path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Find out how many randomized textures the game provides
|
||||
local n = 0
|
||||
local filename
|
||||
local menu_files = core.get_dir_list(gamedetails.path .. DIR_DELIM .. "menu", false)
|
||||
for i = 1, #menu_files do
|
||||
filename = identifier .. "." .. i .. ".png"
|
||||
if table.indexof(menu_files, filename) == -1 then
|
||||
n = i - 1
|
||||
break
|
||||
end
|
||||
end
|
||||
-- Select random texture, 0 means standard texture
|
||||
n = math.random(0, n)
|
||||
if n == 0 then
|
||||
filename = identifier .. ".png"
|
||||
else
|
||||
filename = identifier .. "." .. n .. ".png"
|
||||
end
|
||||
|
||||
local path = gamedetails.path .. DIR_DELIM .. "menu" ..
|
||||
DIR_DELIM .. filename
|
||||
if core.set_background(identifier, path) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.set_dirt_bg()
|
||||
if mm_game_theme.texturepack ~= nil then
|
||||
local path = mm_game_theme.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 .. "menu_bg.png"
|
||||
core.set_background("background", minimalpath, true, 128)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_game_theme.set_music(gamedetails)
|
||||
if mm_game_theme.music_handle ~= nil then
|
||||
core.sound_stop(mm_game_theme.music_handle)
|
||||
end
|
||||
local music_path = gamedetails.path .. DIR_DELIM .. "menu" .. DIR_DELIM .. "theme"
|
||||
mm_game_theme.music_handle = core.sound_play(music_path, true)
|
||||
end
|
||||
136
builtin/mainmenu/generate_from_settingtypes.lua
Normal file
136
builtin/mainmenu/generate_from_settingtypes.lua
Normal file
@@ -0,0 +1,136 @@
|
||||
local settings = ...
|
||||
|
||||
local concat = table.concat
|
||||
local insert = table.insert
|
||||
local sprintf = string.format
|
||||
local rep = string.rep
|
||||
|
||||
local minetest_example_header = [[
|
||||
# This file contains a list of all available settings and their default value for minetest.conf
|
||||
|
||||
# By default, all the settings are commented and not functional.
|
||||
# Uncomment settings by removing the preceding #.
|
||||
|
||||
# minetest.conf is read by default from:
|
||||
# ../minetest.conf
|
||||
# ../../minetest.conf
|
||||
# Any other path can be chosen by passing the path as a parameter
|
||||
# to the program, eg. "minetest.exe --config ../minetest.conf.example".
|
||||
|
||||
# Further documentation:
|
||||
# http://wiki.minetest.net/
|
||||
|
||||
]]
|
||||
|
||||
local group_format_template = [[
|
||||
# %s = {
|
||||
# offset = %s,
|
||||
# scale = %s,
|
||||
# spread = (%s, %s, %s),
|
||||
# seed = %s,
|
||||
# octaves = %s,
|
||||
# persistence = %s,
|
||||
# lacunarity = %s,
|
||||
# flags =%s
|
||||
# }
|
||||
|
||||
]]
|
||||
|
||||
local function create_minetest_conf_example()
|
||||
local result = { minetest_example_header }
|
||||
for _, entry in ipairs(settings) do
|
||||
if entry.type == "category" then
|
||||
if entry.level == 0 then
|
||||
insert(result, "#\n# " .. entry.name .. "\n#\n\n")
|
||||
else
|
||||
insert(result, rep("#", entry.level))
|
||||
insert(result, "# " .. entry.name .. "\n\n")
|
||||
end
|
||||
else
|
||||
local group_format = false
|
||||
if entry.noise_params and entry.values then
|
||||
if entry.type == "noise_params_2d" or entry.type == "noise_params_3d" then
|
||||
group_format = true
|
||||
end
|
||||
end
|
||||
if entry.comment ~= "" then
|
||||
for _, comment_line in ipairs(entry.comment:split("\n", true)) do
|
||||
if comment_line == "" then
|
||||
insert(result, "#\n")
|
||||
else
|
||||
insert(result, "# " .. comment_line .. "\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
insert(result, "# type: " .. entry.type)
|
||||
if entry.min then
|
||||
insert(result, " min: " .. entry.min)
|
||||
end
|
||||
if entry.max then
|
||||
insert(result, " max: " .. entry.max)
|
||||
end
|
||||
if entry.values and entry.noise_params == nil then
|
||||
insert(result, " values: " .. concat(entry.values, ", "))
|
||||
end
|
||||
if entry.possible then
|
||||
insert(result, " possible values: " .. concat(entry.possible, ", "))
|
||||
end
|
||||
insert(result, "\n")
|
||||
if group_format == true then
|
||||
local flags = entry.values[10]
|
||||
if flags ~= "" then
|
||||
flags = " "..flags
|
||||
end
|
||||
insert(result, sprintf(group_format_template, entry.name, entry.values[1],
|
||||
entry.values[2], entry.values[3], entry.values[4], entry.values[5],
|
||||
entry.values[6], entry.values[7], entry.values[8], entry.values[9],
|
||||
flags))
|
||||
else
|
||||
local append
|
||||
if entry.default ~= "" then
|
||||
append = " " .. entry.default
|
||||
end
|
||||
insert(result, sprintf("# %s =%s\n\n", entry.name, append or ""))
|
||||
end
|
||||
end
|
||||
end
|
||||
return concat(result)
|
||||
end
|
||||
|
||||
local translation_file_header = [[
|
||||
// This file is automatically generated
|
||||
// It contains a bunch of fake gettext calls, to tell xgettext about the strings in config files
|
||||
// To update it, refer to the bottom of builtin/mainmenu/dlg_settings_advanced.lua
|
||||
|
||||
fake_function() {]]
|
||||
|
||||
local function create_translation_file()
|
||||
local result = { translation_file_header }
|
||||
for _, entry in ipairs(settings) do
|
||||
if entry.type == "category" then
|
||||
insert(result, sprintf("\tgettext(%q);", entry.name))
|
||||
else
|
||||
if entry.readable_name then
|
||||
insert(result, sprintf("\tgettext(%q);", entry.readable_name))
|
||||
end
|
||||
if entry.comment ~= "" then
|
||||
local comment_escaped = entry.comment:gsub("\n", "\\n")
|
||||
comment_escaped = comment_escaped:gsub("\"", "\\\"")
|
||||
insert(result, "\tgettext(\"" .. comment_escaped .. "\");")
|
||||
end
|
||||
end
|
||||
end
|
||||
insert(result, "}\n")
|
||||
return concat(result, "\n")
|
||||
end
|
||||
|
||||
local file = assert(io.open("minetest.conf.example", "w"))
|
||||
file:write(create_minetest_conf_example())
|
||||
file:close()
|
||||
|
||||
file = assert(io.open("src/settings_translation_file.cpp", "w"))
|
||||
-- If 'minetest.conf.example' appears in the 'bin' folder, the line below may have to be
|
||||
-- used instead. The file will also appear in the 'bin' folder.
|
||||
--file = assert(io.open("settings_translation_file.cpp", "w"))
|
||||
file:write(create_translation_file())
|
||||
file:close()
|
||||
131
builtin/mainmenu/init.lua
Normal file
131
builtin/mainmenu/init.lua
Normal file
@@ -0,0 +1,131 @@
|
||||
--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.
|
||||
|
||||
mt_color_grey = "#AAAAAA"
|
||||
mt_color_blue = "#6389FF"
|
||||
mt_color_lightblue = "#99CCFF"
|
||||
mt_color_green = "#72FF63"
|
||||
mt_color_dark_green = "#25C191"
|
||||
mt_color_orange = "#FF8800"
|
||||
mt_color_red = "#FF3300"
|
||||
|
||||
local menupath = core.get_mainmenu_path()
|
||||
local basepath = core.get_builtin_path()
|
||||
defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
|
||||
DIR_DELIM .. "pack" .. DIR_DELIM
|
||||
|
||||
dofile(basepath .. "common" .. DIR_DELIM .. "filterlist.lua")
|
||||
dofile(basepath .. "fstk" .. DIR_DELIM .. "buttonbar.lua")
|
||||
dofile(basepath .. "fstk" .. DIR_DELIM .. "dialog.lua")
|
||||
dofile(basepath .. "fstk" .. DIR_DELIM .. "tabview.lua")
|
||||
dofile(basepath .. "fstk" .. DIR_DELIM .. "ui.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "async_event.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "common.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "pkgmgr.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "serverlistmgr.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "game_theme.lua")
|
||||
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_contentstore.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
|
||||
|
||||
local tabs = {}
|
||||
|
||||
tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
|
||||
tabs.content = dofile(menupath .. DIR_DELIM .. "tab_content.lua")
|
||||
tabs.about = dofile(menupath .. DIR_DELIM .. "tab_about.lua")
|
||||
tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua")
|
||||
tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua")
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function main_event_handler(tabview, event)
|
||||
if event == "MenuQuit" then
|
||||
core.close()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
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
|
||||
end
|
||||
)
|
||||
|
||||
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_game_theme.init()
|
||||
|
||||
-- Create main tabview
|
||||
local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = 0})
|
||||
-- note: size would be 15.5,7.1 in real coordinates mode
|
||||
|
||||
tv_main:set_autosave_tab(true)
|
||||
tv_main:add(tabs.local_game)
|
||||
tv_main:add(tabs.play_online)
|
||||
|
||||
tv_main:add(tabs.content)
|
||||
tv_main:add(tabs.settings)
|
||||
tv_main:add(tabs.about)
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
-- In case the folder of the last selected game has been deleted,
|
||||
-- display "Minetest" as a header
|
||||
if tv_main.current_tab == "local" then
|
||||
local game = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
|
||||
if game == nil then
|
||||
mm_game_theme.reset()
|
||||
end
|
||||
end
|
||||
|
||||
ui.set_default("maintab")
|
||||
check_new_version()
|
||||
tv_main:show()
|
||||
ui.update()
|
||||
end
|
||||
|
||||
init_globals()
|
||||
929
builtin/mainmenu/pkgmgr.lua
Normal file
929
builtin/mainmenu/pkgmgr.lua
Normal file
@@ -0,0 +1,929 @@
|
||||
--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_last_folder(text,count)
|
||||
local parts = text:split(DIR_DELIM)
|
||||
|
||||
if count == nil then
|
||||
return parts[#parts]
|
||||
end
|
||||
|
||||
local retval = ""
|
||||
for i=1,count,1 do
|
||||
retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
local function cleanup_path(temppath)
|
||||
|
||||
local parts = temppath:split("-")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath .. "_"
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
parts = temppath:split(".")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath .. "_"
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
parts = temppath:split("'")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath .. ""
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
parts = temppath:split(" ")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
return temppath
|
||||
end
|
||||
|
||||
local function load_texture_packs(txtpath, retval)
|
||||
local list = core.get_dir_list(txtpath, true)
|
||||
local current_texture_path = core.settings:get("texture_path")
|
||||
|
||||
for _, item in ipairs(list) do
|
||||
if item ~= "base" then
|
||||
local path = txtpath .. DIR_DELIM .. item .. DIR_DELIM
|
||||
local conf = Settings(path .. "texture_pack.conf")
|
||||
local enabled = path == current_texture_path
|
||||
|
||||
local title = conf:get("title") or item
|
||||
|
||||
-- list_* is only used if non-nil, else the regular versions are used.
|
||||
retval[#retval + 1] = {
|
||||
name = item,
|
||||
title = title,
|
||||
list_name = enabled and fgettext("$1 (Enabled)", item) or nil,
|
||||
list_title = enabled and fgettext("$1 (Enabled)", title) or nil,
|
||||
author = conf:get("author"),
|
||||
release = tonumber(conf:get("release")) or 0,
|
||||
type = "txp",
|
||||
path = path,
|
||||
enabled = enabled,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_mods(path, virtual_path, retval, modpack)
|
||||
local mods = core.get_dir_list(path, true)
|
||||
|
||||
for _, name in ipairs(mods) do
|
||||
if name:sub(1, 1) ~= "." then
|
||||
local mod_path = path .. DIR_DELIM .. name
|
||||
local mod_virtual_path = virtual_path .. "/" .. name
|
||||
local toadd = {
|
||||
dir_name = name,
|
||||
parent_dir = path,
|
||||
}
|
||||
retval[#retval + 1] = toadd
|
||||
|
||||
-- Get config file
|
||||
local mod_conf
|
||||
local modpack_conf = io.open(mod_path .. DIR_DELIM .. "modpack.conf")
|
||||
if modpack_conf then
|
||||
toadd.is_modpack = true
|
||||
modpack_conf:close()
|
||||
|
||||
mod_conf = Settings(mod_path .. 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(mod_path .. 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.title = mod_conf.title
|
||||
toadd.author = mod_conf.author
|
||||
toadd.release = tonumber(mod_conf.release) or 0
|
||||
toadd.path = mod_path
|
||||
toadd.virtual_path = mod_virtual_path
|
||||
toadd.type = "mod"
|
||||
|
||||
-- Check modpack.txt
|
||||
-- Note: modpack.conf is already checked above
|
||||
local modpackfile = io.open(mod_path .. 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(mod_path, mod_virtual_path, retval, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--modmanager implementation
|
||||
pkgmgr = {}
|
||||
|
||||
function pkgmgr.get_texture_packs()
|
||||
local txtpath = core.get_texturepath()
|
||||
local txtpath_system = core.get_texturepath_share()
|
||||
local retval = {}
|
||||
|
||||
load_texture_packs(txtpath, retval)
|
||||
-- on portable versions these two paths coincide. It avoids loading the path twice
|
||||
if txtpath ~= txtpath_system then
|
||||
load_texture_packs(txtpath_system, retval)
|
||||
end
|
||||
|
||||
table.sort(retval, function(a, b)
|
||||
return a.name > b.name
|
||||
end)
|
||||
|
||||
return retval
|
||||
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, use_technical_names, with_error)
|
||||
if not render_list then
|
||||
if not pkgmgr.global_mods then
|
||||
pkgmgr.refresh_globals()
|
||||
end
|
||||
render_list = pkgmgr.global_mods
|
||||
end
|
||||
|
||||
local list = render_list:get_list()
|
||||
local retval = {}
|
||||
for i, v in ipairs(list) do
|
||||
local color = ""
|
||||
local icon = 0
|
||||
local error = with_error and with_error[v.virtual_path]
|
||||
local function update_error(val)
|
||||
if val and (not error or (error.type == "warning" and val.type == "error")) then
|
||||
error = val
|
||||
end
|
||||
end
|
||||
|
||||
if v.is_modpack then
|
||||
local rawlist = render_list:get_raw_list()
|
||||
color = mt_color_dark_green
|
||||
|
||||
for j = 1, #rawlist do
|
||||
if rawlist[j].modpack == list[i].name then
|
||||
if with_error then
|
||||
update_error(with_error[rawlist[j].virtual_path])
|
||||
end
|
||||
|
||||
if rawlist[j].enabled then
|
||||
icon = 1
|
||||
else
|
||||
-- Modpack not entirely enabled so showing as grey
|
||||
color = mt_color_grey
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif v.is_game_content or v.type == "game" then
|
||||
icon = 1
|
||||
color = mt_color_blue
|
||||
|
||||
local rawlist = render_list:get_raw_list()
|
||||
if v.type == "game" and with_error then
|
||||
for j = 1, #rawlist do
|
||||
if rawlist[j].is_game_content then
|
||||
update_error(with_error[rawlist[j].virtual_path])
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif v.enabled or v.type == "txp" then
|
||||
icon = 1
|
||||
color = mt_color_green
|
||||
end
|
||||
|
||||
if error then
|
||||
if error.type == "warning" then
|
||||
color = mt_color_orange
|
||||
icon = 2
|
||||
else
|
||||
color = mt_color_red
|
||||
icon = 3
|
||||
end
|
||||
end
|
||||
|
||||
retval[#retval + 1] = color
|
||||
if v.modpack ~= nil or v.loc == "game" then
|
||||
retval[#retval + 1] = "1"
|
||||
else
|
||||
retval[#retval + 1] = "0"
|
||||
end
|
||||
|
||||
if with_error then
|
||||
retval[#retval + 1] = icon
|
||||
end
|
||||
|
||||
if use_technical_names then
|
||||
retval[#retval + 1] = core.formspec_escape(v.list_name or v.name)
|
||||
else
|
||||
retval[#retval + 1] = core.formspec_escape(v.list_title or v.list_name or v.title or v.name)
|
||||
end
|
||||
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
|
||||
|
||||
local function disable_all_by_name(list, name, except)
|
||||
for i=1, #list do
|
||||
if list[i].name == name and list[i] ~= except then
|
||||
list[i].enabled = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---------- toggles or en/disables a mod or modpack and its dependencies --------
|
||||
local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
|
||||
if not mod.is_modpack then
|
||||
-- Toggle or en/disable the mod
|
||||
if toset == nil then
|
||||
toset = not mod.enabled
|
||||
end
|
||||
if mod.enabled ~= toset then
|
||||
toggled_mods[#toggled_mods+1] = mod.name
|
||||
end
|
||||
if toset then
|
||||
-- Mark this mod for recursive dependency traversal
|
||||
enabled_mods[mod.name] = true
|
||||
|
||||
-- Disable other mods with the same name
|
||||
disable_all_by_name(list, mod.name, mod)
|
||||
end
|
||||
mod.enabled = toset
|
||||
else
|
||||
-- Toggle or en/disable every mod in the modpack,
|
||||
-- interleaved unsupported
|
||||
for i = 1, #list do
|
||||
if list[i].modpack == mod.name then
|
||||
toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, list[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pkgmgr.enable_mod(this, toset)
|
||||
local list = this.data.list:get_list()
|
||||
local mod = list[this.data.selected_mod]
|
||||
|
||||
-- Game mods can't be enabled or disabled
|
||||
if mod.is_game_content then
|
||||
return
|
||||
end
|
||||
|
||||
local toggled_mods = {}
|
||||
local enabled_mods = {}
|
||||
toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
|
||||
|
||||
if next(enabled_mods) == nil then
|
||||
-- Mod(s) were disabled, so no dependencies need to be enabled
|
||||
table.sort(toggled_mods)
|
||||
core.log("info", "Following mods were disabled: " ..
|
||||
table.concat(toggled_mods, ", "))
|
||||
return
|
||||
end
|
||||
|
||||
-- Enable mods' depends after activation
|
||||
|
||||
-- Make a list of mod ids indexed by their names. Among mods with the
|
||||
-- same name, enabled mods take precedence, after which game mods take
|
||||
-- precedence, being last in the mod list.
|
||||
local mod_ids = {}
|
||||
for id, mod2 in pairs(list) do
|
||||
if mod2.type == "mod" and not mod2.is_modpack then
|
||||
local prev_id = mod_ids[mod2.name]
|
||||
if not prev_id or not list[prev_id].enabled then
|
||||
mod_ids[mod2.name] = id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- to_enable is used as a DFS stack with sp as stack pointer
|
||||
local to_enable = {}
|
||||
local sp = 0
|
||||
for name in pairs(enabled_mods) do
|
||||
local depends = pkgmgr.get_dependencies(list[mod_ids[name]].path)
|
||||
for i = 1, #depends do
|
||||
local dependency_name = depends[i]
|
||||
if not enabled_mods[dependency_name] then
|
||||
sp = sp+1
|
||||
to_enable[sp] = dependency_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- If sp is 0, every dependency is already activated
|
||||
while sp > 0 do
|
||||
local name = to_enable[sp]
|
||||
sp = sp-1
|
||||
|
||||
if not enabled_mods[name] then
|
||||
enabled_mods[name] = true
|
||||
local mod_to_enable = list[mod_ids[name]]
|
||||
if not mod_to_enable then
|
||||
core.log("warning", "Mod dependency \"" .. name ..
|
||||
"\" not found!")
|
||||
elseif not mod_to_enable.is_game_content then
|
||||
if not mod_to_enable.enabled then
|
||||
mod_to_enable.enabled = true
|
||||
toggled_mods[#toggled_mods+1] = mod_to_enable.name
|
||||
end
|
||||
-- Push the dependencies of the dependency onto the stack
|
||||
local depends = pkgmgr.get_dependencies(mod_to_enable.path)
|
||||
for i = 1, #depends do
|
||||
if not enabled_mods[depends[i]] then
|
||||
sp = sp+1
|
||||
to_enable[sp] = depends[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Log the list of enabled mods
|
||||
table.sort(toggled_mods)
|
||||
core.log("info", "Following mods were enabled: " ..
|
||||
table.concat(toggled_mods, ", "))
|
||||
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 not targetpath then
|
||||
targetpath = core.get_texturepath() .. DIR_DELIM .. basename
|
||||
end
|
||||
core.delete_dir(targetpath)
|
||||
if not core.copy_dir(from, targetpath, false) 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)
|
||||
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",
|
||||
path)
|
||||
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)
|
||||
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", path)
|
||||
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)
|
||||
else
|
||||
targetpath = core.get_gamepath() .. DIR_DELIM .. basename
|
||||
end
|
||||
else
|
||||
error("basefolder didn't return a recognised type, this shouldn't happen")
|
||||
end
|
||||
|
||||
-- Copy it
|
||||
core.delete_dir(targetpath)
|
||||
if not core.copy_dir(basefolder.path, targetpath, false) 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.preparemodlist(data)
|
||||
local retval = {}
|
||||
|
||||
local global_mods = {}
|
||||
local game_mods = {}
|
||||
|
||||
--read global mods
|
||||
local modpaths = core.get_modpaths()
|
||||
for key, modpath in pairs(modpaths) do
|
||||
get_mods(modpath, key, global_mods)
|
||||
end
|
||||
|
||||
for i=1,#global_mods,1 do
|
||||
global_mods[i].type = "mod"
|
||||
global_mods[i].loc = "global"
|
||||
global_mods[i].enabled = false
|
||||
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.title),
|
||||
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 mod_found = false
|
||||
|
||||
local fallback_found = false
|
||||
local fallback_mod = nil
|
||||
|
||||
for i=1, #retval do
|
||||
if retval[i].name == key and
|
||||
not retval[i].is_modpack then
|
||||
if core.is_yes(value) or retval[i].virtual_path == value then
|
||||
retval[i].enabled = true
|
||||
mod_found = true
|
||||
break
|
||||
elseif fallback_found then
|
||||
-- Only allow fallback if only one mod matches
|
||||
fallback_mod = nil
|
||||
else
|
||||
fallback_found = true
|
||||
fallback_mod = retval[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not mod_found then
|
||||
if fallback_mod and value:find("/") then
|
||||
fallback_mod.enabled = true
|
||||
else
|
||||
core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
|
||||
end
|
||||
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.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, ("games/%s/mods"):format(gamespec.id), 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].title)
|
||||
|
||||
for i=2,#pkgmgr.games,1 do
|
||||
retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].title)
|
||||
end
|
||||
end
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- read initial data
|
||||
--------------------------------------------------------------------------------
|
||||
pkgmgr.update_gamelist()
|
||||
252
builtin/mainmenu/serverlistmgr.lua
Normal file
252
builtin/mainmenu/serverlistmgr.lua
Normal file
@@ -0,0 +1,252 @@
|
||||
--Minetest
|
||||
--Copyright (C) 2020 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.
|
||||
|
||||
serverlistmgr = {}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function order_server_list(list)
|
||||
local res = {}
|
||||
--orders the favorite list after support
|
||||
for i = 1, #list do
|
||||
local fav = list[i]
|
||||
if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
|
||||
res[#res + 1] = fav
|
||||
end
|
||||
end
|
||||
for i = 1, #list do
|
||||
local fav = list[i]
|
||||
if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
|
||||
res[#res + 1] = fav
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local public_downloading = false
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function serverlistmgr.sync()
|
||||
if not serverlistmgr.servers then
|
||||
serverlistmgr.servers = {{
|
||||
name = fgettext("Loading..."),
|
||||
description = fgettext_ne("Try reenabling public serverlist and check your internet connection.")
|
||||
}}
|
||||
end
|
||||
|
||||
local serverlist_url = core.settings:get("serverlist_url") or ""
|
||||
if not core.get_http_api or serverlist_url == "" then
|
||||
serverlistmgr.servers = {{
|
||||
name = fgettext("Public server list is disabled"),
|
||||
description = ""
|
||||
}}
|
||||
return
|
||||
end
|
||||
|
||||
if public_downloading then
|
||||
return
|
||||
end
|
||||
public_downloading = true
|
||||
|
||||
core.handle_async(
|
||||
function(param)
|
||||
local http = core.get_http_api()
|
||||
local url = ("%s/list?proto_version_min=%d&proto_version_max=%d"):format(
|
||||
core.settings:get("serverlist_url"),
|
||||
core.get_min_supp_proto(),
|
||||
core.get_max_supp_proto())
|
||||
|
||||
local response = http.fetch_sync({ url = url })
|
||||
if not response.succeeded then
|
||||
return {}
|
||||
end
|
||||
|
||||
local retval = core.parse_json(response.data)
|
||||
return retval and retval.list or {}
|
||||
end,
|
||||
nil,
|
||||
function(result)
|
||||
public_downloading = nil
|
||||
local favs = order_server_list(result)
|
||||
if favs[1] then
|
||||
serverlistmgr.servers = favs
|
||||
end
|
||||
core.event_handler("Refresh")
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function get_favorites_path(folder)
|
||||
local base = core.get_user_path() .. DIR_DELIM .. "client" .. DIR_DELIM .. "serverlist" .. DIR_DELIM
|
||||
if folder then
|
||||
return base
|
||||
end
|
||||
return base .. core.settings:get("serverlist_file")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function save_favorites(favorites)
|
||||
local filename = core.settings:get("serverlist_file")
|
||||
-- If setting specifies legacy format change the filename to the new one
|
||||
if filename:sub(#filename - 3):lower() == ".txt" then
|
||||
core.settings:set("serverlist_file", filename:sub(1, #filename - 4) .. ".json")
|
||||
end
|
||||
|
||||
assert(core.create_dir(get_favorites_path(true)))
|
||||
core.safe_file_write(get_favorites_path(), core.write_json(favorites))
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function serverlistmgr.read_legacy_favorites(path)
|
||||
local file = io.open(path, "r")
|
||||
if not file then
|
||||
return nil
|
||||
end
|
||||
|
||||
local lines = {}
|
||||
for line in file:lines() do
|
||||
lines[#lines + 1] = line
|
||||
end
|
||||
file:close()
|
||||
|
||||
local favorites = {}
|
||||
|
||||
local i = 1
|
||||
while i < #lines do
|
||||
local function pop()
|
||||
local line = lines[i]
|
||||
i = i + 1
|
||||
return line and line:trim()
|
||||
end
|
||||
|
||||
if pop():lower() == "[server]" then
|
||||
local name = pop()
|
||||
local address = pop()
|
||||
local port = tonumber(pop())
|
||||
local description = pop()
|
||||
|
||||
if name == "" then
|
||||
name = nil
|
||||
end
|
||||
|
||||
if description == "" then
|
||||
description = nil
|
||||
end
|
||||
|
||||
if not address or #address < 3 then
|
||||
core.log("warning", "Malformed favorites file, missing address at line " .. i)
|
||||
elseif not port or port < 1 or port > 65535 then
|
||||
core.log("warning", "Malformed favorites file, missing port at line " .. i)
|
||||
elseif (name and name:upper() == "[SERVER]") or
|
||||
(address and address:upper() == "[SERVER]") or
|
||||
(description and description:upper() == "[SERVER]") then
|
||||
core.log("warning", "Potentially malformed favorites file, overran at line " .. i)
|
||||
else
|
||||
favorites[#favorites + 1] = {
|
||||
name = name,
|
||||
address = address,
|
||||
port = port,
|
||||
description = description
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return favorites
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function read_favorites()
|
||||
local path = get_favorites_path()
|
||||
|
||||
-- If new format configured fall back to reading the legacy file
|
||||
if path:sub(#path - 4):lower() == ".json" then
|
||||
local file = io.open(path, "r")
|
||||
if file then
|
||||
local json = file:read("*all")
|
||||
file:close()
|
||||
return core.parse_json(json)
|
||||
end
|
||||
|
||||
path = path:sub(1, #path - 5) .. ".txt"
|
||||
end
|
||||
|
||||
local favs = serverlistmgr.read_legacy_favorites(path)
|
||||
if favs then
|
||||
save_favorites(favs)
|
||||
os.remove(path)
|
||||
end
|
||||
return favs
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function delete_favorite(favorites, del_favorite)
|
||||
for i=1, #favorites do
|
||||
local fav = favorites[i]
|
||||
|
||||
if fav.address == del_favorite.address and fav.port == del_favorite.port then
|
||||
table.remove(favorites, i)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function serverlistmgr.get_favorites()
|
||||
if serverlistmgr.favorites then
|
||||
return serverlistmgr.favorites
|
||||
end
|
||||
|
||||
serverlistmgr.favorites = {}
|
||||
|
||||
-- Add favorites, removing duplicates
|
||||
local seen = {}
|
||||
for _, fav in ipairs(read_favorites() or {}) do
|
||||
local key = ("%s:%d"):format(fav.address:lower(), fav.port)
|
||||
if not seen[key] then
|
||||
seen[key] = true
|
||||
serverlistmgr.favorites[#serverlistmgr.favorites + 1] = fav
|
||||
end
|
||||
end
|
||||
|
||||
return serverlistmgr.favorites
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function serverlistmgr.add_favorite(new_favorite)
|
||||
assert(type(new_favorite.port) == "number")
|
||||
|
||||
-- Whitelist favorite keys
|
||||
new_favorite = {
|
||||
name = new_favorite.name,
|
||||
address = new_favorite.address,
|
||||
port = new_favorite.port,
|
||||
description = new_favorite.description,
|
||||
}
|
||||
|
||||
local favorites = serverlistmgr.get_favorites()
|
||||
delete_favorite(favorites, new_favorite)
|
||||
table.insert(favorites, 1, new_favorite)
|
||||
save_favorites(favorites)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function serverlistmgr.delete_favorite(del_favorite)
|
||||
local favorites = serverlistmgr.get_favorites()
|
||||
delete_favorite(favorites, del_favorite)
|
||||
save_favorites(favorites)
|
||||
end
|
||||
195
builtin/mainmenu/tab_about.lua
Normal file
195
builtin/mainmenu/tab_about.lua
Normal file
@@ -0,0 +1,195 @@
|
||||
--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.
|
||||
|
||||
-- https://github.com/orgs/minetest/teams/engine/members
|
||||
|
||||
local core_developers = {
|
||||
"Perttu Ahola (celeron55) <celeron55@gmail.com> [Project founder]",
|
||||
"sfan5 <sfan5@live.de>",
|
||||
"ShadowNinja <shadowninja@minetest.net>",
|
||||
"Nathanaëlle Courant (Nore/Ekdohibs) <nore@mesecons.net>",
|
||||
"Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>",
|
||||
"Andrew Ward (rubenwardy) <rw@rubenwardy.com>",
|
||||
"Krock/SmallJoker <mk939@ymail.com>",
|
||||
"Lars Hofhansl <larsh@apache.org>",
|
||||
"v-rob <robinsonvincent89@gmail.com>",
|
||||
"hecks",
|
||||
"Hugues Ross <hugues.ross@gmail.com>",
|
||||
"Dmitry Kostenko (x2048) <codeforsmile@gmail.com>",
|
||||
}
|
||||
|
||||
local core_team = {
|
||||
"Zughy [Issue triager]",
|
||||
}
|
||||
|
||||
-- For updating active/previous contributors, see the script in ./util/gather_git_credits.py
|
||||
|
||||
local active_contributors = {
|
||||
"Wuzzy [Features, translations, devtest]",
|
||||
"Lars Müller [Lua optimizations and fixes]",
|
||||
"Jude Melton-Houghton [Optimizations, bugfixes]",
|
||||
"paradust7 [Performance, fixes, Irrlicht refactoring]",
|
||||
"Desour [Fixes]",
|
||||
"ROllerozxa [Main menu]",
|
||||
"savilli [Bugfixes]",
|
||||
"Lexi Hale [Particlespawner animation]",
|
||||
"Liso [Shadow Mapping]",
|
||||
"JosiahWI [Fixes, build system]",
|
||||
"numzero [Graphics and rendering]",
|
||||
"HybridDog [Fixes]",
|
||||
"NeroBurner [Joystick]",
|
||||
"pecksin [Clickable web links]",
|
||||
"Daroc Alden [Fixes]",
|
||||
"Jean-Patrick Guerrero (kilbith) [Fixes]",
|
||||
}
|
||||
|
||||
local previous_core_developers = {
|
||||
"BlockMen",
|
||||
"Maciej Kasatkin (RealBadAngel) [RIP]",
|
||||
"Lisa Milne (darkrose) <lisa@ltmnet.com>",
|
||||
"proller",
|
||||
"Ilya Zhuravlev (xyz) <xyz@minetest.net>",
|
||||
"PilzAdam <pilzadam@minetest.net>",
|
||||
"est31 <MTest31@outlook.com>",
|
||||
"kahrl <kahrl@gmx.net>",
|
||||
"Ryan Kwolek (kwolekr) <kwolekr@minetest.net>",
|
||||
"sapier",
|
||||
"Zeno",
|
||||
"Auke Kok (sofar) <sofar@foo-projects.org>",
|
||||
"Aaron Suen <warr1024@gmail.com>",
|
||||
"paramat",
|
||||
"Pierre-Yves Rollo <dev@pyrollo.com>",
|
||||
}
|
||||
|
||||
local previous_contributors = {
|
||||
"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest logo]",
|
||||
"red-001 <red-001@outlook.ie>",
|
||||
"Giuseppe Bilotta",
|
||||
"ClobberXD",
|
||||
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
|
||||
"MirceaKitsune <mirceakitsune@gmail.com>",
|
||||
"MoNTE48",
|
||||
"Constantin Wenger (SpeedProg)",
|
||||
"Ciaran Gultnieks (CiaranG)",
|
||||
"Paul Ouellette (pauloue)",
|
||||
"stujones11",
|
||||
"srifqi",
|
||||
"Rogier <rogier777@gmail.com>",
|
||||
"Gregory Currie (gregorycu)",
|
||||
"JacobF",
|
||||
"Jeija <jeija@mesecons.net>",
|
||||
}
|
||||
|
||||
local function prepare_credits(dest, source)
|
||||
for _, s in ipairs(source) do
|
||||
-- if there's text inside brackets make it gray-ish
|
||||
s = s:gsub("%[.-%]", core.colorize("#aaa", "%1"))
|
||||
dest[#dest+1] = s
|
||||
end
|
||||
end
|
||||
|
||||
local function build_hacky_list(items, spacing)
|
||||
spacing = spacing or 0.5
|
||||
local y = spacing / 2
|
||||
local ret = {}
|
||||
for _, item in ipairs(items) do
|
||||
if item ~= "" then
|
||||
ret[#ret+1] = ("label[0,%f;%s]"):format(y, core.formspec_escape(item))
|
||||
end
|
||||
y = y + spacing
|
||||
end
|
||||
return table.concat(ret, ""), y
|
||||
end
|
||||
|
||||
return {
|
||||
name = "about",
|
||||
caption = fgettext("About"),
|
||||
cbf_formspec = function(tabview, name, tabdata)
|
||||
local logofile = defaulttexturedir .. "logo.png"
|
||||
local version = core.get_version()
|
||||
|
||||
local credit_list = {}
|
||||
table.insert_all(credit_list, {
|
||||
core.colorize("#ff0", fgettext("Core Developers"))
|
||||
})
|
||||
prepare_credits(credit_list, core_developers)
|
||||
table.insert_all(credit_list, {
|
||||
"",
|
||||
core.colorize("#ff0", fgettext("Core Team"))
|
||||
})
|
||||
prepare_credits(credit_list, core_team)
|
||||
table.insert_all(credit_list, {
|
||||
"",
|
||||
core.colorize("#ff0", fgettext("Active Contributors"))
|
||||
})
|
||||
prepare_credits(credit_list, active_contributors)
|
||||
table.insert_all(credit_list, {
|
||||
"",
|
||||
core.colorize("#ff0", fgettext("Previous Core Developers"))
|
||||
})
|
||||
prepare_credits(credit_list, previous_core_developers)
|
||||
table.insert_all(credit_list, {
|
||||
"",
|
||||
core.colorize("#ff0", fgettext("Previous Contributors"))
|
||||
})
|
||||
prepare_credits(credit_list, previous_contributors)
|
||||
local credit_fs, scroll_height = build_hacky_list(credit_list)
|
||||
-- account for the visible portion
|
||||
scroll_height = math.max(0, scroll_height - 6.9)
|
||||
|
||||
local fs = "image[1.5,0.6;2.5,2.5;" .. core.formspec_escape(logofile) .. "]" ..
|
||||
"style[label_button;border=false]" ..
|
||||
"button[0.1,3.4;5.3,0.5;label_button;" ..
|
||||
core.formspec_escape(version.project .. " " .. version.string) .. "]" ..
|
||||
"button[1.5,4.1;2.5,0.8;homepage;minetest.net]" ..
|
||||
"scroll_container[5.5,0.1;9.5,6.9;scroll_credits;vertical;" ..
|
||||
tostring(scroll_height / 1000) .. "]" .. credit_fs ..
|
||||
"scroll_container_end[]"..
|
||||
"scrollbar[15,0.1;0.4,6.9;vertical;scroll_credits;0]"
|
||||
|
||||
-- Render information
|
||||
fs = fs .. "style[label_button2;border=false]" ..
|
||||
"button[0.1,6;5.3,1;label_button2;" ..
|
||||
fgettext("Active renderer:") .. "\n" ..
|
||||
core.formspec_escape(core.get_screen_info().render_info) .. "]"
|
||||
|
||||
if PLATFORM == "Android" then
|
||||
fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
|
||||
else
|
||||
fs = fs .. "tooltip[userdata;" ..
|
||||
fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" ..
|
||||
"and texture packs in a file manager / explorer.") .. "]"
|
||||
fs = fs .. "button[0.5,5.1;4.5,0.8;userdata;" .. fgettext("Open User Data Directory") .. "]"
|
||||
end
|
||||
|
||||
return fs, "size[15.5,7.1,false]real_coordinates[true]"
|
||||
end,
|
||||
cbf_button_handler = function(this, fields, name, tabdata)
|
||||
if fields.homepage then
|
||||
core.open_url("https://www.minetest.net")
|
||||
end
|
||||
|
||||
if fields.share_debug then
|
||||
local path = core.get_user_path() .. DIR_DELIM .. "debug.txt"
|
||||
core.share_file(path)
|
||||
end
|
||||
|
||||
if fields.userdata then
|
||||
core.open_dir(core.get_user_path())
|
||||
end
|
||||
end,
|
||||
}
|
||||
237
builtin/mainmenu/tab_content.lua
Normal file
237
builtin/mainmenu/tab_content.lua
Normal file
@@ -0,0 +1,237 @@
|
||||
--Minetest
|
||||
--Copyright (C) 2014 sapier
|
||||
--Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
--
|
||||
--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 use_technical_names = core.settings:get_bool("show_technical_names")
|
||||
|
||||
|
||||
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, use_technical_names) ..
|
||||
";" .. 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
|
||||
|
||||
local title_and_name
|
||||
if selected_pkg.type == "game" then
|
||||
title_and_name = selected_pkg.name
|
||||
else
|
||||
title_and_name = (selected_pkg.title or selected_pkg.name) .. "\n" ..
|
||||
core.colorize("#BFBFBF", selected_pkg.name)
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"image[5.5,0;3,2;" .. core.formspec_escape(modscreenshot) .. "]" ..
|
||||
"label[8.25,0.6;" .. core.formspec_escape(title_and_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_doubleclick(pkg)
|
||||
if pkg.type == "txp" then
|
||||
if core.settings:get("texture_path") == pkg.path then
|
||||
core.settings:set("texture_path", "")
|
||||
else
|
||||
core.settings:set("texture_path", pkg.path)
|
||||
end
|
||||
packages = nil
|
||||
|
||||
mm_game_theme.init()
|
||||
mm_game_theme.reset()
|
||||
end
|
||||
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
|
||||
if event.type == "DCL" then
|
||||
handle_doubleclick(packages:get_list()[tabdata.selected_pkg])
|
||||
end
|
||||
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 or fields.btn_mod_mgr_disable_txp then
|
||||
local txp_path = ""
|
||||
if fields.btn_mod_mgr_use_txp then
|
||||
txp_path = packages:get_list()[tabdata.selected_pkg].path
|
||||
end
|
||||
|
||||
core.settings:set("texture_path", txp_path)
|
||||
packages = nil
|
||||
|
||||
mm_game_theme.init()
|
||||
mm_game_theme.reset()
|
||||
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
|
||||
}
|
||||
393
builtin/mainmenu/tab_local.lua
Normal file
393
builtin/mainmenu/tab_local.lua
Normal file
@@ -0,0 +1,393 @@
|
||||
--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 current_game, singleplayer_refresh_gamebar
|
||||
local valid_disabled_settings = {
|
||||
["enable_damage"]=true,
|
||||
["creative_mode"]=true,
|
||||
["enable_server"]=true,
|
||||
}
|
||||
|
||||
-- Currently chosen game in gamebar for theming and filtering
|
||||
function current_game()
|
||||
local last_game_id = core.settings:get("menu_last_game")
|
||||
local game = pkgmgr.find_by_gameid(last_game_id)
|
||||
|
||||
return game
|
||||
end
|
||||
|
||||
-- Apply menu changes from given game
|
||||
function apply_game(game)
|
||||
core.set_topleft_text(game.name)
|
||||
core.settings:set("menu_last_game", game.id)
|
||||
menudata.worldlist:set_filtercriteria(game.id)
|
||||
|
||||
mm_game_theme.update("singleplayer", game) -- this refreshes the formspec
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
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)
|
||||
if fields.game_open_cdb then
|
||||
local maintab = ui.find_by_name("maintab")
|
||||
local dlg = create_store_dlg("game")
|
||||
dlg:set_parent(maintab)
|
||||
maintab:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
for _, game in ipairs(pkgmgr.games) do
|
||||
if fields["game_btnbar_" .. game.id] then
|
||||
apply_game(game)
|
||||
return true
|
||||
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 _, game in ipairs(pkgmgr.games) do
|
||||
local btn_name = "game_btnbar_" .. game.id
|
||||
|
||||
local image = nil
|
||||
local text = nil
|
||||
local tooltip = core.formspec_escape(game.title)
|
||||
|
||||
if (game.menuicon_path or "") ~= "" then
|
||||
image = core.formspec_escape(game.menuicon_path)
|
||||
else
|
||||
local part1 = game.id:sub(1,5)
|
||||
local part2 = game.id:sub(6,10)
|
||||
local part3 = game.id:sub(11)
|
||||
|
||||
text = part1 .. "\n" .. part2
|
||||
if part3 ~= "" then
|
||||
text = text .. "\n" .. part3
|
||||
end
|
||||
end
|
||||
btnbar:add_button(btn_name, text, image, tooltip)
|
||||
end
|
||||
|
||||
local plus_image = core.formspec_escape(defaulttexturedir .. "plus.png")
|
||||
btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
|
||||
end
|
||||
|
||||
local function get_disabled_settings(game)
|
||||
if not game then
|
||||
return {}
|
||||
end
|
||||
|
||||
local gameconfig = Settings(game.path .. "/game.conf")
|
||||
local disabled_settings = {}
|
||||
if gameconfig then
|
||||
local disabled_settings_str = (gameconfig:get("disabled_settings") or ""):split()
|
||||
for _, value in pairs(disabled_settings_str) do
|
||||
local state = false
|
||||
value = value:trim()
|
||||
if string.sub(value, 1, 1) == "!" then
|
||||
state = true
|
||||
value = string.sub(value, 2)
|
||||
end
|
||||
if valid_disabled_settings[value] then
|
||||
disabled_settings[value] = state
|
||||
else
|
||||
core.log("error", "Invalid disabled setting in game.conf: "..tostring(value))
|
||||
end
|
||||
end
|
||||
end
|
||||
return disabled_settings
|
||||
end
|
||||
|
||||
local function get_formspec(tabview, name, tabdata)
|
||||
local retval = ""
|
||||
|
||||
local index = filterlist.get_current_index(menudata.worldlist,
|
||||
tonumber(core.settings:get("mainmenu_last_selected_world")))
|
||||
local list = menudata.worldlist:get_list()
|
||||
local world = list and index and list[index]
|
||||
local game
|
||||
if world then
|
||||
game = pkgmgr.find_by_gameid(world.gameid)
|
||||
else
|
||||
game = current_game()
|
||||
end
|
||||
local disabled_settings = get_disabled_settings(game)
|
||||
|
||||
local creative, damage, host = "", "", ""
|
||||
|
||||
-- Y offsets for game settings checkboxes
|
||||
local y = -0.2
|
||||
local yo = 0.45
|
||||
|
||||
if disabled_settings["creative_mode"] == nil then
|
||||
creative = "checkbox[0,"..y..";cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
|
||||
dump(core.settings:get_bool("creative_mode")) .. "]"
|
||||
y = y + yo
|
||||
end
|
||||
if disabled_settings["enable_damage"] == nil then
|
||||
damage = "checkbox[0,"..y..";cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
|
||||
dump(core.settings:get_bool("enable_damage")) .. "]"
|
||||
y = y + yo
|
||||
end
|
||||
if disabled_settings["enable_server"] == nil then
|
||||
host = "checkbox[0,"..y..";cb_server;".. fgettext("Host Server") ..";" ..
|
||||
dump(core.settings:get_bool("enable_server")) .. "]"
|
||||
y = y + yo
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"button[3.9,3.8;2.8,1;world_delete;".. fgettext("Delete") .. "]" ..
|
||||
"button[6.55,3.8;2.8,1;world_configure;".. fgettext("Select Mods") .. "]" ..
|
||||
"button[9.2,3.8;2.8,1;world_create;".. fgettext("New") .. "]" ..
|
||||
"label[3.9,-0.05;".. fgettext("Select World:") .. "]"..
|
||||
creative ..
|
||||
damage ..
|
||||
host ..
|
||||
"textlist[3.9,0.4;7.9,3.45;sp_worlds;" ..
|
||||
menu_render_worldlist() ..
|
||||
";" .. index .. "]"
|
||||
|
||||
if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then
|
||||
retval = retval ..
|
||||
"button[7.9,4.75;4.1,1;play;".. fgettext("Host Game") .. "]" ..
|
||||
"checkbox[0,"..y..";cb_server_announce;" .. fgettext("Announce Server") .. ";" ..
|
||||
dump(core.settings:get_bool("server_announce")) .. "]" ..
|
||||
"field[0.3,2.85;3.8,0.5;te_playername;" .. fgettext("Name") .. ";" ..
|
||||
core.formspec_escape(core.settings:get("name")) .. "]" ..
|
||||
"pwdfield[0.3,4.05;3.8,0.5;te_passwd;" .. fgettext("Password") .. "]"
|
||||
|
||||
local bind_addr = core.settings:get("bind_address")
|
||||
if bind_addr ~= nil and bind_addr ~= "" then
|
||||
retval = retval ..
|
||||
"field[0.3,5.25;2.5,0.5;te_serveraddr;" .. fgettext("Bind Address") .. ";" ..
|
||||
core.formspec_escape(core.settings:get("bind_address")) .. "]" ..
|
||||
"field[2.85,5.25;1.25,0.5;te_serverport;" .. fgettext("Port") .. ";" ..
|
||||
core.formspec_escape(core.settings:get("port")) .. "]"
|
||||
else
|
||||
retval = retval ..
|
||||
"field[0.3,5.25;3.8,0.5;te_serverport;" .. fgettext("Server Port") .. ";" ..
|
||||
core.formspec_escape(core.settings:get("port")) .. "]"
|
||||
end
|
||||
else
|
||||
retval = retval ..
|
||||
"button[7.9,4.75;4.1,1;play;" .. fgettext("Play Game") .. "]"
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
local function main_button_handler(this, fields, name, tabdata)
|
||||
|
||||
assert(name == "local")
|
||||
|
||||
local world_doubleclick = false
|
||||
|
||||
if fields["sp_worlds"] ~= nil then
|
||||
local event = core.explode_textlist_event(fields["sp_worlds"])
|
||||
local selected = core.get_textlist_index("sp_worlds")
|
||||
|
||||
menu_worldmt_legacy(selected)
|
||||
|
||||
if event.type == "DCL" then
|
||||
world_doubleclick = true
|
||||
end
|
||||
|
||||
if event.type == "CHG" and selected ~= nil then
|
||||
core.settings:set("mainmenu_last_selected_world",
|
||||
menudata.worldlist:get_raw_index(selected))
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if menu_handle_key_up_down(fields,"sp_worlds","mainmenu_last_selected_world") then
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["cb_creative_mode"] then
|
||||
core.settings:set("creative_mode", fields["cb_creative_mode"])
|
||||
local selected = core.get_textlist_index("sp_worlds")
|
||||
menu_worldmt(selected, "creative_mode", fields["cb_creative_mode"])
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["cb_enable_damage"] then
|
||||
core.settings:set("enable_damage", fields["cb_enable_damage"])
|
||||
local selected = core.get_textlist_index("sp_worlds")
|
||||
menu_worldmt(selected, "enable_damage", fields["cb_enable_damage"])
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["cb_server"] then
|
||||
core.settings:set("enable_server", fields["cb_server"])
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["cb_server_announce"] then
|
||||
core.settings:set("server_announce", fields["cb_server_announce"])
|
||||
local selected = core.get_textlist_index("srv_worlds")
|
||||
menu_worldmt(selected, "server_announce", fields["cb_server_announce"])
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
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)
|
||||
|
||||
if selected == nil or gamedata.selected_world == 0 then
|
||||
gamedata.errormessage =
|
||||
fgettext("No world created or selected!")
|
||||
return true
|
||||
end
|
||||
|
||||
-- Update last game
|
||||
local world = menudata.worldlist:get_raw_element(gamedata.selected_world)
|
||||
local game_obj
|
||||
if world then
|
||||
game_obj = pkgmgr.find_by_gameid(world.gameid)
|
||||
core.settings:set("menu_last_game", game_obj.id)
|
||||
end
|
||||
|
||||
local disabled_settings = get_disabled_settings(game_obj)
|
||||
for k, _ in pairs(valid_disabled_settings) do
|
||||
local v = disabled_settings[k]
|
||||
if v ~= nil then
|
||||
if k == "enable_server" and v == true then
|
||||
error("Setting 'enable_server' cannot be force-enabled! The game.conf needs to be fixed.")
|
||||
end
|
||||
core.settings:set_bool(k, disabled_settings[k])
|
||||
end
|
||||
end
|
||||
|
||||
if core.settings:get_bool("enable_server") then
|
||||
gamedata.playername = fields["te_playername"]
|
||||
gamedata.password = fields["te_passwd"]
|
||||
gamedata.port = fields["te_serverport"]
|
||||
gamedata.address = ""
|
||||
|
||||
core.settings:set("port",gamedata.port)
|
||||
if fields["te_serveraddr"] ~= nil then
|
||||
core.settings:set("bind_address",fields["te_serveraddr"])
|
||||
end
|
||||
else
|
||||
gamedata.singleplayer = true
|
||||
end
|
||||
|
||||
core.start()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["world_create"] ~= nil then
|
||||
local create_world_dlg = create_create_world_dlg()
|
||||
create_world_dlg:set_parent(this)
|
||||
this:hide()
|
||||
create_world_dlg:show()
|
||||
mm_game_theme.update("singleplayer", current_game())
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["world_delete"] ~= nil then
|
||||
local selected = core.get_textlist_index("sp_worlds")
|
||||
if selected ~= nil and
|
||||
selected <= menudata.worldlist:size() then
|
||||
local world = menudata.worldlist:get_list()[selected]
|
||||
if world ~= nil and
|
||||
world.name ~= nil and
|
||||
world.name ~= "" then
|
||||
local index = menudata.worldlist:get_raw_index(selected)
|
||||
local delete_world_dlg = create_delete_world_dlg(world.name,index)
|
||||
delete_world_dlg:set_parent(this)
|
||||
this:hide()
|
||||
delete_world_dlg:show()
|
||||
mm_game_theme.update("singleplayer",current_game())
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["world_configure"] ~= nil then
|
||||
local selected = core.get_textlist_index("sp_worlds")
|
||||
if selected ~= nil then
|
||||
local configdialog =
|
||||
create_configure_world_dlg(
|
||||
menudata.worldlist:get_raw_index(selected))
|
||||
|
||||
if (configdialog ~= nil) then
|
||||
configdialog:set_parent(this)
|
||||
this:hide()
|
||||
configdialog:show()
|
||||
mm_game_theme.update("singleplayer",current_game())
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function on_change(type, old_tab, new_tab)
|
||||
if (type == "ENTER") then
|
||||
local game = current_game()
|
||||
if game then
|
||||
apply_game(game)
|
||||
end
|
||||
|
||||
singleplayer_refresh_gamebar()
|
||||
ui.find_by_name("game_button_bar"):show()
|
||||
else
|
||||
menudata.worldlist:set_filtercriteria(nil)
|
||||
local gamebar = ui.find_by_name("game_button_bar")
|
||||
if gamebar then
|
||||
gamebar:hide()
|
||||
end
|
||||
core.set_topleft_text("")
|
||||
mm_game_theme.update(new_tab,nil)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
return {
|
||||
name = "local",
|
||||
caption = fgettext("Start Game"),
|
||||
cbf_formspec = get_formspec,
|
||||
cbf_button_handler = main_button_handler,
|
||||
on_change = on_change
|
||||
}
|
||||
427
builtin/mainmenu/tab_online.lua
Normal file
427
builtin/mainmenu/tab_online.lua
Normal file
@@ -0,0 +1,427 @@
|
||||
--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 get_sorted_servers()
|
||||
local servers = {
|
||||
fav = {},
|
||||
public = {},
|
||||
incompatible = {}
|
||||
}
|
||||
|
||||
local favs = serverlistmgr.get_favorites()
|
||||
local taken_favs = {}
|
||||
local result = menudata.search_result or serverlistmgr.servers
|
||||
for _, server in ipairs(result) do
|
||||
server.is_favorite = false
|
||||
for index, fav in ipairs(favs) do
|
||||
if server.address == fav.address and server.port == fav.port then
|
||||
taken_favs[index] = true
|
||||
server.is_favorite = true
|
||||
break
|
||||
end
|
||||
end
|
||||
server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max)
|
||||
if server.is_favorite then
|
||||
table.insert(servers.fav, server)
|
||||
elseif server.is_compatible then
|
||||
table.insert(servers.public, server)
|
||||
else
|
||||
table.insert(servers.incompatible, server)
|
||||
end
|
||||
end
|
||||
|
||||
if not menudata.search_result then
|
||||
for index, fav in ipairs(favs) do
|
||||
if not taken_favs[index] then
|
||||
table.insert(servers.fav, fav)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return servers
|
||||
end
|
||||
|
||||
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()
|
||||
|
||||
if not tabdata.search_for then
|
||||
tabdata.search_for = ""
|
||||
end
|
||||
|
||||
local retval =
|
||||
-- Search
|
||||
"field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
|
||||
"container[7.25,0.25]" ..
|
||||
"image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
|
||||
"image_button[0.75,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" ..
|
||||
"image_button[1.5,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "refresh.png") .. ";btn_mp_refresh;]" ..
|
||||
"tooltip[btn_mp_clear;" .. fgettext("Clear") .. "]" ..
|
||||
"tooltip[btn_mp_search;" .. fgettext("Search") .. "]" ..
|
||||
"tooltip[btn_mp_refresh;" .. fgettext("Refresh") .. "]" ..
|
||||
"container_end[]" ..
|
||||
|
||||
"container[9.75,0]" ..
|
||||
"box[0,0;5.75,7;#666666]" ..
|
||||
|
||||
-- Address / Port
|
||||
"label[0.25,0.35;" .. fgettext("Address") .. "]" ..
|
||||
"label[4.25,0.35;" .. fgettext("Port") .. "]" ..
|
||||
"field[0.25,0.5;4,0.75;te_address;;" ..
|
||||
core.formspec_escape(core.settings:get("address")) .. "]" ..
|
||||
"field[4.25,0.5;1.25,0.75;te_port;;" ..
|
||||
core.formspec_escape(core.settings:get("remote_port")) .. "]" ..
|
||||
|
||||
-- Description Background
|
||||
"label[0.25,1.6;" .. fgettext("Server Description") .. "]" ..
|
||||
"box[0.25,1.85;5.25,2.7;#999999]"..
|
||||
|
||||
-- Name / Password
|
||||
"container[0,4.8]" ..
|
||||
"label[0.25,0;" .. fgettext("Name") .. "]" ..
|
||||
"label[2.875,0;" .. fgettext("Password") .. "]" ..
|
||||
"field[0.25,0.2;2.625,0.75;te_name;;" .. core.formspec_escape(core.settings:get("name")) .. "]" ..
|
||||
"pwdfield[2.875,0.2;2.625,0.75;te_pwd;]" ..
|
||||
"container_end[]" ..
|
||||
|
||||
-- Connect
|
||||
"button[3,6;2.5,0.75;btn_mp_login;" .. fgettext("Login") .. "]"
|
||||
|
||||
if core.settings:get_bool("enable_split_login_register") then
|
||||
retval = retval .. "button[0.25,6;2.5,0.75;btn_mp_register;" .. fgettext("Register") .. "]"
|
||||
end
|
||||
|
||||
if tabdata.selected then
|
||||
if gamedata.fav then
|
||||
retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
|
||||
retval = retval .. "style[btn_delete_favorite;padding=6]"
|
||||
retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
|
||||
"server_favorite_delete.png") .. ";btn_delete_favorite;]"
|
||||
end
|
||||
if gamedata.serverdescription then
|
||||
retval = retval .. "textarea[0.25,1.85;5.2,2.75;;;" ..
|
||||
core.formspec_escape(gamedata.serverdescription) .. "]"
|
||||
end
|
||||
end
|
||||
|
||||
retval = retval .. "container_end[]"
|
||||
|
||||
-- Table
|
||||
retval = retval .. "tablecolumns[" ..
|
||||
"image,tooltip=" .. fgettext("Ping") .. "," ..
|
||||
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
|
||||
"1=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," ..
|
||||
"2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," ..
|
||||
"3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," ..
|
||||
"4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png") .. "," ..
|
||||
"5=" .. core.formspec_escape(defaulttexturedir .. "server_favorite.png") .. "," ..
|
||||
"6=" .. core.formspec_escape(defaulttexturedir .. "server_public.png") .. "," ..
|
||||
"7=" .. core.formspec_escape(defaulttexturedir .. "server_incompatible.png") .. ";" ..
|
||||
"color,span=1;" ..
|
||||
"text,align=inline;"..
|
||||
"color,span=1;" ..
|
||||
"text,align=inline,width=4.25;" ..
|
||||
"image,tooltip=" .. fgettext("Creative mode") .. "," ..
|
||||
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
|
||||
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_creative.png") .. "," ..
|
||||
"align=inline,padding=0.25,width=1.5;" ..
|
||||
--~ PvP = Player versus Player
|
||||
"image,tooltip=" .. fgettext("Damage / PvP") .. "," ..
|
||||
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
|
||||
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_damage.png") .. "," ..
|
||||
"2=" .. core.formspec_escape(defaulttexturedir .. "server_flags_pvp.png") .. "," ..
|
||||
"align=inline,padding=0.25,width=1.5;" ..
|
||||
"color,align=inline,span=1;" ..
|
||||
"text,align=inline,padding=1]" ..
|
||||
"table[0.25,1;9.25,5.75;servers;"
|
||||
|
||||
local servers = get_sorted_servers()
|
||||
|
||||
local dividers = {
|
||||
fav = "5,#ffff00," .. fgettext("Favorites") .. ",,,0,0,,",
|
||||
public = "6,#4bdd42," .. fgettext("Public Servers") .. ",,,0,0,,",
|
||||
incompatible = "7,"..mt_color_grey.."," .. fgettext("Incompatible Servers") .. ",,,0,0,,"
|
||||
}
|
||||
local order = {"fav", "public", "incompatible"}
|
||||
|
||||
tabdata.lookup = {} -- maps row number to server
|
||||
local rows = {}
|
||||
for _, section in ipairs(order) do
|
||||
local section_servers = servers[section]
|
||||
if next(section_servers) ~= nil then
|
||||
rows[#rows + 1] = dividers[section]
|
||||
for _, server in ipairs(section_servers) do
|
||||
tabdata.lookup[#rows + 1] = server
|
||||
rows[#rows + 1] = render_serverlist_row(server)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
retval = retval .. table.concat(rows, ",")
|
||||
|
||||
if tabdata.selected then
|
||||
retval = retval .. ";" .. tabdata.selected .. "]"
|
||||
else
|
||||
retval = retval .. ";0]"
|
||||
end
|
||||
|
||||
return retval, "size[15.5,7,false]real_coordinates[true]"
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local function search_server_list(input)
|
||||
menudata.search_result = nil
|
||||
if #serverlistmgr.servers < 2 then
|
||||
return
|
||||
end
|
||||
|
||||
-- setup the keyword list
|
||||
local keywords = {}
|
||||
for word in input:gmatch("%S+") do
|
||||
word = word:gsub("(%W)", "%%%1")
|
||||
table.insert(keywords, word)
|
||||
end
|
||||
|
||||
if #keywords == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
menudata.search_result = {}
|
||||
|
||||
-- Search the serverlist
|
||||
local search_result = {}
|
||||
for i = 1, #serverlistmgr.servers do
|
||||
local server = serverlistmgr.servers[i]
|
||||
local found = 0
|
||||
for k = 1, #keywords do
|
||||
local keyword = keywords[k]
|
||||
if server.name then
|
||||
local sername = server.name:lower()
|
||||
local _, count = sername:gsub(keyword, keyword)
|
||||
found = found + count * 4
|
||||
end
|
||||
|
||||
if server.description then
|
||||
local desc = server.description:lower()
|
||||
local _, count = desc:gsub(keyword, keyword)
|
||||
found = found + count * 2
|
||||
end
|
||||
end
|
||||
if found > 0 then
|
||||
local points = (#serverlistmgr.servers - i) / 5 + found
|
||||
server.points = points
|
||||
table.insert(search_result, server)
|
||||
end
|
||||
end
|
||||
|
||||
if #search_result == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
table.sort(search_result, function(a, b)
|
||||
return a.points > b.points
|
||||
end)
|
||||
menudata.search_result = search_result
|
||||
end
|
||||
|
||||
local function set_selected_server(tabdata, idx, server)
|
||||
-- reset selection
|
||||
if idx == nil or server == nil then
|
||||
tabdata.selected = nil
|
||||
|
||||
core.settings:set("address", "")
|
||||
core.settings:set("remote_port", "30000")
|
||||
return
|
||||
end
|
||||
|
||||
local address = server.address
|
||||
local port = server.port
|
||||
gamedata.serverdescription = server.description
|
||||
|
||||
gamedata.fav = false
|
||||
for _, fav in ipairs(serverlistmgr.get_favorites()) do
|
||||
if address == fav.address and port == fav.port then
|
||||
gamedata.fav = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if address and port then
|
||||
core.settings:set("address", address)
|
||||
core.settings:set("remote_port", port)
|
||||
end
|
||||
tabdata.selected = idx
|
||||
end
|
||||
|
||||
local function main_button_handler(tabview, fields, name, tabdata)
|
||||
if fields.te_name then
|
||||
gamedata.playername = fields.te_name
|
||||
core.settings:set("name", fields.te_name)
|
||||
end
|
||||
|
||||
if fields.servers then
|
||||
local event = core.explode_table_event(fields.servers)
|
||||
local server = tabdata.lookup[event.row]
|
||||
|
||||
if server then
|
||||
if event.type == "DCL" then
|
||||
if not is_server_protocol_compat_or_error(
|
||||
server.proto_min, server.proto_max) then
|
||||
return true
|
||||
end
|
||||
|
||||
gamedata.address = server.address
|
||||
gamedata.port = server.port
|
||||
gamedata.playername = fields.te_name
|
||||
gamedata.selected_world = 0
|
||||
|
||||
if fields.te_pwd then
|
||||
gamedata.password = fields.te_pwd
|
||||
end
|
||||
|
||||
gamedata.servername = server.name
|
||||
gamedata.serverdescription = server.description
|
||||
|
||||
if gamedata.address and gamedata.port then
|
||||
core.settings:set("address", gamedata.address)
|
||||
core.settings:set("remote_port", gamedata.port)
|
||||
core.start()
|
||||
end
|
||||
return true
|
||||
end
|
||||
if event.type == "CHG" then
|
||||
set_selected_server(tabdata, event.row, server)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if fields.btn_delete_favorite then
|
||||
local idx = core.get_table_index("servers")
|
||||
if not idx then return end
|
||||
local server = tabdata.lookup[idx]
|
||||
if not server then return end
|
||||
|
||||
serverlistmgr.delete_favorite(server)
|
||||
-- the server at [idx+1] will be at idx once list is refreshed
|
||||
set_selected_server(tabdata, idx, tabdata.lookup[idx+1])
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_mp_clear then
|
||||
tabdata.search_for = ""
|
||||
menudata.search_result = nil
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
|
||||
tabdata.search_for = fields.te_search
|
||||
search_server_list(fields.te_search:lower())
|
||||
if menudata.search_result then
|
||||
-- first server in row 2 due to header
|
||||
set_selected_server(tabdata, 2, menudata.search_result[1])
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_mp_refresh then
|
||||
serverlistmgr.sync()
|
||||
return true
|
||||
end
|
||||
|
||||
if (fields.btn_mp_login or fields.key_enter)
|
||||
and fields.te_address ~= "" and fields.te_port then
|
||||
gamedata.playername = fields.te_name
|
||||
gamedata.password = fields.te_pwd
|
||||
gamedata.address = fields.te_address
|
||||
gamedata.port = tonumber(fields.te_port)
|
||||
|
||||
local enable_split_login_register = core.settings:get_bool("enable_split_login_register")
|
||||
gamedata.allow_login_or_register = enable_split_login_register and "login" or "any"
|
||||
gamedata.selected_world = 0
|
||||
|
||||
local idx = core.get_table_index("servers")
|
||||
local server = idx and tabdata.lookup[idx]
|
||||
|
||||
set_selected_server(tabdata)
|
||||
|
||||
if server and server.address == gamedata.address and
|
||||
server.port == gamedata.port then
|
||||
|
||||
serverlistmgr.add_favorite(server)
|
||||
|
||||
gamedata.servername = server.name
|
||||
gamedata.serverdescription = server.description
|
||||
|
||||
if not is_server_protocol_compat_or_error(
|
||||
server.proto_min, server.proto_max) then
|
||||
return true
|
||||
end
|
||||
else
|
||||
gamedata.servername = ""
|
||||
gamedata.serverdescription = ""
|
||||
|
||||
serverlistmgr.add_favorite({
|
||||
address = gamedata.address,
|
||||
port = gamedata.port,
|
||||
})
|
||||
end
|
||||
|
||||
core.settings:set("address", gamedata.address)
|
||||
core.settings:set("remote_port", gamedata.port)
|
||||
|
||||
core.start()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_mp_register and fields.te_address ~= "" and fields.te_port then
|
||||
local idx = core.get_table_index("servers")
|
||||
local server = idx and tabdata.lookup[idx]
|
||||
if server and (server.address ~= fields.te_address or server.port ~= tonumber(fields.te_port)) then
|
||||
server = nil
|
||||
end
|
||||
|
||||
if server and not is_server_protocol_compat_or_error(
|
||||
server.proto_min, server.proto_max) then
|
||||
return true
|
||||
end
|
||||
|
||||
local dlg = create_register_dialog(fields.te_address, tonumber(fields.te_port), server)
|
||||
dlg:set_parent(tabview)
|
||||
tabview:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function on_change(type, old_tab, new_tab)
|
||||
if type == "LEAVE" then return end
|
||||
serverlistmgr.sync()
|
||||
end
|
||||
|
||||
return {
|
||||
name = "online",
|
||||
caption = fgettext("Join Game"),
|
||||
cbf_formspec = get_formspec,
|
||||
cbf_button_handler = main_button_handler,
|
||||
on_change = on_change
|
||||
}
|
||||
403
builtin/mainmenu/tab_settings.lua
Normal file
403
builtin/mainmenu/tab_settings.lua
Normal file
@@ -0,0 +1,403 @@
|
||||
--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 labels = {
|
||||
leaves = {
|
||||
fgettext("Opaque Leaves"),
|
||||
fgettext("Simple Leaves"),
|
||||
fgettext("Fancy Leaves")
|
||||
},
|
||||
node_highlighting = {
|
||||
fgettext("Node Outlining"),
|
||||
fgettext("Node Highlighting"),
|
||||
fgettext("None")
|
||||
},
|
||||
filters = {
|
||||
fgettext("No Filter"),
|
||||
fgettext("Bilinear Filter"),
|
||||
fgettext("Trilinear Filter")
|
||||
},
|
||||
mipmap = {
|
||||
fgettext("No Mipmap"),
|
||||
fgettext("Mipmap"),
|
||||
fgettext("Mipmap + Aniso. Filter")
|
||||
},
|
||||
antialiasing = {
|
||||
fgettext("None"),
|
||||
fgettext("2x"),
|
||||
fgettext("4x"),
|
||||
fgettext("8x")
|
||||
},
|
||||
shadow_levels = {
|
||||
fgettext("Disabled"),
|
||||
fgettext("Very Low"),
|
||||
fgettext("Low"),
|
||||
fgettext("Medium"),
|
||||
fgettext("High"),
|
||||
fgettext("Very High")
|
||||
}
|
||||
}
|
||||
|
||||
local dd_options = {
|
||||
leaves = {
|
||||
table.concat(labels.leaves, ","),
|
||||
{"opaque", "simple", "fancy"}
|
||||
},
|
||||
node_highlighting = {
|
||||
table.concat(labels.node_highlighting, ","),
|
||||
{"box", "halo", "none"}
|
||||
},
|
||||
filters = {
|
||||
table.concat(labels.filters, ","),
|
||||
{"", "bilinear_filter", "trilinear_filter"}
|
||||
},
|
||||
mipmap = {
|
||||
table.concat(labels.mipmap, ","),
|
||||
{"", "mip_map", "anisotropic_filter"}
|
||||
},
|
||||
antialiasing = {
|
||||
table.concat(labels.antialiasing, ","),
|
||||
{"0", "2", "4", "8"}
|
||||
},
|
||||
shadow_levels = {
|
||||
table.concat(labels.shadow_levels, ","),
|
||||
{ "0", "1", "2", "3", "4", "5" }
|
||||
}
|
||||
}
|
||||
|
||||
local getSettingIndex = {
|
||||
Leaves = function()
|
||||
local style = core.settings:get("leaves_style")
|
||||
for idx, name in pairs(dd_options.leaves[2]) do
|
||||
if style == name then return idx end
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
NodeHighlighting = function()
|
||||
local style = core.settings:get("node_highlighting")
|
||||
for idx, name in pairs(dd_options.node_highlighting[2]) do
|
||||
if style == name then return idx end
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
Filter = function()
|
||||
if core.settings:get(dd_options.filters[2][3]) == "true" then
|
||||
return 3
|
||||
elseif core.settings:get(dd_options.filters[2][3]) == "false" and
|
||||
core.settings:get(dd_options.filters[2][2]) == "true" then
|
||||
return 2
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
Mipmap = function()
|
||||
if core.settings:get(dd_options.mipmap[2][3]) == "true" then
|
||||
return 3
|
||||
elseif core.settings:get(dd_options.mipmap[2][3]) == "false" and
|
||||
core.settings:get(dd_options.mipmap[2][2]) == "true" then
|
||||
return 2
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
Antialiasing = function()
|
||||
local antialiasing_setting = core.settings:get("fsaa")
|
||||
for i = 1, #dd_options.antialiasing[2] do
|
||||
if antialiasing_setting == dd_options.antialiasing[2][i] then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
ShadowMapping = function()
|
||||
local shadow_setting = core.settings:get("shadow_levels")
|
||||
for i = 1, #dd_options.shadow_levels[2] do
|
||||
if shadow_setting == dd_options.shadow_levels[2][i] then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
}
|
||||
|
||||
local function antialiasing_fname_to_name(fname)
|
||||
for i = 1, #labels.antialiasing do
|
||||
if fname == labels.antialiasing[i] then
|
||||
return dd_options.antialiasing[2][i]
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local function formspec(tabview, name, tabdata)
|
||||
local tab_string =
|
||||
"box[0,0;3.75,4.5;#999999]" ..
|
||||
"checkbox[0.25,0;cb_smooth_lighting;" .. fgettext("Smooth Lighting") .. ";"
|
||||
.. dump(core.settings:get_bool("smooth_lighting")) .. "]" ..
|
||||
"checkbox[0.25,0.5;cb_particles;" .. fgettext("Particles") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_particles")) .. "]" ..
|
||||
"checkbox[0.25,1;cb_3d_clouds;" .. fgettext("3D Clouds") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_3d_clouds")) .. "]" ..
|
||||
"checkbox[0.25,1.5;cb_opaque_water;" .. fgettext("Opaque Water") .. ";"
|
||||
.. dump(core.settings:get_bool("opaque_water")) .. "]" ..
|
||||
"checkbox[0.25,2.0;cb_connected_glass;" .. fgettext("Connected Glass") .. ";"
|
||||
.. dump(core.settings:get_bool("connected_glass")) .. "]" ..
|
||||
"dropdown[0.25,2.8;3.5;dd_node_highlighting;" .. dd_options.node_highlighting[1] .. ";"
|
||||
.. getSettingIndex.NodeHighlighting() .. "]" ..
|
||||
"dropdown[0.25,3.6;3.5;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
|
||||
.. getSettingIndex.Leaves() .. "]" ..
|
||||
"box[4,0;3.75,4.9;#999999]" ..
|
||||
"label[4.25,0.1;" .. fgettext("Texturing:") .. "]" ..
|
||||
"dropdown[4.25,0.55;3.5;dd_filters;" .. dd_options.filters[1] .. ";"
|
||||
.. getSettingIndex.Filter() .. "]" ..
|
||||
"dropdown[4.25,1.35;3.5;dd_mipmap;" .. dd_options.mipmap[1] .. ";"
|
||||
.. getSettingIndex.Mipmap() .. "]" ..
|
||||
"label[4.25,2.15;" .. fgettext("Antialiasing:") .. "]" ..
|
||||
"dropdown[4.25,2.6;3.5;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
|
||||
.. getSettingIndex.Antialiasing() .. "]" ..
|
||||
"box[8,0;3.75,4.5;#999999]"
|
||||
|
||||
local video_driver = core.settings:get("video_driver")
|
||||
local shaders_enabled = core.settings:get_bool("enable_shaders")
|
||||
if video_driver == "opengl" then
|
||||
tab_string = tab_string ..
|
||||
"checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders") .. ";"
|
||||
.. tostring(shaders_enabled) .. "]"
|
||||
elseif video_driver == "ogles2" then
|
||||
tab_string = tab_string ..
|
||||
"checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders (experimental)") .. ";"
|
||||
.. tostring(shaders_enabled) .. "]"
|
||||
else
|
||||
core.settings:set_bool("enable_shaders", false)
|
||||
shaders_enabled = false
|
||||
tab_string = tab_string ..
|
||||
"label[8.38,0.2;" .. core.colorize("#888888",
|
||||
fgettext("Shaders (unavailable)")) .. "]"
|
||||
end
|
||||
|
||||
tab_string = tab_string ..
|
||||
"button[8,4.75;3.95,1;btn_change_keys;"
|
||||
.. fgettext("Change Keys") .. "]"
|
||||
|
||||
tab_string = tab_string ..
|
||||
"button[0,4.75;3.95,1;btn_advanced_settings;"
|
||||
.. fgettext("All Settings") .. "]"
|
||||
|
||||
|
||||
if core.settings:get("touchscreen_threshold") ~= nil then
|
||||
tab_string = tab_string ..
|
||||
"label[4.25,3.5;" .. fgettext("Touch threshold (px):") .. "]" ..
|
||||
"dropdown[4.25,3.95;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
|
||||
((tonumber(core.settings:get("touchscreen_threshold")) / 10) + 1) ..
|
||||
"]"
|
||||
else
|
||||
tab_string = tab_string ..
|
||||
"label[4.25,3.65;" .. fgettext("Screen:") .. "]" ..
|
||||
"checkbox[4.25,3.9;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
|
||||
.. dump(core.settings:get_bool("autosave_screensize")) .. "]"
|
||||
end
|
||||
|
||||
if shaders_enabled then
|
||||
tab_string = tab_string ..
|
||||
"checkbox[8.25,0.5;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
|
||||
.. dump(core.settings:get_bool("tone_mapping")) .. "]" ..
|
||||
"checkbox[8.25,1;cb_waving_water;" .. fgettext("Waving Liquids") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_water")) .. "]" ..
|
||||
"checkbox[8.25,1.5;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_leaves")) .. "]" ..
|
||||
"checkbox[8.25,2;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_plants")) .. "]"
|
||||
|
||||
if video_driver == "opengl" then
|
||||
tab_string = tab_string ..
|
||||
"label[8.25,2.8;" .. fgettext("Dynamic shadows:") .. "]" ..
|
||||
"label[8.25,3.2;" .. fgettext("(game support required)") .. "]" ..
|
||||
"dropdown[8.25,3.7;3.5;dd_shadows;" .. dd_options.shadow_levels[1] .. ";"
|
||||
.. getSettingIndex.ShadowMapping() .. "]"
|
||||
else
|
||||
tab_string = tab_string ..
|
||||
"label[8.38,2.7;" .. core.colorize("#888888",
|
||||
fgettext("Dynamic shadows")) .. "]"
|
||||
end
|
||||
else
|
||||
tab_string = tab_string ..
|
||||
"label[8.38,0.7;" .. core.colorize("#888888",
|
||||
fgettext("Tone Mapping")) .. "]" ..
|
||||
"label[8.38,1.2;" .. core.colorize("#888888",
|
||||
fgettext("Waving Liquids")) .. "]" ..
|
||||
"label[8.38,1.7;" .. core.colorize("#888888",
|
||||
fgettext("Waving Leaves")) .. "]" ..
|
||||
"label[8.38,2.2;" .. core.colorize("#888888",
|
||||
fgettext("Waving Plants")) .. "]"..
|
||||
"label[8.38,2.7;" .. core.colorize("#888888",
|
||||
fgettext("Dynamic shadows")) .. "]"
|
||||
end
|
||||
|
||||
return tab_string
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
local function handle_settings_buttons(this, fields, tabname, tabdata)
|
||||
|
||||
if fields["btn_advanced_settings"] ~= nil then
|
||||
local adv_settings_dlg = create_adv_settings_dlg()
|
||||
adv_settings_dlg:set_parent(this)
|
||||
this:hide()
|
||||
adv_settings_dlg:show()
|
||||
--mm_game_theme.update("singleplayer", current_game())
|
||||
return true
|
||||
end
|
||||
if fields["cb_smooth_lighting"] then
|
||||
core.settings:set("smooth_lighting", fields["cb_smooth_lighting"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_particles"] then
|
||||
core.settings:set("enable_particles", fields["cb_particles"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_3d_clouds"] then
|
||||
core.settings:set("enable_3d_clouds", fields["cb_3d_clouds"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_opaque_water"] then
|
||||
core.settings:set("opaque_water", fields["cb_opaque_water"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_connected_glass"] then
|
||||
core.settings:set("connected_glass", fields["cb_connected_glass"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_autosave_screensize"] then
|
||||
core.settings:set("autosave_screensize", fields["cb_autosave_screensize"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_shaders"] then
|
||||
core.settings:set("enable_shaders", fields["cb_shaders"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_tonemapping"] then
|
||||
core.settings:set("tone_mapping", fields["cb_tonemapping"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_waving_water"] then
|
||||
core.settings:set("enable_waving_water", fields["cb_waving_water"])
|
||||
return true
|
||||
end
|
||||
if fields["cb_waving_leaves"] then
|
||||
core.settings:set("enable_waving_leaves", fields["cb_waving_leaves"])
|
||||
end
|
||||
if fields["cb_waving_plants"] then
|
||||
core.settings:set("enable_waving_plants", fields["cb_waving_plants"])
|
||||
return true
|
||||
end
|
||||
if fields["btn_change_keys"] then
|
||||
core.show_keys_menu()
|
||||
return true
|
||||
end
|
||||
if fields["cb_touchscreen_target"] then
|
||||
core.settings:set("touchtarget", fields["cb_touchscreen_target"])
|
||||
return true
|
||||
end
|
||||
|
||||
--Note dropdowns have to be handled LAST!
|
||||
local ddhandled = false
|
||||
|
||||
for i = 1, #labels.leaves do
|
||||
if fields["dd_leaves_style"] == labels.leaves[i] then
|
||||
core.settings:set("leaves_style", dd_options.leaves[2][i])
|
||||
ddhandled = true
|
||||
end
|
||||
end
|
||||
for i = 1, #labels.node_highlighting do
|
||||
if fields["dd_node_highlighting"] == labels.node_highlighting[i] then
|
||||
core.settings:set("node_highlighting", dd_options.node_highlighting[2][i])
|
||||
ddhandled = true
|
||||
end
|
||||
end
|
||||
if fields["dd_filters"] == labels.filters[1] then
|
||||
core.settings:set("bilinear_filter", "false")
|
||||
core.settings:set("trilinear_filter", "false")
|
||||
ddhandled = true
|
||||
elseif fields["dd_filters"] == labels.filters[2] then
|
||||
core.settings:set("bilinear_filter", "true")
|
||||
core.settings:set("trilinear_filter", "false")
|
||||
ddhandled = true
|
||||
elseif fields["dd_filters"] == labels.filters[3] then
|
||||
core.settings:set("bilinear_filter", "false")
|
||||
core.settings:set("trilinear_filter", "true")
|
||||
ddhandled = true
|
||||
end
|
||||
if fields["dd_mipmap"] == labels.mipmap[1] then
|
||||
core.settings:set("mip_map", "false")
|
||||
core.settings:set("anisotropic_filter", "false")
|
||||
ddhandled = true
|
||||
elseif fields["dd_mipmap"] == labels.mipmap[2] then
|
||||
core.settings:set("mip_map", "true")
|
||||
core.settings:set("anisotropic_filter", "false")
|
||||
ddhandled = true
|
||||
elseif fields["dd_mipmap"] == labels.mipmap[3] then
|
||||
core.settings:set("mip_map", "true")
|
||||
core.settings:set("anisotropic_filter", "true")
|
||||
ddhandled = true
|
||||
end
|
||||
if fields["dd_antialiasing"] then
|
||||
core.settings:set("fsaa",
|
||||
antialiasing_fname_to_name(fields["dd_antialiasing"]))
|
||||
ddhandled = true
|
||||
end
|
||||
if fields["dd_touchthreshold"] then
|
||||
core.settings:set("touchscreen_threshold", fields["dd_touchthreshold"])
|
||||
ddhandled = true
|
||||
end
|
||||
|
||||
for i = 1, #labels.shadow_levels do
|
||||
if fields["dd_shadows"] == labels.shadow_levels[i] then
|
||||
core.settings:set("shadow_levels", dd_options.shadow_levels[2][i])
|
||||
ddhandled = true
|
||||
end
|
||||
end
|
||||
|
||||
if fields["dd_shadows"] == labels.shadow_levels[1] then
|
||||
core.settings:set("enable_dynamic_shadows", "false")
|
||||
else
|
||||
local shadow_presets = {
|
||||
[2] = { 62, 512, "true", 0, "false" },
|
||||
[3] = { 93, 1024, "true", 0, "false" },
|
||||
[4] = { 140, 2048, "true", 1, "false" },
|
||||
[5] = { 210, 4096, "true", 2, "true" },
|
||||
[6] = { 300, 8192, "true", 2, "true" },
|
||||
}
|
||||
local s = shadow_presets[table.indexof(labels.shadow_levels, fields["dd_shadows"])]
|
||||
if s then
|
||||
core.settings:set("enable_dynamic_shadows", "true")
|
||||
core.settings:set("shadow_map_max_distance", s[1])
|
||||
core.settings:set("shadow_map_texture_size", s[2])
|
||||
core.settings:set("shadow_map_texture_32bit", s[3])
|
||||
core.settings:set("shadow_filters", s[4])
|
||||
core.settings:set("shadow_map_color", s[5])
|
||||
end
|
||||
end
|
||||
|
||||
return ddhandled
|
||||
end
|
||||
|
||||
return {
|
||||
name = "settings",
|
||||
caption = fgettext("Settings"),
|
||||
cbf_formspec = formspec,
|
||||
cbf_button_handler = handle_settings_buttons
|
||||
}
|
||||
29
builtin/mainmenu/tests/favorites_wellformed.txt
Normal file
29
builtin/mainmenu/tests/favorites_wellformed.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
[server]
|
||||
|
||||
127.0.0.1
|
||||
30000
|
||||
|
||||
|
||||
[server]
|
||||
|
||||
localhost
|
||||
30000
|
||||
|
||||
|
||||
[server]
|
||||
|
||||
vps.rubenwardy.com
|
||||
30001
|
||||
|
||||
|
||||
[server]
|
||||
|
||||
gundul.ddnss.de
|
||||
39155
|
||||
|
||||
|
||||
[server]
|
||||
VanessaE's Dreambuilder creative Server
|
||||
daconcepts.com
|
||||
30000
|
||||
VanessaE's Dreambuilder creative-mode server. Lots of mods, whitelisted buckets.
|
||||
38
builtin/mainmenu/tests/serverlistmgr_spec.lua
Normal file
38
builtin/mainmenu/tests/serverlistmgr_spec.lua
Normal file
@@ -0,0 +1,38 @@
|
||||
_G.core = {}
|
||||
_G.vector = {metatable = {}}
|
||||
_G.unpack = table.unpack
|
||||
_G.serverlistmgr = {}
|
||||
|
||||
dofile("builtin/common/vector.lua")
|
||||
dofile("builtin/common/misc_helpers.lua")
|
||||
dofile("builtin/mainmenu/serverlistmgr.lua")
|
||||
|
||||
local base = "builtin/mainmenu/tests/"
|
||||
|
||||
describe("legacy favorites", function()
|
||||
it("loads well-formed correctly", function()
|
||||
local favs = serverlistmgr.read_legacy_favorites(base .. "favorites_wellformed.txt")
|
||||
|
||||
local expected = {
|
||||
{
|
||||
address = "127.0.0.1",
|
||||
port = 30000,
|
||||
},
|
||||
|
||||
{ address = "localhost", port = 30000 },
|
||||
|
||||
{ address = "vps.rubenwardy.com", port = 30001 },
|
||||
|
||||
{ address = "gundul.ddnss.de", port = 39155 },
|
||||
|
||||
{
|
||||
address = "daconcepts.com",
|
||||
port = 30000,
|
||||
name = "VanessaE's Dreambuilder creative Server",
|
||||
description = "VanessaE's Dreambuilder creative-mode server. Lots of mods, whitelisted buckets."
|
||||
},
|
||||
}
|
||||
|
||||
assert.same(expected, favs)
|
||||
end)
|
||||
end)
|
||||
Reference in New Issue
Block a user