aboutsummaryrefslogtreecommitdiff
path: root/builtin/mainmenu
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/mainmenu')
-rw-r--r--builtin/mainmenu/common.lua28
-rw-r--r--builtin/mainmenu/dlg_config_world.lua30
-rw-r--r--builtin/mainmenu/dlg_contentstore.lua85
-rw-r--r--builtin/mainmenu/dlg_create_world.lua275
-rw-r--r--builtin/mainmenu/dlg_settings_advanced.lua69
-rw-r--r--builtin/mainmenu/game_theme.lua (renamed from builtin/mainmenu/textures.lua)98
-rw-r--r--builtin/mainmenu/generate_from_settingtypes.lua17
-rw-r--r--builtin/mainmenu/init.lua8
-rw-r--r--builtin/mainmenu/pkgmgr.lua205
-rw-r--r--builtin/mainmenu/tab_about.lua50
-rw-r--r--builtin/mainmenu/tab_content.lua35
-rw-r--r--builtin/mainmenu/tab_local.lua92
-rw-r--r--builtin/mainmenu/tab_settings.lua20
-rw-r--r--builtin/mainmenu/tests/serverlistmgr_spec.lua1
14 files changed, 541 insertions, 472 deletions
diff --git a/builtin/mainmenu/common.lua b/builtin/mainmenu/common.lua
index 6db351048..8db8bb8d1 100644
--- a/builtin/mainmenu/common.lua
+++ b/builtin/mainmenu/common.lua
@@ -119,31 +119,27 @@ function render_serverlist_row(spec)
return table.concat(details, ",")
end
-
---------------------------------------------------------------------------------
-os.tempfolder = function()
- local temp = core.get_temp_path()
- return temp .. DIR_DELIM .. "MT_" .. math.random(0, 10000)
-end
-
+---------------------------------------------------------------------------------
os.tmpname = function()
- local path = os.tempfolder()
- io.open(path, "w"):close()
- return path
+ error('do not use') -- instead use core.get_temp_path()
end
--------------------------------------------------------------------------------
-function menu_render_worldlist()
- local retval = ""
+function menu_render_worldlist(show_gameid)
+ local retval = {}
local current_worldlist = menudata.worldlist:get_list()
+ local row
for i, v in ipairs(current_worldlist) do
- if retval ~= "" then retval = retval .. "," end
- retval = retval .. core.formspec_escape(v.name) ..
- " \\[" .. core.formspec_escape(v.gameid) .. "\\]"
+ row = v.name
+ if show_gameid == nil or show_gameid == true then
+ row = row .. " [" .. v.gameid .. "]"
+ end
+ retval[#retval+1] = core.formspec_escape(row)
+
end
- return retval
+ return table.concat(retval, ",")
end
function menu_handle_key_up_down(fields, textlist, settingname)
diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua
index 9bdf92a74..f73256612 100644
--- a/builtin/mainmenu/dlg_config_world.lua
+++ b/builtin/mainmenu/dlg_config_world.lua
@@ -163,10 +163,13 @@ local function get_formspec(data)
"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;text]" ..
"table[5.5,0.75;5.75,6;world_config_modlist;" ..
- pkgmgr.render_packagelist(data.list) .. ";" .. data.selected_mod .."]"
+ pkgmgr.render_packagelist(data.list, use_technical_names) .. ";" .. data.selected_mod .."]"
end
local function handle_buttons(this, fields)
@@ -205,14 +208,19 @@ local function handle_buttons(this, fields)
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
- worldfile:set("load_mod_" .. mod.name,
- mod.enabled and "true" or "false")
+ 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. " ..
@@ -256,12 +264,26 @@ local function handle_buttons(this, fields)
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 then
+ 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
diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua
index 790da03ba..ff32c8c9f 100644
--- a/builtin/mainmenu/dlg_contentstore.lua
+++ b/builtin/mainmenu/dlg_contentstore.lua
@@ -25,7 +25,7 @@ end
-- Unordered preserves the original order of the ContentDB API,
-- before the package list is ordered based on installed state.
-local store = { packages = {}, packages_full = {}, packages_full_unordered = {} }
+local store = { packages = {}, packages_full = {}, packages_full_unordered = {}, aliases = {} }
local http = core.get_http_api()
@@ -62,9 +62,19 @@ local REASON_UPDATE = "update"
local REASON_DEPENDENCY = "dependency"
+-- encodes for use as URL parameter or path component
+local function urlencode(str)
+ return str:gsub("[^%a%d()._~-]", function(char)
+ return string.format("%%%02X", string.byte(char))
+ end)
+end
+assert(urlencode("sample text?") == "sample%20text%3F")
+
+
local function get_download_url(package, reason)
local base_url = core.settings:get("contentdb_url")
- local ret = base_url .. ("/packages/%s/%s/releases/%d/download/"):format(package.author, package.name, package.release)
+ local ret = base_url .. ("/packages/%s/releases/%d/download/"):format(
+ package.url_part, package.release)
if reason then
ret = ret .. "?reason=" .. reason
end
@@ -72,34 +82,52 @@ local function get_download_url(package, reason)
end
-local function download_package(param)
- if core.download_file(param.url, param.filename) then
+local function download_and_extract(param)
+ local package = param.package
+
+ local filename = core.get_temp_path(true)
+ if filename == "" or not core.download_file(param.url, filename) then
+ core.log("error", "Downloading " .. dump(param.url) .. " failed")
return {
- filename = param.filename,
- successful = true,
+ msg = fgettext("Failed to download $1", package.name)
}
+ end
+
+ local tempfolder = core.get_temp_path()
+ if tempfolder ~= "" then
+ tempfolder = tempfolder .. DIR_DELIM .. "MT_" .. math.random(1, 1024000)
+ if not core.extract_zip(filename, tempfolder) then
+ tempfolder = nil
+ end
else
- core.log("error", "downloading " .. dump(param.url) .. " failed")
+ tempfolder = nil
+ end
+ os.remove(filename)
+ if not tempfolder then
return {
- successful = false,
+ msg = fgettext("Install: Unsupported file type or broken archive"),
}
end
+
+ return {
+ path = tempfolder
+ }
end
local function start_install(package, reason)
local params = {
package = package,
url = get_download_url(package, reason),
- filename = os.tempfolder() .. "_MODNAME_" .. package.name .. ".zip",
}
number_downloading = number_downloading + 1
local function callback(result)
- if result.successful then
- local path, msg = pkgmgr.install(package.type,
- result.filename, package.name,
- package.path)
+ if result.msg then
+ gamedata.errormessage = result.msg
+ else
+ local path, msg = pkgmgr.install_dir(package.type, result.path, package.name, package.path)
+ core.delete_dir(result.path)
if not path then
gamedata.errormessage = msg
else
@@ -137,9 +165,6 @@ local function start_install(package, reason)
conf:write()
end
end
- os.remove(result.filename)
- else
- gamedata.errormessage = fgettext("Failed to download $1", package.name)
end
package.downloading = false
@@ -159,7 +184,7 @@ local function start_install(package, reason)
package.queued = false
package.downloading = true
- if not core.handle_async(download_package, params, callback) then
+ if not core.handle_async(download_and_extract, params, callback) then
core.log("error", "ERROR: async event failed")
gamedata.errormessage = fgettext("Failed to download $1", package.name)
return
@@ -184,7 +209,7 @@ local function get_raw_dependencies(package)
local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s"
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
- local url = base_url .. url_fmt:format(package.id, core.get_max_supp_proto(), version.string)
+ local url = base_url .. url_fmt:format(package.url_part, core.get_max_supp_proto(), urlencode(version.string))
local response = http.fetch_sync({ url = url })
if not response.succeeded then
@@ -559,17 +584,16 @@ function store.load()
local base_url = core.settings:get("contentdb_url")
local url = base_url ..
"/api/packages/?type=mod&type=game&type=txp&protocol_version=" ..
- core.get_max_supp_proto() .. "&engine_version=" .. version.string
+ core.get_max_supp_proto() .. "&engine_version=" .. urlencode(version.string)
for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do
item = item:trim()
if item ~= "" then
- url = url .. "&hide=" .. item
+ url = url .. "&hide=" .. urlencode(item)
end
end
- local timeout = tonumber(core.settings:get("curl_file_download_timeout"))
- local response = http.fetch_sync({ url = url, timeout = timeout })
+ local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
@@ -579,12 +603,16 @@ function store.load()
for _, package in pairs(store.packages_full) do
local name_len = #package.name
+ -- This must match what store.update_paths() does!
+ package.id = package.author:lower() .. "/"
if package.type == "game" and name_len > 5 and package.name:sub(name_len - 4) == "_game" then
- package.id = package.author:lower() .. "/" .. package.name:sub(1, name_len - 5)
+ package.id = package.id .. package.name:sub(1, name_len - 5)
else
- package.id = package.author:lower() .. "/" .. package.name
+ package.id = package.id .. package.name
end
+ package.url_part = urlencode(package.author) .. "/" .. urlencode(package.name)
+
if package.aliases then
for _, alias in ipairs(package.aliases) do
-- We currently don't support name changing
@@ -834,8 +862,7 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
elseif package.queued then
formspec[#formspec + 1] = left_base
- formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
- formspec[#formspec + 1] = "cdb_queued.png;queued]"
+ formspec[#formspec + 1] = "cdb_queued.png;queued;]"
elseif not package.path then
local elem_name = "install_" .. i .. ";"
formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]"
@@ -998,9 +1025,9 @@ function store.handle_submit(this, fields)
end
if fields["view_" .. i] then
- local url = ("%s/packages/%s/%s?protocol_version=%d"):format(
- core.settings:get("contentdb_url"),
- package.author, package.name, core.get_max_supp_proto())
+ local url = ("%s/packages/%s?protocol_version=%d"):format(
+ core.settings:get("contentdb_url"), package.url_part,
+ core.get_max_supp_proto())
core.open_url(url)
return true
end
diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
index 1938747fe..76ceb0f16 100644
--- a/builtin/mainmenu/dlg_create_world.lua
+++ b/builtin/mainmenu/dlg_create_world.lua
@@ -15,7 +15,8 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-local worldname = ""
+-- cf. tab_local, the gamebar already provides game selection so we hide the list from here
+local hide_gamelist = PLATFORM ~= "Android"
local function table_to_flags(ftable)
-- Convert e.g. { jungles = true, caves = false } to "jungles,nocaves"
@@ -31,9 +32,8 @@ local function strflag(flags, flag)
return (flags[flag] == true) and "true" or "false"
end
-local cb_caverns = { "caverns", fgettext("Caverns"), "caverns",
+local cb_caverns = { "caverns", fgettext("Caverns"),
fgettext("Very large caverns deep in the underground") }
-local tt_sea_rivers = fgettext("Sea level rivers")
local flag_checkboxes = {
v5 = {
@@ -41,39 +41,38 @@ local flag_checkboxes = {
},
v7 = {
cb_caverns,
- { "ridges", fgettext("Rivers"), "ridges", tt_sea_rivers },
- { "mountains", fgettext("Mountains"), "mountains" },
- { "floatlands", fgettext("Floatlands (experimental)"), "floatlands",
+ { "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"), "rivers", tt_sea_rivers },
+ { "rivers", fgettext("Rivers"), fgettext("Sea level rivers") },
},
valleys = {
- { "altitude-chill", fgettext("Altitude chill"), "altitude_chill",
+ { "altitude_chill", fgettext("Altitude chill"),
fgettext("Reduces heat with altitude") },
- { "altitude-dry", fgettext("Altitude dry"), "altitude_dry",
+ { "altitude_dry", fgettext("Altitude dry"),
fgettext("Reduces humidity with altitude") },
- { "humid-rivers", fgettext("Humid rivers"), "humid_rivers",
+ { "humid_rivers", fgettext("Humid rivers"),
fgettext("Increases humidity around rivers") },
- { "vary-river-depth", fgettext("Vary river depth"), "vary_river_depth",
+ { "vary_river_depth", fgettext("Vary river depth"),
fgettext("Low humidity and high heat causes shallow or dry rivers") },
},
flat = {
cb_caverns,
- { "hills", fgettext("Hills"), "hills" },
- { "lakes", fgettext("Lakes"), "lakes" },
+ { "hills", fgettext("Hills") },
+ { "lakes", fgettext("Lakes") },
},
fractal = {
- { "terrain", fgettext("Additional terrain"), "terrain",
+ { "terrain", fgettext("Additional terrain"),
fgettext("Generate non-fractal terrain: Oceans and underground") },
},
v6 = {
- { "trees", fgettext("Trees and jungle grass"), "trees" },
- { "flat", fgettext("Flat terrain"), "flat" },
- { "mudflow", fgettext("Mud flow"), "mudflow",
- fgettext("Terrain surface erosion") },
+ { "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
},
}
@@ -105,38 +104,26 @@ local function create_world_formspec(dialogdata)
"button[4.75,2.5;3,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
end
+ local current_mg = dialogdata.mg
local mapgens = core.get_mapgen_names()
- local current_seed = core.settings:get("fixed_map_seed") or ""
- local current_mg = core.settings:get("mg_name")
local gameid = core.settings:get("menu_last_game")
- local 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"),
- }
-
- local gameidx = 0
- if gameid ~= nil then
- local _
- _, gameidx = pkgmgr.find_by_gameid(gameid)
+ local flags = dialogdata.flags
- if gameidx == nil then
- gameidx = 0
- end
+ local game, gameidx = pkgmgr.find_by_gameid(gameid)
+ if game == nil and hide_gamelist then
+ -- should never happen but just pick the first game
+ game = pkgmgr.get_game(1)
+ gameidx = 1
+ core.settings:set("menu_last_game", game.id)
+ elseif game == nil then
+ gameidx = 0
end
- local game_by_gameidx = core.get_game(gameidx)
local disallowed_mapgen_settings = {}
- if game_by_gameidx ~= nil then
- local gamepath = game_by_gameidx.path
- local gameconfig = Settings(gamepath.."/game.conf")
+ 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
@@ -156,7 +143,7 @@ local function create_world_formspec(dialogdata)
end
end
- if disallowed_mapgens then
+ if #disallowed_mapgens > 0 then
for i = #mapgens, 1, -1 do
if table.indexof(disallowed_mapgens, mapgens[i]) > 0 then
table.remove(mapgens, i)
@@ -172,23 +159,29 @@ local function create_world_formspec(dialogdata)
local mglist = ""
local selindex
- local i = 1
- local first_mg
- for k,v in pairs(mapgens) do
- if not first_mg then
- first_mg = v
+ 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 current_mg == v then
- selindex = i
+ if not selindex then
+ selindex = 1
+ current_mg = first_mg
end
- i = i + 1
- mglist = mglist .. v .. ","
- end
- if not selindex then
- selindex = 1
- current_mg = first_mg
+ mglist = mglist:sub(1, -2)
end
- mglist = mglist:sub(1, -2)
+
+ -- 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
@@ -198,11 +191,11 @@ local function create_world_formspec(dialogdata)
return "", y
end
- local form = "checkbox[0," .. y .. ";flag_mg_caves;" ..
+ local form = "checkbox[0," .. y .. ";flag_main_caves;" ..
fgettext("Caves") .. ";"..strflag(flags.main, "caves").."]"
y = y + 0.5
- form = form .. "checkbox[0,"..y..";flag_mg_dungeons;" ..
+ form = form .. "checkbox[0,"..y..";flag_main_dungeons;" ..
fgettext("Dungeons") .. ";"..strflag(flags.main, "dungeons").."]"
y = y + 0.5
@@ -213,7 +206,7 @@ local function create_world_formspec(dialogdata)
else
d_tt = fgettext("Structures appearing on the terrain, typically trees and plants")
end
- form = form .. "checkbox[0,"..y..";flag_mg_decorations;" ..
+ form = form .. "checkbox[0,"..y..";flag_main_decorations;" ..
d_name .. ";" ..
strflag(flags.main, "decorations").."]" ..
"tooltip[flag_mg_decorations;" ..
@@ -221,7 +214,7 @@ local function create_world_formspec(dialogdata)
"]"
y = y + 0.5
- form = form .. "tooltip[flag_mg_caves;" ..
+ form = form .. "tooltip[flag_main_caves;" ..
fgettext("Network of tunnels and caves")
.. "]"
return form, y
@@ -235,13 +228,13 @@ local function create_world_formspec(dialogdata)
return "", y
end
local form = ""
- for _,tab in pairs(flag_checkboxes[mapgen]) do
- local id = "flag_mg"..mapgen.."_"..tab[1]
+ 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[3]))
+ format(y, id, tab[2], strflag(flags[mapgen], tab[1]))
- if tab[4] then
- form = form .. "tooltip["..id..";"..tab[4].."]"
+ if tab[3] then
+ form = form .. "tooltip["..id..";"..tab[3].."]"
end
y = y + 0.5
end
@@ -277,16 +270,14 @@ local function create_world_formspec(dialogdata)
-- biomeblend
y = y + 0.55
- form = form .. "checkbox[0,"..y..";flag_mgv6_biomeblend;" ..
+ form = form .. "checkbox[0,"..y..";flag_v6_biomeblend;" ..
fgettext("Biome blending") .. ";"..strflag(flags.v6, "biomeblend").."]" ..
- "tooltip[flag_mgv6_biomeblend;" ..
+ "tooltip[flag_v6_biomeblend;" ..
fgettext("Smooth transition between biomes") .. "]"
return form, y
end
- current_seed = core.formspec_escape(current_seed)
-
local y_start = 0.0
local y = y_start
local str_flags, str_spflags
@@ -323,21 +314,32 @@ local function create_world_formspec(dialogdata)
"container[0,0]"..
"field[0.3,0.6;6,0.5;te_world_name;" ..
fgettext("World name") ..
- ";" .. core.formspec_escape(worldname) .. "]" ..
+ ";" .. core.formspec_escape(dialogdata.worldname) .. "]" ..
+ "set_focus[te_world_name;false]"
+
+ if not disallowed_mapgen_settings["seed"] then
- "field[0.3,1.7;6,0.5;te_seed;" ..
- fgettext("Seed") ..
- ";".. current_seed .. "]" ..
+ 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 .. "]" ..
+ "dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]"
+
+ if not hide_gamelist or devtest_only ~= "" then
+ retval = retval ..
+ "label[0,3.35;" .. fgettext("Game") .. "]"..
+ "textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
+ pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
+ "container[0,4.5]" ..
+ devtest_only ..
+ "container_end[]"
+ end
- "label[0,3.35;" .. fgettext("Game") .. "]"..
- "textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
- pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
- "container[0,4.5]" ..
- devtest_only ..
- "container_end[]" ..
+ retval = retval ..
"container_end[]" ..
-- Right side
@@ -360,9 +362,20 @@ local function create_world_buttonhandler(this, fields)
fields["key_enter"] then
local worldname = fields["te_world_name"]
- local gameindex = core.get_textlist_index("games")
+ local game, gameindex
+ if hide_gamelist then
+ game, gameindex = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
+ else
+ gameindex = core.get_textlist_index("games")
+ game = pkgmgr.get_game(gameindex)
+ end
+
+ local message
+ if game == nil then
+ message = fgettext("No game selected")
+ end
- if gameindex ~= nil then
+ 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.
@@ -377,36 +390,48 @@ local function create_world_buttonhandler(this, fields)
worldname = "world" .. worldnum_max + 1
end
- core.settings:set("fixed_map_seed", fields["te_seed"])
-
- local message
- if not menudata.worldlist:uid_exists_raw(worldname) then
- core.settings:set("mg_name",fields["dd_mapgen"])
- message = core.create_world(worldname,gameindex)
- else
+ if menudata.worldlist:uid_exists_raw(worldname) then
message = fgettext("A world named \"$1\" already exists", worldname)
end
+ end
- if message ~= nil then
- gamedata.errormessage = message
- else
- core.settings:set("menu_last_game",pkgmgr.games[gameindex].id)
- if this.data.update_worldlist_filter then
- menudata.worldlist:set_filtercriteria(pkgmgr.games[gameindex].id)
- mm_texture.update("singleplayer", pkgmgr.games[gameindex].id)
- end
- menudata.worldlist:refresh()
- core.settings:set("mainmenu_last_selected_world",
- menudata.worldlist:raw_index_by_uid(worldname))
+ 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)
+ if this.data.update_worldlist_filter then
+ menudata.worldlist:set_filtercriteria(game.id)
end
- else
- gamedata.errormessage = fgettext("No game selected")
+ 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
- worldname = fields.te_world_name
+ 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")
@@ -417,22 +442,11 @@ local function create_world_buttonhandler(this, fields)
for k,v in pairs(fields) do
local split = string.split(k, "_", nil, 3)
if split and split[1] == "flag" then
- local setting
- if split[2] == "mg" then
- setting = "mg_flags"
- else
- setting = split[2].."_spflags"
- end
-- We replaced the underscore of flag names with a dash.
local flag = string.gsub(split[3], "-", "_")
- local ftable = core.settings:get_flags(setting)
- if v == "true" then
- ftable[flag] = true
- else
- ftable[flag] = false
- end
- local flags = table_to_flags(ftable)
- core.settings:set(setting, flags)
+ local ftable = this.data.flags[split[2]]
+ assert(ftable)
+ ftable[flag] = v == "true"
return true
end
end
@@ -446,18 +460,16 @@ local function create_world_buttonhandler(this, fields)
local entry = core.formspec_escape(fields["mgv6_biomes"])
for b=1, #mgv6_biomes do
if entry == mgv6_biomes[b][1] then
- local ftable = core.settings:get_flags("mgv6_spflags")
+ local ftable = this.data.flags.v6
ftable.jungles = mgv6_biomes[b][2].jungles
ftable.snowbiomes = mgv6_biomes[b][2].snowbiomes
- local flags = table_to_flags(ftable)
- core.settings:set("mgv6_spflags", flags)
return true
end
end
end
if fields["dd_mapgen"] then
- core.settings:set("mg_name", fields["dd_mapgen"])
+ this.data.mg = fields["dd_mapgen"]
return true
end
@@ -466,12 +478,27 @@ end
function create_create_world_dlg(update_worldlistfilter)
- worldname = ""
local retval = dialog_create("sp_create_world",
create_world_formspec,
create_world_buttonhandler,
nil)
- retval.update_worldlist_filter = update_worldlistfilter
+ retval.data = {
+ update_worldlist_filter = update_worldlistfilter,
+ 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
diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua
index 38a658969..d6f485cf7 100644
--- a/builtin/mainmenu/dlg_settings_advanced.lua
+++ b/builtin/mainmenu/dlg_settings_advanced.lua
@@ -378,7 +378,7 @@ local function parse_config_file(read_all, parse_mods)
-- Parse mods
local mods_category_initialized = false
local mods = {}
- get_mods(core.get_modpath(), mods)
+ get_mods(core.get_modpath(), "mods", mods)
for _, mod in ipairs(mods) do
local path = mod.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
@@ -395,6 +395,7 @@ local function parse_config_file(read_all, parse_mods)
table.insert(settings, {
name = mod.name,
+ readable_name = mod.title,
level = 1,
type = "category",
})
@@ -408,7 +409,7 @@ local function parse_config_file(read_all, parse_mods)
-- Parse clientmods
local clientmods_category_initialized = false
local clientmods = {}
- get_mods(core.get_clientmodpath(), clientmods)
+ get_mods(core.get_clientmodpath(), "clientmods", clientmods)
for _, clientmod in ipairs(clientmods) do
local path = clientmod.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
@@ -527,44 +528,40 @@ end
local function get_current_np_group(setting)
local value = core.settings:get_np_group(setting.name)
- local t = {}
if value == nil then
- t = setting.values
- else
- table.insert(t, value.offset)
- table.insert(t, value.scale)
- table.insert(t, value.spread.x)
- table.insert(t, value.spread.y)
- table.insert(t, value.spread.z)
- table.insert(t, value.seed)
- table.insert(t, value.octaves)
- table.insert(t, value.persistence)
- table.insert(t, value.lacunarity)
- table.insert(t, value.flags)
+ return setting.values
end
- return t
+ local p = "%g"
+ return {
+ p:format(value.offset),
+ p:format(value.scale),
+ p:format(value.spread.x),
+ p:format(value.spread.y),
+ p:format(value.spread.z),
+ p:format(value.seed),
+ p:format(value.octaves),
+ p:format(value.persistence),
+ p:format(value.lacunarity),
+ value.flags
+ }
end
local function get_current_np_group_as_string(setting)
local value = core.settings:get_np_group(setting.name)
- local t
if value == nil then
- t = setting.default
- else
- t = value.offset .. ", " ..
- value.scale .. ", (" ..
- value.spread.x .. ", " ..
- value.spread.y .. ", " ..
- value.spread.z .. "), " ..
- value.seed .. ", " ..
- value.octaves .. ", " ..
- value.persistence .. ", " ..
- value.lacunarity
- if value.flags ~= "" then
- t = t .. ", " .. value.flags
- end
+ return setting.default
end
- return t
+ return ("%g, %g, (%g, %g, %g), %g, %g, %g, %g"):format(
+ value.offset,
+ value.scale,
+ value.spread.x,
+ value.spread.y,
+ value.spread.z,
+ value.seed,
+ value.octaves,
+ value.persistence,
+ value.lacunarity
+ ) .. (value.flags ~= "" and (", " .. value.flags) or "")
end
local checkboxes = {} -- handle checkboxes events
@@ -697,7 +694,7 @@ local function create_change_setting_formspec(dialogdata)
elseif setting.type == "v3f" then
local val = get_current_value(setting)
local v3f = {}
- for line in val:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
+ for line in val:gmatch("[+-]?[%d.+-eE]+") do -- All numeric characters
table.insert(v3f, line)
end
@@ -990,7 +987,7 @@ local function create_settings_formspec(tabview, _, tabdata)
local current_level = 0
for _, entry in ipairs(settings) do
local name
- if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
+ if not core.settings:get_bool("show_technical_names") and entry.readable_name then
name = fgettext_ne(entry.readable_name)
else
name = entry.name
@@ -1031,7 +1028,7 @@ local function create_settings_formspec(tabview, _, tabdata)
"button[10,4.9;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
"button[7,4.9;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
"checkbox[0,4.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
- .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
+ .. dump(core.settings:get_bool("show_technical_names")) .. "]"
return formspec
end
@@ -1114,7 +1111,7 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
end
if fields["cb_tech_settings"] then
- core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
+ core.settings:set("show_technical_names", fields["cb_tech_settings"])
core.settings:write()
core.update_formspec(this:get_formspec())
return true
diff --git a/builtin/mainmenu/textures.lua b/builtin/mainmenu/game_theme.lua
index a3acbbdec..89e1b66c8 100644
--- a/builtin/mainmenu/textures.lua
+++ b/builtin/mainmenu/game_theme.lua
@@ -16,23 +16,25 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-mm_texture = {}
+mm_game_theme = {}
--------------------------------------------------------------------------------
-function mm_texture.init()
- mm_texture.defaulttexturedir = core.get_texturepath() .. DIR_DELIM .. "base" ..
+function mm_game_theme.init()
+ mm_game_theme.defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
DIR_DELIM .. "pack" .. DIR_DELIM
- mm_texture.basetexturedir = mm_texture.defaulttexturedir
+ mm_game_theme.basetexturedir = mm_game_theme.defaulttexturedir
- mm_texture.texturepack = core.settings:get("texture_path")
+ mm_game_theme.texturepack = core.settings:get("texture_path")
- mm_texture.gameid = nil
+ mm_game_theme.gameid = nil
+
+ mm_game_theme.music_handle = nil
end
--------------------------------------------------------------------------------
-function mm_texture.update(tab,gamedetails)
+function mm_game_theme.update(tab,gamedetails)
if tab ~= "singleplayer" then
- mm_texture.reset()
+ mm_game_theme.reset()
return
end
@@ -40,50 +42,54 @@ function mm_texture.update(tab,gamedetails)
return
end
- mm_texture.update_game(gamedetails)
+ mm_game_theme.update_game(gamedetails)
end
--------------------------------------------------------------------------------
-function mm_texture.reset()
- mm_texture.gameid = nil
+function mm_game_theme.reset()
+ mm_game_theme.gameid = nil
local have_bg = false
- local have_overlay = mm_texture.set_generic("overlay")
+ local have_overlay = mm_game_theme.set_generic("overlay")
if not have_overlay then
- have_bg = mm_texture.set_generic("background")
+ have_bg = mm_game_theme.set_generic("background")
end
- mm_texture.clear("header")
- mm_texture.clear("footer")
+ mm_game_theme.clear("header")
+ mm_game_theme.clear("footer")
core.set_clouds(false)
- mm_texture.set_generic("footer")
- mm_texture.set_generic("header")
+ 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_texture.set_dirt_bg()
+ 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_texture.update_game(gamedetails)
- if mm_texture.gameid == gamedetails.id then
+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_texture.set_game("overlay",gamedetails)
+ local have_overlay = mm_game_theme.set_game("overlay",gamedetails)
if not have_overlay then
- have_bg = mm_texture.set_game("background",gamedetails)
+ have_bg = mm_game_theme.set_game("background",gamedetails)
end
- mm_texture.clear("header")
- mm_texture.clear("footer")
+ mm_game_theme.clear("header")
+ mm_game_theme.clear("footer")
core.set_clouds(false)
if not have_bg then
@@ -91,34 +97,34 @@ function mm_texture.update_game(gamedetails)
if core.settings:get_bool("menu_clouds") then
core.set_clouds(true)
else
- mm_texture.set_dirt_bg()
+ mm_game_theme.set_dirt_bg()
end
end
- mm_texture.set_game("footer",gamedetails)
- mm_texture.set_game("header",gamedetails)
+ mm_game_theme.set_game("footer",gamedetails)
+ mm_game_theme.set_game("header",gamedetails)
- mm_texture.gameid = gamedetails.id
+ mm_game_theme.gameid = gamedetails.id
end
--------------------------------------------------------------------------------
-function mm_texture.clear(identifier)
+function mm_game_theme.clear(identifier)
core.set_background(identifier,"")
end
--------------------------------------------------------------------------------
-function mm_texture.set_generic(identifier)
+function mm_game_theme.set_generic(identifier)
--try texture pack first
- if mm_texture.texturepack ~= nil then
- local path = mm_texture.texturepack .. DIR_DELIM .."menu_" ..
+ 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_texture.defaulttexturedir ~= nil then
- local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" ..
+ 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
@@ -129,14 +135,16 @@ function mm_texture.set_generic(identifier)
end
--------------------------------------------------------------------------------
-function mm_texture.set_game(identifier, gamedetails)
+function mm_game_theme.set_game(identifier, gamedetails)
if gamedetails == nil then
return false
end
- if mm_texture.texturepack ~= nil then
- local path = mm_texture.texturepack .. DIR_DELIM ..
+ 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
@@ -171,9 +179,10 @@ function mm_texture.set_game(identifier, gamedetails)
return false
end
-function mm_texture.set_dirt_bg()
- if mm_texture.texturepack ~= nil then
- local path = mm_texture.texturepack .. DIR_DELIM .."default_dirt.png"
+--------------------------------------------------------------------------------
+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
@@ -183,3 +192,12 @@ function mm_texture.set_dirt_bg()
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
diff --git a/builtin/mainmenu/generate_from_settingtypes.lua b/builtin/mainmenu/generate_from_settingtypes.lua
index 43fc57bb9..0f551fbb1 100644
--- a/builtin/mainmenu/generate_from_settingtypes.lua
+++ b/builtin/mainmenu/generate_from_settingtypes.lua
@@ -31,7 +31,7 @@ local group_format_template = [[
# octaves = %s,
# persistence = %s,
# lacunarity = %s,
-# flags = %s
+# flags =%s
# }
]]
@@ -55,7 +55,11 @@ local function create_minetest_conf_example()
end
if entry.comment ~= "" then
for _, comment_line in ipairs(entry.comment:split("\n", true)) do
- insert(result, "# " .. comment_line .. "\n")
+ if comment_line == "" then
+ insert(result, "#\n")
+ else
+ insert(result, "# " .. comment_line .. "\n")
+ end
end
end
insert(result, "# type: " .. entry.type)
@@ -73,10 +77,14 @@ local function create_minetest_conf_example()
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],
- entry.values[10]))
+ flags))
else
local append
if entry.default ~= "" then
@@ -91,7 +99,7 @@ end
local translation_file_header = [[
// This file is automatically generated
-// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files
+// 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() {]]
@@ -126,4 +134,3 @@ file = assert(io.open("src/settings_translation_file.cpp", "w"))
--file = assert(io.open("settings_translation_file.cpp", "w"))
file:write(create_translation_file())
file:close()
-
diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua
index 2481078e2..943454677 100644
--- a/builtin/mainmenu/init.lua
+++ b/builtin/mainmenu/init.lua
@@ -35,7 +35,7 @@ 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 .. "textures.lua")
+dofile(menupath .. DIR_DELIM .. "game_theme.lua")
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua")
@@ -87,7 +87,7 @@ local function init_globals()
core.settings:set("menu_last_game", default_game)
end
- mm_texture.init()
+ mm_game_theme.init()
-- Create main tabview
local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = 0})
@@ -113,7 +113,7 @@ local function init_globals()
if tv_main.current_tab == "local" then
local game = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
if game == nil then
- mm_texture.reset()
+ mm_game_theme.reset()
end
end
@@ -121,8 +121,6 @@ local function init_globals()
tv_main:show()
ui.update()
-
- core.sound_play("main_menu", true)
end
init_globals()
diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
index 58a4ed8c1..072c41f0c 100644
--- a/builtin/mainmenu/pkgmgr.lua
+++ b/builtin/mainmenu/pkgmgr.lua
@@ -78,34 +78,35 @@ local function load_texture_packs(txtpath, retval)
for _, item in ipairs(list) do
if item ~= "base" then
- local name = item
-
local path = txtpath .. DIR_DELIM .. item .. DIR_DELIM
- if path == current_texture_path then
- name = fgettext("$1 (Enabled)", name)
- end
-
local conf = Settings(path .. "texture_pack.conf")
+ 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,
- list_name = name,
type = "txp",
path = path,
- enabled = path == current_texture_path,
+ enabled = enabled,
}
end
end
end
-function get_mods(path,retval,modpack)
+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 prefix = path .. DIR_DELIM .. name
+ local mod_path = path .. DIR_DELIM .. name
+ local mod_virtual_path = virtual_path .. "/" .. name
local toadd = {
dir_name = name,
parent_dir = path,
@@ -114,18 +115,18 @@ function get_mods(path,retval,modpack)
-- Get config file
local mod_conf
- local modpack_conf = io.open(prefix .. DIR_DELIM .. "modpack.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(prefix .. DIR_DELIM .. "modpack.conf"):to_table()
+ 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(prefix .. DIR_DELIM .. "mod.conf"):to_table()
+ 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
@@ -134,14 +135,16 @@ function get_mods(path,retval,modpack)
-- 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 = prefix
+ 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(prefix .. DIR_DELIM .. "modpack.txt")
+ local modpackfile = io.open(mod_path .. DIR_DELIM .. "modpack.txt")
if modpackfile then
modpackfile:close()
toadd.is_modpack = true
@@ -153,7 +156,7 @@ function get_mods(path,retval,modpack)
elseif toadd.is_modpack then
toadd.type = "modpack"
toadd.is_modpack = true
- get_mods(prefix, retval, name)
+ get_mods(mod_path, mod_virtual_path, retval, name)
end
end
end
@@ -181,21 +184,6 @@ function pkgmgr.get_texture_packs()
end
--------------------------------------------------------------------------------
-function pkgmgr.extract(modfile)
- if modfile.type == "zip" then
- local tempfolder = os.tempfolder()
-
- if tempfolder ~= nil and
- tempfolder ~= "" then
- core.create_dir(tempfolder)
- if core.extract_zip(modfile.name,tempfolder) then
- return tempfolder
- end
- end
- end
- return nil
-end
-
function pkgmgr.get_folder_type(path)
local testfile = io.open(path .. DIR_DELIM .. "init.lua","r")
if testfile ~= nil then
@@ -349,7 +337,7 @@ function pkgmgr.identify_modname(modpath,filename)
return nil
end
--------------------------------------------------------------------------------
-function pkgmgr.render_packagelist(render_list)
+function pkgmgr.render_packagelist(render_list, use_technical_names)
if not render_list then
if not pkgmgr.global_mods then
pkgmgr.refresh_globals()
@@ -385,7 +373,12 @@ function pkgmgr.render_packagelist(render_list)
else
retval[#retval + 1] = "0"
end
- retval[#retval + 1] = core.formspec_escape(v.list_name or v.name)
+
+ 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, ",")
@@ -412,6 +405,14 @@ function pkgmgr.is_modpack_entirely_enabled(data, name)
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
@@ -420,13 +421,16 @@ local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mo
toset = not mod.enabled
end
if mod.enabled ~= toset then
- mod.enabled = toset
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
@@ -451,7 +455,7 @@ function pkgmgr.enable_mod(this, toset)
local enabled_mods = {}
toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
- if not toset then
+ 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: " ..
@@ -461,11 +465,16 @@ function pkgmgr.enable_mod(this, toset)
-- Enable mods' depends after activation
- -- Make a list of mod ids indexed by their names
+ -- 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
- mod_ids[mod2.name] = id
+ 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
@@ -482,6 +491,7 @@ function pkgmgr.enable_mod(this, toset)
end
end
end
+
-- If sp is 0, every dependency is already activated
while sp > 0 do
local name = to_enable[sp]
@@ -494,14 +504,14 @@ function pkgmgr.enable_mod(this, toset)
core.log("warning", "Mod dependency \"" .. name ..
"\" not found!")
else
- if mod_to_enable.enabled == false 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[name] then
+ if not enabled_mods[depends[i]] then
sp = sp+1
to_enable[sp] = depends[i]
end
@@ -561,11 +571,10 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
local from = basefolder and basefolder.path or path
if targetpath then
core.delete_dir(targetpath)
- core.create_dir(targetpath)
else
targetpath = core.get_texturepath() .. DIR_DELIM .. basename
end
- if not core.copy_dir(from, targetpath) then
+ if not core.copy_dir(from, targetpath, false) then
return nil,
fgettext("Failed to install $1 to $2", basename, targetpath)
end
@@ -586,7 +595,6 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
-- Get destination name for modpack
if targetpath then
core.delete_dir(targetpath)
- core.create_dir(targetpath)
else
local clean_path = nil
if basename ~= nil then
@@ -610,7 +618,6 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
if targetpath then
core.delete_dir(targetpath)
- core.create_dir(targetpath)
else
local targetfolder = basename
if targetfolder == nil then
@@ -636,14 +643,13 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
if targetpath then
core.delete_dir(targetpath)
- core.create_dir(targetpath)
else
targetpath = core.get_gamepath() .. DIR_DELIM .. basename
end
end
-- Copy it
- if not core.copy_dir(basefolder.path, targetpath) then
+ if not core.copy_dir(basefolder.path, targetpath, false) then
return nil,
fgettext("Failed to install $1 to $2", basename, targetpath)
end
@@ -658,23 +664,6 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
end
--------------------------------------------------------------------------------
-function pkgmgr.install(type, modfilename, basename, dest)
- local archive_info = pkgmgr.identify_filetype(modfilename)
- local path = pkgmgr.extract(archive_info)
-
- if path == nil then
- return nil,
- fgettext("Install: file: \"$1\"", archive_info.name) .. "\n" ..
- fgettext("Install: Unsupported file type \"$1\" or broken archive",
- archive_info.type)
- end
-
- local targetpath, msg = pkgmgr.install_dir(type, path, basename, dest)
- core.delete_dir(path)
- return targetpath, msg
-end
-
---------------------------------------------------------------------------------
function pkgmgr.prepareclientmodlist(data)
local retval = {}
@@ -683,9 +672,8 @@ function pkgmgr.prepareclientmodlist(data)
--read clientmods
local modpath = core.get_clientmodpath()
- if modpath ~= nil and
- modpath ~= "" then
- get_mods(modpath,clientmods)
+ if modpath ~= nil and modpath ~= "" then
+ get_mods(modpath, "clientmods", clientmods)
end
for i=1,#clientmods,1 do
@@ -730,16 +718,15 @@ function pkgmgr.preparemodlist(data)
local game_mods = {}
--read global mods
- local modpath = core.get_modpath()
-
- if modpath ~= nil and
- modpath ~= "" then
- get_mods(modpath,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
@@ -773,22 +760,37 @@ function pkgmgr.preparemodlist(data)
DIR_DELIM .. "world.mt"
local worldfile = Settings(filename)
-
- for key,value in pairs(worldfile:to_table()) do
+ for key, value in pairs(worldfile:to_table()) do
if key:sub(1, 9) == "load_mod_" then
key = key:sub(10)
- local element = nil
- for i=1,#retval,1 do
+ 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
- element = retval[i]
- break
+ 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 element ~= nil then
- element.enabled = value ~= "false" and value ~= "nil" and value
- else
- core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
+
+ 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
@@ -872,45 +874,6 @@ function pkgmgr.refresh_globals()
end
--------------------------------------------------------------------------------
-function pkgmgr.identify_filetype(name)
-
- if name:sub(-3):lower() == "zip" then
- return {
- name = name,
- type = "zip"
- }
- end
-
- if name:sub(-6):lower() == "tar.gz" or
- name:sub(-3):lower() == "tgz"then
- return {
- name = name,
- type = "tgz"
- }
- end
-
- if name:sub(-6):lower() == "tar.bz2" then
- return {
- name = name,
- type = "tbz"
- }
- end
-
- if name:sub(-2):lower() == "7z" then
- return {
- name = name,
- type = "7z"
- }
- end
-
- return {
- name = name,
- type = "ukn"
- }
-end
-
-
---------------------------------------------------------------------------------
function pkgmgr.find_by_gameid(gameid)
for i=1,#pkgmgr.games,1 do
if pkgmgr.games[i].id == gameid then
@@ -925,7 +888,7 @@ function pkgmgr.get_game_mods(gamespec, retval)
if gamespec ~= nil and
gamespec.gamemods_path ~= nil and
gamespec.gamemods_path ~= "" then
- get_mods(gamespec.gamemods_path, retval)
+ get_mods(gamespec.gamemods_path, ("games/%s/mods"):format(gamespec.id), retval)
end
end
diff --git a/builtin/mainmenu/tab_about.lua b/builtin/mainmenu/tab_about.lua
index cb566f773..3336786ba 100644
--- a/builtin/mainmenu/tab_about.lua
+++ b/builtin/mainmenu/tab_about.lua
@@ -38,32 +38,35 @@ local core_developers = {
"Lars Hofhansl <larsh@apache.org>",
"Pierre-Yves Rollo <dev@pyrollo.com>",
"v-rob <robinsonvincent89@gmail.com>",
+ "hecks",
+ "Hugues Ross <hugues.ross@gmail.com>",
+ "Dmitry Kostenko (x2048) <codeforsmile@gmail.com>",
}
-- For updating active/previous contributors, see the script in ./util/gather_git_credits.py
local active_contributors = {
- "Wuzzy [devtest game, visual corrections]",
- "Zughy [Visual improvements, various fixes]",
- "Maksim (MoNTE48) [Android]",
+ "Wuzzy [I18n for builtin, liquid features, fixes]",
+ "Zughy [Various features and fixes]",
"numzero [Graphics and rendering]",
- "appgurueu [Various internal fixes]",
- "Desour [Formspec and vector API changes]",
- "HybridDog [Rendering fixes and documentation]",
- "Hugues Ross [Graphics-related improvements]",
- "ANAND (ClobberXD) [Mouse buttons rebinding]",
- "luk3yx [Fixes]",
- "hecks [Audiovisuals, Lua API]",
- "LoneWolfHT [Object crosshair, documentation fixes]",
- "Lejo [Server-related improvements]",
- "EvidenceB [Compass HUD element]",
- "Paul Ouellette (pauloue) [Lua API, documentation]",
- "TheTermos [Collision detection, physics]",
+ "Desour [Internal fixes, Clipboard on X11]",
+ "Lars Müller [Various internal fixes]",
+ "JosiahWI [CMake, cleanups and fixes]",
+ "HybridDog [builtin, documentation]",
+ "Jude Melton-Houghton [Database implementation]",
+ "savilli [Fixes]",
+ "Liso [Shadow Mapping]",
+ "MoNTE48 [Build fix]",
+ "Jean-Patrick Guerrero (kilbith) [Fixes]",
+ "ROllerozxa [Code cleanups]",
+ "Lejo [bitop library integration]",
+ "LoneWolfHT [Build fixes]",
+ "NeroBurner [Joystick]",
+ "Elias Fleckenstein [Internal fixes]",
"David CARLIER [Unix & Haiku build fixes]",
- "dcbrwn [Object shading]",
- "Elias Fleckenstein [API features/fixes]",
- "Jean-Patrick Guerrero (kilbith) [model element, visual fixes]",
- "k.h.lai [Memory leak fixes, documentation]",
+ "pecksin [Clickable web links]",
+ "srfqi [Android & rendering fixes]",
+ "EvidenceB [Formspec]",
}
local previous_core_developers = {
@@ -80,6 +83,7 @@ local previous_core_developers = {
"Zeno",
"ShadowNinja <shadowninja@minetest.net>",
"Auke Kok (sofar) <sofar@foo-projects.org>",
+ "Aaron Suen <warr1024@gmail.com>",
}
local previous_contributors = {
@@ -90,10 +94,10 @@ local previous_contributors = {
"MirceaKitsune <mirceakitsune@gmail.com>",
"Constantin Wenger (SpeedProg)",
"Ciaran Gultnieks (CiaranG)",
- "stujones11 [Android UX improvements]",
- "Rogier <rogier777@gmail.com> [Fixes]",
- "Gregory Currie (gregorycu) [optimisation]",
- "srifqi [Fixes]",
+ "Paul Ouellette (pauloue)",
+ "stujones11",
+ "Rogier <rogier777@gmail.com>",
+ "Gregory Currie (gregorycu)",
"JacobF",
"Jeija <jeija@mesecons.net> [HTTP, particles]",
}
diff --git a/builtin/mainmenu/tab_content.lua b/builtin/mainmenu/tab_content.lua
index 1bffeeb22..a366d4ab4 100644
--- a/builtin/mainmenu/tab_content.lua
+++ b/builtin/mainmenu/tab_content.lua
@@ -88,12 +88,14 @@ local function get_formspec(tabview, name, tabdata)
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) ..
+ pkgmgr.render_packagelist(packages, use_technical_names) ..
";" .. tabdata.selected_pkg .. "]" ..
"button[0,4.85;5.25,0.5;btn_contentdb;".. fgettext("Browse online content") .. "]"
@@ -124,9 +126,17 @@ local function get_formspec(tabview, name, tabdata)
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(selected_pkg.name) .. "]" ..
+ "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
@@ -214,6 +224,9 @@ local function handle_doubleclick(pkg, pkg_name)
core.settings:set("texture_path", pkg.path)
end
packages = nil
+
+ mm_game_theme.init()
+ mm_game_theme.reset()
elseif pkg.is_clientside then
pkgmgr.enable_mod({data = {list = packages, selected_mod = pkg_name}})
packages = nil
@@ -276,17 +289,17 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
return true
end
- if fields.btn_mod_mgr_use_txp then
- local txp = packages:get_list()[tabdata.selected_pkg]
- core.settings:set("texture_path", txp.path)
- packages = nil
- return true
- end
-
+ if fields.btn_mod_mgr_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
- if fields.btn_mod_mgr_disable_txp then
- core.settings:set("texture_path", "")
+ core.settings:set("texture_path", txp_path)
packages = nil
+
+ mm_game_theme.init()
+ mm_game_theme.reset()
return true
end
diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua
index be5f905ac..e77c6f04d 100644
--- a/builtin/mainmenu/tab_local.lua
+++ b/builtin/mainmenu/tab_local.lua
@@ -33,10 +33,30 @@ if enable_gamebar then
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
@@ -51,26 +71,10 @@ if enable_gamebar then
return true
end
- for key,value in pairs(fields) do
- for j=1,#pkgmgr.games,1 do
- if ("game_btnbar_" .. pkgmgr.games[j].id == key) then
- mm_texture.update("singleplayer", pkgmgr.games[j])
- core.set_topleft_text(pkgmgr.games[j].name)
- core.settings:set("menu_last_game",pkgmgr.games[j].id)
- menudata.worldlist:set_filtercriteria(pkgmgr.games[j].id)
- local index = filterlist.get_current_index(menudata.worldlist,
- tonumber(core.settings:get("mainmenu_last_selected_world")))
- if not index or index < 1 then
- local selected = core.get_textlist_index("sp_worlds")
- if selected ~= nil and selected < #menudata.worldlist:get_list() then
- index = selected
- else
- index = #menudata.worldlist:get_list()
- end
- end
- menu_worldmt_legacy(index)
- return true
- end
+ for _, game in ipairs(pkgmgr.games) do
+ if fields["game_btnbar_" .. game.id] then
+ apply_game(game)
+ return true
end
end
end
@@ -79,25 +83,22 @@ if enable_gamebar then
game_buttonbar_button_handler,
{x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15})
- for i=1,#pkgmgr.games,1 do
- local btn_name = "game_btnbar_" .. pkgmgr.games[i].id
+ 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(pkgmgr.games[i].name)
+ local tooltip = core.formspec_escape(game.name)
- if pkgmgr.games[i].menuicon_path ~= nil and
- pkgmgr.games[i].menuicon_path ~= "" then
- image = core.formspec_escape(pkgmgr.games[i].menuicon_path)
+ if (game.menuicon_path or "") ~= "" then
+ image = core.formspec_escape(game.menuicon_path)
else
-
- local part1 = pkgmgr.games[i].id:sub(1,5)
- local part2 = pkgmgr.games[i].id:sub(6,10)
- local part3 = pkgmgr.games[i].id:sub(11)
+ 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 ~= nil and
- part3 ~= "" then
+ if part3 ~= "" then
text = text .. "\n" .. part3
end
end
@@ -147,8 +148,12 @@ local function get_formspec(tabview, name, tabdata)
tonumber(core.settings:get("mainmenu_last_selected_world")))
local list = menudata.worldlist:get_list()
local world = list and index and list[index]
- local gameid = world and world.gameid
- local game = gameid and pkgmgr.find_by_gameid(gameid)
+ 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 = "", "", ""
@@ -182,7 +187,7 @@ local function get_formspec(tabview, name, tabdata)
damage ..
host ..
"textlist[3.9,0.4;7.9,3.45;sp_worlds;" ..
- menu_render_worldlist() ..
+ menu_render_worldlist(not enable_gamebar) ..
";" .. index .. "]"
if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then
@@ -319,11 +324,11 @@ local function main_button_handler(this, fields, name, tabdata)
end
if fields["world_create"] ~= nil then
- local create_world_dlg = create_create_world_dlg(true)
+ local create_world_dlg = create_create_world_dlg(enable_gamebar)
create_world_dlg:set_parent(this)
this:hide()
create_world_dlg:show()
- mm_texture.update("singleplayer", current_game())
+ mm_game_theme.update("singleplayer", current_game())
return true
end
@@ -340,7 +345,7 @@ local function main_button_handler(this, fields, name, tabdata)
delete_world_dlg:set_parent(this)
this:hide()
delete_world_dlg:show()
- mm_texture.update("singleplayer",current_game())
+ mm_game_theme.update("singleplayer",current_game())
end
end
@@ -358,7 +363,7 @@ local function main_button_handler(this, fields, name, tabdata)
configdialog:set_parent(this)
this:hide()
configdialog:show()
- mm_texture.update("singleplayer",current_game())
+ mm_game_theme.update("singleplayer",current_game())
end
end
@@ -371,11 +376,8 @@ if enable_gamebar then
function on_change(type, old_tab, new_tab)
if (type == "ENTER") then
local game = current_game()
-
if game then
- menudata.worldlist:set_filtercriteria(game.id)
- core.set_topleft_text(game.name)
- mm_texture.update("singleplayer",game)
+ apply_game(game)
end
singleplayer_refresh_gamebar()
@@ -387,7 +389,7 @@ if enable_gamebar then
gamebar:hide()
end
core.set_topleft_text("")
- mm_texture.update(new_tab,nil)
+ mm_game_theme.update(new_tab,nil)
end
end
end
diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua
index f06e35872..0e761d324 100644
--- a/builtin/mainmenu/tab_settings.lua
+++ b/builtin/mainmenu/tab_settings.lua
@@ -247,7 +247,7 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
adv_settings_dlg:set_parent(this)
this:hide()
adv_settings_dlg:show()
- --mm_texture.update("singleplayer", current_game())
+ --mm_game_theme.update("singleplayer", current_game())
return true
end
if fields["cb_smooth_lighting"] then
@@ -275,13 +275,7 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
return true
end
if fields["cb_shaders"] then
- if (core.settings:get("video_driver") == "direct3d8" or
- core.settings:get("video_driver") == "direct3d9") then
- core.settings:set("enable_shaders", "false")
- gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.")
- else
- core.settings:set("enable_shaders", fields["cb_shaders"])
- end
+ core.settings:set("enable_shaders", fields["cb_shaders"])
return true
end
if fields["cb_tonemapping"] then
@@ -370,11 +364,11 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
core.settings:set("enable_dynamic_shadows", "false")
else
local shadow_presets = {
- [2] = { 80, 512, "true", 0, "false" },
- [3] = { 120, 1024, "true", 1, "false" },
- [4] = { 350, 2048, "true", 1, "false" },
- [5] = { 350, 2048, "true", 2, "true" },
- [6] = { 450, 4096, "true", 2, "true" },
+ [2] = { 55, 512, "true", 0, "false" },
+ [3] = { 82, 1024, "true", 1, "false" },
+ [4] = { 240, 2048, "true", 1, "false" },
+ [5] = { 240, 2048, "true", 2, "true" },
+ [6] = { 300, 4096, "true", 2, "true" },
}
local s = shadow_presets[table.indexof(labels.shadow_levels, fields["dd_shadows"])]
if s then
diff --git a/builtin/mainmenu/tests/serverlistmgr_spec.lua b/builtin/mainmenu/tests/serverlistmgr_spec.lua
index a091959fb..ab7a6c60c 100644
--- a/builtin/mainmenu/tests/serverlistmgr_spec.lua
+++ b/builtin/mainmenu/tests/serverlistmgr_spec.lua
@@ -1,4 +1,5 @@
_G.core = {}
+_G.vector = {metatable = {}}
_G.unpack = table.unpack
_G.serverlistmgr = {}