mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-31 18:31:04 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
b5aab1bcc7
1196 changed files with 57421 additions and 35855 deletions
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/client/chatcommands.lua
|
||||
|
||||
core.register_on_sending_chat_message(function(message)
|
||||
if message:sub(1,2) == ".." then
|
||||
return false
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
-- Minetest: builtin/client/init.lua
|
||||
local scriptpath = core.get_builtin_path()
|
||||
local clientpath = scriptpath.."client"..DIR_DELIM
|
||||
local commonpath = scriptpath.."common"..DIR_DELIM
|
||||
|
|
|
@ -155,7 +155,7 @@ end
|
|||
|
||||
function core.after(after, func, ...)
|
||||
assert(tonumber(after) and not core.is_nan(after) and type(func) == "function",
|
||||
"Invalid minetest.after invocation")
|
||||
"Invalid core.after invocation")
|
||||
|
||||
local new_job = {
|
||||
mod_origin = core.get_last_run_mod(),
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/common/chatcommands.lua
|
||||
|
||||
-- For server-side translations (if INIT == "game")
|
||||
-- Otherwise, use core.gettext
|
||||
local S = core.get_translator("__builtin")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
-- Minetest: builtin/item_s.lua
|
||||
-- The distinction of what goes here is a bit tricky, basically it's everything
|
||||
-- that does not (directly or indirectly) need access to ServerEnvironment,
|
||||
-- Server or writable access to IGameDef on the engine side.
|
||||
|
@ -166,20 +165,19 @@ function core.is_colored_paramtype(ptype)
|
|||
end
|
||||
|
||||
function core.strip_param2_color(param2, paramtype2)
|
||||
if not core.is_colored_paramtype(paramtype2) then
|
||||
if paramtype2 == "color" then
|
||||
return param2
|
||||
elseif paramtype2 == "colorfacedir" then
|
||||
return math.floor(param2 / 32) * 32
|
||||
elseif paramtype2 == "color4dir" then
|
||||
return math.floor(param2 / 4) * 4
|
||||
elseif paramtype2 == "colorwallmounted" then
|
||||
return math.floor(param2 / 8) * 8
|
||||
elseif paramtype2 == "colordegrotate" then
|
||||
return math.floor(param2 / 32) * 32
|
||||
else
|
||||
return nil
|
||||
end
|
||||
if paramtype2 == "colorfacedir" then
|
||||
param2 = math.floor(param2 / 32) * 32
|
||||
elseif paramtype2 == "color4dir" then
|
||||
param2 = math.floor(param2 / 4) * 4
|
||||
elseif paramtype2 == "colorwallmounted" then
|
||||
param2 = math.floor(param2 / 8) * 8
|
||||
elseif paramtype2 == "colordegrotate" then
|
||||
param2 = math.floor(param2 / 32) * 32
|
||||
end
|
||||
-- paramtype2 == "color" requires no modification.
|
||||
return param2
|
||||
end
|
||||
|
||||
-- Content ID caching
|
||||
|
|
|
@ -11,8 +11,8 @@ end
|
|||
core.known_metatables = known_metatables
|
||||
|
||||
function core.register_async_metatable(...)
|
||||
core.log("deprecated", "minetest.register_async_metatable is deprecated. " ..
|
||||
"Use minetest.register_portable_metatable instead.")
|
||||
core.log("deprecated", "core.register_async_metatable is deprecated. " ..
|
||||
"Use core.register_portable_metatable instead.")
|
||||
return core.register_portable_metatable(...)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/misc_helpers.lua
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Localize functions to avoid table lookups (better performance).
|
||||
local string_sub, string_find = string.sub, string.find
|
||||
|
@ -235,6 +233,16 @@ function core.formspec_escape(text)
|
|||
end
|
||||
|
||||
|
||||
local hypertext_escapes = {
|
||||
["\\"] = "\\\\",
|
||||
["<"] = "\\<",
|
||||
[">"] = "\\>",
|
||||
}
|
||||
function core.hypertext_escape(text)
|
||||
return text and text:gsub("[\\<>]", hypertext_escapes)
|
||||
end
|
||||
|
||||
|
||||
function core.wrap_text(text, max_length, as_table)
|
||||
local result = {}
|
||||
local line = {}
|
||||
|
@ -564,12 +572,14 @@ function core.strip_colors(str)
|
|||
return (str:gsub(ESCAPE_CHAR .. "%([bc]@[^)]+%)", ""))
|
||||
end
|
||||
|
||||
function core.translate(textdomain, str, ...)
|
||||
local function translate(textdomain, str, num, ...)
|
||||
local start_seq
|
||||
if textdomain == "" then
|
||||
if textdomain == "" and num == "" then
|
||||
start_seq = ESCAPE_CHAR .. "T"
|
||||
else
|
||||
elseif num == "" then
|
||||
start_seq = ESCAPE_CHAR .. "(T@" .. textdomain .. ")"
|
||||
else
|
||||
start_seq = ESCAPE_CHAR .. "(T@" .. textdomain .. "@" .. num .. ")"
|
||||
end
|
||||
local arg = {n=select('#', ...), ...}
|
||||
local end_seq = ESCAPE_CHAR .. "E"
|
||||
|
@ -600,8 +610,31 @@ function core.translate(textdomain, str, ...)
|
|||
return start_seq .. translated .. end_seq
|
||||
end
|
||||
|
||||
function core.translate(textdomain, str, ...)
|
||||
return translate(textdomain, str, "", ...)
|
||||
end
|
||||
|
||||
function core.translate_n(textdomain, str, str_plural, n, ...)
|
||||
assert (type(n) == "number")
|
||||
assert (n >= 0)
|
||||
assert (math.floor(n) == n)
|
||||
|
||||
-- Truncate n if too large
|
||||
local max = 1000000
|
||||
if n >= 2 * max then
|
||||
n = n % max + max
|
||||
end
|
||||
if n == 1 then
|
||||
return translate(textdomain, str, "1", ...)
|
||||
else
|
||||
return translate(textdomain, str_plural, tostring(n), ...)
|
||||
end
|
||||
end
|
||||
|
||||
function core.get_translator(textdomain)
|
||||
return function(str, ...) return core.translate(textdomain or "", str, ...) end
|
||||
return
|
||||
(function(str, ...) return core.translate(textdomain or "", str, ...) end),
|
||||
(function(str, str_plural, n, ...) return core.translate_n(textdomain or "", str, str_plural, n, ...) end)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
|
|
@ -204,18 +204,18 @@ local function dummy_func() end
|
|||
function core.deserialize(str, safe)
|
||||
-- Backwards compatibility
|
||||
if str == nil then
|
||||
core.log("deprecated", "minetest.deserialize called with nil (expected string).")
|
||||
core.log("deprecated", "core.deserialize called with nil (expected string).")
|
||||
return nil, "Invalid type: Expected a string, got nil"
|
||||
end
|
||||
local t = type(str)
|
||||
if t ~= "string" then
|
||||
error(("minetest.deserialize called with %s (expected string)."):format(t))
|
||||
error(("core.deserialize called with %s (expected string)."):format(t))
|
||||
end
|
||||
|
||||
local func, err = loadstring(str)
|
||||
if not func then return nil, err end
|
||||
|
||||
-- math.huge was serialized to inf and NaNs to nan by Lua in Minetest 5.6, so we have to support this here
|
||||
-- math.huge was serialized to inf and NaNs to nan by Lua in engine version 5.6, so we have to support this here
|
||||
local env = {inf = math_huge, nan = 0/0}
|
||||
if safe then
|
||||
env.loadstring = dummy_func
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--Copyright (C) 2023 Gregor Parzefall
|
||||
--
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -66,13 +66,13 @@ local function get_formspec(self)
|
|||
|
||||
local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize)
|
||||
|
||||
local ENABLE_TOUCH = core.settings:get_bool("enable_touch")
|
||||
local TOUCH_GUI = core.settings:get_bool("touch_gui")
|
||||
|
||||
local orig_tsize = tab.tabsize or { width = self.width, height = self.height }
|
||||
local tsize = { width = orig_tsize.width, height = orig_tsize.height }
|
||||
tsize.height = tsize.height
|
||||
+ TABHEADER_H -- tabheader included in formspec size
|
||||
+ (ENABLE_TOUCH and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP)
|
||||
+ (TOUCH_GUI and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP)
|
||||
+ GAMEBAR_H -- gamebar included in formspec size
|
||||
|
||||
if self.parent == nil and not prepend then
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -10,7 +10,7 @@ end
|
|||
|
||||
function core.handle_async(func, callback, ...)
|
||||
assert(type(func) == "function" and type(callback) == "function",
|
||||
"Invalid minetest.handle_async invocation")
|
||||
"Invalid core.handle_async invocation")
|
||||
local args = {n = select("#", ...), ...}
|
||||
local mod_origin = core.get_last_run_mod()
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/auth.lua
|
||||
|
||||
--
|
||||
-- Builtin authentication handler
|
||||
--
|
||||
|
@ -95,11 +93,11 @@ core.builtin_auth_handler = {
|
|||
for priv, value in pairs(privileges) do
|
||||
-- Warnings for improper API usage
|
||||
if value == false then
|
||||
core.log('deprecated', "`false` value given to `minetest.set_player_privs`, "..
|
||||
core.log('deprecated', "`false` value given to `core.set_player_privs`, "..
|
||||
"this is almost certainly a bug, "..
|
||||
"granting a privilege rather than revoking it")
|
||||
elseif value ~= true then
|
||||
core.log('deprecated', "non-`true` value given to `minetest.set_player_privs`")
|
||||
core.log('deprecated', "non-`true` value given to `core.set_player_privs`")
|
||||
end
|
||||
-- Run grant callbacks
|
||||
if prev_privs[priv] == nil then
|
||||
|
@ -196,7 +194,7 @@ function core.change_player_privs(name, changes)
|
|||
elseif change == false then
|
||||
privs[priv] = nil
|
||||
else
|
||||
error("non-bool value given to `minetest.change_player_privs`")
|
||||
error("non-bool value given to `core.change_player_privs`")
|
||||
end
|
||||
end
|
||||
core.set_player_privs(name, privs)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/game/chat.lua
|
||||
|
||||
local S = core.get_translator("__builtin")
|
||||
|
||||
-- Helper function that implements search and replace without pattern matching
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/constants.lua
|
||||
|
||||
--
|
||||
-- Constants values for use with the Lua API
|
||||
--
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/deprecated.lua
|
||||
|
||||
--
|
||||
-- EnvRef
|
||||
--
|
||||
|
@ -35,9 +33,9 @@ local settings = core.settings
|
|||
|
||||
local function setting_proxy(name)
|
||||
return function(...)
|
||||
core.log("deprecated", "WARNING: minetest.setting_* "..
|
||||
core.log("deprecated", "WARNING: core.setting_* "..
|
||||
"functions are deprecated. "..
|
||||
"Use methods on the minetest.settings object.")
|
||||
"Use methods on the core.settings object.")
|
||||
return settings[name](settings, ...)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/detached_inventory.lua
|
||||
|
||||
core.detached_inventories = {}
|
||||
|
||||
local create_detached_inventory_raw = core.create_detached_inventory_raw
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/item.lua
|
||||
|
||||
local builtin_shared = ...
|
||||
local SCALE = 0.667
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/features.lua
|
||||
|
||||
core.features = {
|
||||
glasslike_framed = true,
|
||||
nodebox_as_selectionbox = true,
|
||||
|
@ -45,6 +43,8 @@ core.features = {
|
|||
hotbar_hud_element = true,
|
||||
bulk_lbms = true,
|
||||
abm_without_neighbors = true,
|
||||
biome_weights = true,
|
||||
particle_blend_clip = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/item.lua
|
||||
|
||||
local builtin_shared = ...
|
||||
|
||||
local function copy_pointed_thing(pointed_thing)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/item_entity.lua
|
||||
|
||||
function core.spawn_item(pos, item)
|
||||
-- Take item in any format
|
||||
local stack = ItemStack(item)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/misc.lua
|
||||
|
||||
local S = core.get_translator("__builtin")
|
||||
|
||||
--
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
-- Minetest: builtin/misc_s.lua
|
||||
-- The distinction of what goes here is a bit tricky, basically it's everything
|
||||
-- that does not (directly or indirectly) need access to ServerEnvironment,
|
||||
-- Server or writable access to IGameDef on the engine side.
|
||||
|
@ -25,11 +24,8 @@ end
|
|||
|
||||
|
||||
function core.get_item_group(name, group)
|
||||
if not core.registered_items[name] or not
|
||||
core.registered_items[name].groups[group] then
|
||||
return 0
|
||||
end
|
||||
return core.registered_items[name].groups[group]
|
||||
local def = core.registered_items[name]
|
||||
return def and def.groups[group] or 0
|
||||
end
|
||||
|
||||
|
||||
|
@ -40,11 +36,7 @@ end
|
|||
|
||||
|
||||
function core.setting_get_pos(name)
|
||||
local value = core.settings:get(name)
|
||||
if not value then
|
||||
return nil
|
||||
end
|
||||
return core.string_to_pos(value)
|
||||
return core.settings:get_pos(name)
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/privileges.lua
|
||||
|
||||
local S = core.get_translator("__builtin")
|
||||
|
||||
--
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
-- Minetest: builtin/register.lua
|
||||
|
||||
local builtin_shared = ...
|
||||
local S = core.get_translator("__builtin")
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
-- Minetest: builtin/static_spawn.lua
|
||||
|
||||
local static_spawnpoint_string = core.settings:get("static_spawnpoint")
|
||||
if static_spawnpoint_string and
|
||||
static_spawnpoint_string ~= "" and
|
||||
not core.setting_get_pos("static_spawnpoint") then
|
||||
not core.settings:get_pos("static_spawnpoint") then
|
||||
error('The static_spawnpoint setting is invalid: "' ..
|
||||
static_spawnpoint_string .. '"')
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ end
|
|||
local log = function(...) end
|
||||
--local log = print
|
||||
|
||||
minetest.register_allow_player_inventory_action(function(_, action, inv, info)
|
||||
core.register_allow_player_inventory_action(function(_, action, inv, info)
|
||||
log("\tallow " .. action, info.count or info.stack:to_string())
|
||||
|
||||
if action == "move" then
|
||||
|
@ -69,7 +69,7 @@ minetest.register_allow_player_inventory_action(function(_, action, inv, info)
|
|||
return -- Unlimited
|
||||
end)
|
||||
|
||||
minetest.register_on_player_inventory_action(function(_, action, inv, info)
|
||||
core.register_on_player_inventory_action(function(_, action, inv, info)
|
||||
log("\ton " .. action, info.count or info.stack:to_string())
|
||||
|
||||
if action == "take" or action == "put" then
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--
|
||||
-- This file contains built-in stuff in Minetest implemented in Lua.
|
||||
-- This file contains built-in stuff in Luanti implemented in Lua.
|
||||
--
|
||||
-- It is always loaded and executed after registration of the C API,
|
||||
-- before loading and running any mods.
|
||||
|
|
|
@ -11,11 +11,6 @@ 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)
|
||||
|
||||
|
@ -23,7 +18,7 @@ function core.handle_async(func, parameter, callback)
|
|||
return false
|
||||
end
|
||||
|
||||
local jobid = core.do_async_callback(serialized_func, serialized_param)
|
||||
local jobid = core.do_async_callback(func, serialized_param)
|
||||
|
||||
core.async_jobs[jobid] = callback
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2018-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -182,6 +182,23 @@ function contentdb.get_package_by_id(id)
|
|||
end
|
||||
|
||||
|
||||
function contentdb.calculate_package_id(type, author, name)
|
||||
local id = author:lower() .. "/"
|
||||
if (type == nil or type == "game") and #name > 5 and name:sub(#name - 4) == "_game" then
|
||||
id = id .. name:sub(1, #name - 5)
|
||||
else
|
||||
id = id .. name
|
||||
end
|
||||
return id
|
||||
end
|
||||
|
||||
|
||||
function contentdb.get_package_by_info(author, name)
|
||||
local id = contentdb.calculate_package_id(nil, author, name)
|
||||
return contentdb.package_by_id[id]
|
||||
end
|
||||
|
||||
|
||||
-- Create a coroutine from `fn` and provide results to `callback` when complete (dead).
|
||||
-- Returns a resumer function.
|
||||
local function make_callback_coroutine(fn, callback)
|
||||
|
@ -375,7 +392,7 @@ function contentdb.resolve_dependencies(package, game, callback)
|
|||
end
|
||||
|
||||
|
||||
local function fetch_pkgs(params)
|
||||
local function fetch_pkgs()
|
||||
local version = core.get_version()
|
||||
local base_url = core.settings:get("contentdb_url")
|
||||
local url = base_url ..
|
||||
|
@ -412,49 +429,43 @@ local function fetch_pkgs(params)
|
|||
if not packages or #packages == 0 then
|
||||
return
|
||||
end
|
||||
local aliases = {}
|
||||
return packages
|
||||
end
|
||||
|
||||
|
||||
function contentdb.set_packages_from_api(packages)
|
||||
contentdb.package_by_id = {}
|
||||
contentdb.aliases = {}
|
||||
|
||||
for _, package in pairs(packages) do
|
||||
local name_len = #package.name
|
||||
-- This must match what contentdb.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.id .. package.name:sub(1, name_len - 5)
|
||||
else
|
||||
package.id = package.id .. package.name
|
||||
end
|
||||
|
||||
package.id = contentdb.calculate_package_id(package.type, package.author, package.name)
|
||||
package.url_part = core.urlencode(package.author) .. "/" .. core.urlencode(package.name)
|
||||
|
||||
contentdb.package_by_id[package.id] = package
|
||||
|
||||
if package.aliases then
|
||||
for _, alias in ipairs(package.aliases) do
|
||||
-- We currently don't support name changing
|
||||
local suffix = "/" .. package.name
|
||||
if alias:sub(-#suffix) == suffix then
|
||||
aliases[alias:lower()] = package.id
|
||||
contentdb.aliases[alias:lower()] = package.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return { packages = packages, aliases = aliases }
|
||||
contentdb.load_ok = true
|
||||
contentdb.load_error = false
|
||||
contentdb.packages = packages
|
||||
contentdb.packages_full = packages
|
||||
contentdb.packages_full_unordered = packages
|
||||
end
|
||||
|
||||
|
||||
function contentdb.fetch_pkgs(callback)
|
||||
contentdb.loading = true
|
||||
core.handle_async(fetch_pkgs, nil, function(result)
|
||||
if result then
|
||||
contentdb.load_ok = true
|
||||
contentdb.load_error = false
|
||||
contentdb.packages = result.packages
|
||||
contentdb.packages_full = result.packages
|
||||
contentdb.packages_full_unordered = result.packages
|
||||
contentdb.aliases = result.aliases
|
||||
|
||||
for _, package in ipairs(result.packages) do
|
||||
contentdb.package_by_id[package.id] = package
|
||||
end
|
||||
contentdb.set_packages_from_api(result)
|
||||
else
|
||||
contentdb.load_error = true
|
||||
end
|
||||
|
@ -554,30 +565,107 @@ function contentdb.filter_packages(query, by_type)
|
|||
end
|
||||
|
||||
local keywords = {}
|
||||
for word in query:lower():gmatch("%S+") do
|
||||
table.insert(keywords, word)
|
||||
for word in query:gmatch("%S+") do
|
||||
table.insert(keywords, word:lower())
|
||||
end
|
||||
|
||||
local function contains_all_keywords(str)
|
||||
str = str:lower()
|
||||
for _, keyword in ipairs(keywords) do
|
||||
if not str:find(keyword, 1, true) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function matches_keywords(package)
|
||||
for k = 1, #keywords do
|
||||
local keyword = keywords[k]
|
||||
|
||||
if string.find(package.name:lower(), keyword, 1, true) or
|
||||
string.find(package.title:lower(), keyword, 1, true) or
|
||||
string.find(package.author:lower(), keyword, 1, true) or
|
||||
string.find(package.short_description:lower(), keyword, 1, true) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
return contains_all_keywords(package.name) or
|
||||
contains_all_keywords(package.title) or
|
||||
contains_all_keywords(package.author) or
|
||||
contains_all_keywords(package.short_description)
|
||||
end
|
||||
|
||||
contentdb.packages = {}
|
||||
for _, package in pairs(contentdb.packages_full) do
|
||||
if (query == "" or matches_keywords(package)) and
|
||||
(by_type == nil or package.type == by_type) then
|
||||
contentdb.packages[#contentdb.packages + 1] = package
|
||||
table.insert(contentdb.packages, package)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function contentdb.get_full_package_info(package, callback)
|
||||
assert(package)
|
||||
if package.full_info then
|
||||
callback(package.full_info)
|
||||
return
|
||||
end
|
||||
|
||||
local function fetch(params)
|
||||
local version = core.get_version()
|
||||
local base_url = core.settings:get("contentdb_url")
|
||||
|
||||
local languages
|
||||
local current_language = core.get_language()
|
||||
if current_language ~= "" then
|
||||
languages = { current_language, "en;q=0.8" }
|
||||
else
|
||||
languages = { "en" }
|
||||
end
|
||||
|
||||
local url = base_url ..
|
||||
"/api/packages/" .. params.package.url_part .. "/for-client/?" ..
|
||||
"protocol_version=" .. core.urlencode(core.get_max_supp_proto()) ..
|
||||
"&engine_version=" .. core.urlencode(version.string) ..
|
||||
"&formspec_version=" .. core.urlencode(core.get_formspec_version()) ..
|
||||
"&include_images=false"
|
||||
local http = core.get_http_api()
|
||||
local response = http.fetch_sync({
|
||||
url = url,
|
||||
extra_headers = {
|
||||
"Accept-Language: " .. table.concat(languages, ", ")
|
||||
},
|
||||
})
|
||||
if not response.succeeded then
|
||||
return nil
|
||||
end
|
||||
|
||||
return core.parse_json(response.data)
|
||||
end
|
||||
|
||||
local function my_callback(value)
|
||||
package.full_info = value
|
||||
callback(value)
|
||||
end
|
||||
|
||||
if not core.handle_async(fetch, { package = package }, my_callback) then
|
||||
core.log("error", "ERROR: async event failed")
|
||||
callback(nil)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function contentdb.get_formspec_padding()
|
||||
-- Padding is increased on Android to account for notches
|
||||
-- TODO: use Android API to determine size of cut outs
|
||||
return { x = PLATFORM == "Android" and 1 or 0.5, y = PLATFORM == "Android" and 0.25 or 0.5 }
|
||||
end
|
||||
|
||||
|
||||
function contentdb.get_formspec_size()
|
||||
local window = core.get_window_info()
|
||||
local size = { x = window.max_formspec_size.x, y = window.max_formspec_size.y }
|
||||
|
||||
-- Minimum formspec size
|
||||
local min_x = 15.5
|
||||
local min_y = 10
|
||||
if size.x < min_x or size.y < min_y then
|
||||
local scale = math.max(min_x / size.x, min_y / size.y)
|
||||
size.x = size.x * scale
|
||||
size.y = size.y * scale
|
||||
end
|
||||
|
||||
return size
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2018-20 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -18,7 +18,7 @@
|
|||
if not core.get_http_api then
|
||||
function create_contentdb_dlg()
|
||||
return messagebox("contentdb",
|
||||
fgettext("ContentDB is not available when Minetest was compiled without cURL"))
|
||||
fgettext("ContentDB is not available when Luanti was compiled without cURL"))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
@ -26,68 +26,20 @@ end
|
|||
-- Filter
|
||||
local search_string = ""
|
||||
local cur_page = 1
|
||||
local num_per_page = 5
|
||||
local filter_type = 1
|
||||
local filter_types_titles = {
|
||||
fgettext("All packages"),
|
||||
fgettext("Games"),
|
||||
fgettext("Mods"),
|
||||
fgettext("Texture packs"),
|
||||
}
|
||||
local filter_type
|
||||
|
||||
-- Automatic package installation
|
||||
local auto_install_spec = nil
|
||||
|
||||
local filter_types_type = {
|
||||
nil,
|
||||
"game",
|
||||
"mod",
|
||||
"txp",
|
||||
|
||||
local filter_type_names = {
|
||||
{ "type_all", nil },
|
||||
{ "type_game", "game" },
|
||||
{ "type_mod", "mod" },
|
||||
{ "type_txp", "txp" },
|
||||
}
|
||||
|
||||
|
||||
local function install_or_update_package(this, package)
|
||||
local install_parent
|
||||
if package.type == "mod" then
|
||||
install_parent = core.get_modpath()
|
||||
elseif package.type == "game" then
|
||||
install_parent = core.get_gamepath()
|
||||
elseif package.type == "txp" then
|
||||
install_parent = core.get_texturepath()
|
||||
else
|
||||
error("Unknown package type: " .. package.type)
|
||||
end
|
||||
|
||||
if package.queued or package.downloading then
|
||||
return
|
||||
end
|
||||
|
||||
local function on_confirm()
|
||||
local dlg = create_install_dialog(package)
|
||||
dlg:set_parent(this)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
|
||||
dlg:load_deps()
|
||||
end
|
||||
|
||||
if package.type == "mod" and #pkgmgr.games == 0 then
|
||||
local dlg = messagebox("install_game",
|
||||
fgettext("You need to install a game before you can install a mod"))
|
||||
dlg:set_parent(this)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
elseif not package.path and core.is_dir(install_parent .. DIR_DELIM .. package.name) then
|
||||
local dlg = create_confirm_overwrite(package, on_confirm)
|
||||
dlg:set_parent(this)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
else
|
||||
on_confirm()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Resolves the package specification stored in auto_install_spec into an actual package.
|
||||
-- May only be called after the package list has been loaded successfully.
|
||||
local function resolve_auto_install_spec()
|
||||
|
@ -145,7 +97,7 @@ end
|
|||
local function sort_and_filter_pkgs()
|
||||
contentdb.update_paths()
|
||||
contentdb.sort_packages()
|
||||
contentdb.filter_packages(search_string, filter_types_type[filter_type])
|
||||
contentdb.filter_packages(search_string, filter_type)
|
||||
|
||||
local auto_install_pkg = resolve_auto_install_spec()
|
||||
if auto_install_pkg then
|
||||
|
@ -176,72 +128,151 @@ local function load()
|
|||
end
|
||||
|
||||
|
||||
local function get_info_formspec(text)
|
||||
local H = 9.5
|
||||
local function get_info_formspec(size, padding, text)
|
||||
return table.concat({
|
||||
"formspec_version[6]",
|
||||
"size[15.75,9.5]",
|
||||
core.settings:get_bool("touch_gui") and "padding[0.01,0.01]" or "position[0.5,0.55]",
|
||||
"size[", size.x, ",", size.y, "]",
|
||||
"padding[0,0]",
|
||||
"bgcolor[;true]",
|
||||
|
||||
"label[4,4.35;", text, "]",
|
||||
"container[0,", H - 0.8 - 0.375, "]",
|
||||
"button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]",
|
||||
"label[", padding.x + 3.625, ",4.35;", text, "]",
|
||||
"container[", padding.x, ",", size.y - 0.8 - padding.y, "]",
|
||||
"button[0,0;2,0.8;back;", fgettext("Back"), "]",
|
||||
"container_end[]",
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
-- Determines how to fit `num_per_page` into `size` space
|
||||
local function fit_cells(num_per_page, size)
|
||||
local cell_spacing = 0.5
|
||||
local columns = 1
|
||||
local cell_w, cell_h
|
||||
-- Fit cells into the available height
|
||||
while true do
|
||||
cell_w = (size.x - (columns-1)*cell_spacing) / columns
|
||||
cell_h = cell_w / 4
|
||||
|
||||
local required_height = math.ceil(num_per_page / columns) * (cell_h + cell_spacing) - cell_spacing
|
||||
-- Add 0.1 to be more lenient
|
||||
if required_height <= size.y + 0.1 then
|
||||
break
|
||||
end
|
||||
|
||||
columns = columns + 1
|
||||
end
|
||||
|
||||
return cell_spacing, columns, cell_w, cell_h
|
||||
end
|
||||
|
||||
|
||||
local function calculate_num_per_page()
|
||||
local size = contentdb.get_formspec_size()
|
||||
local padding = contentdb.get_formspec_padding()
|
||||
local window = core.get_window_info()
|
||||
|
||||
size.x = size.x - padding.x * 2
|
||||
size.y = size.y - padding.y * 2 - 1.425 - 0.25 - 0.8
|
||||
|
||||
local coordToPx = window.size.x / window.max_formspec_size.x / window.real_gui_scaling
|
||||
|
||||
local num_per_page = 12
|
||||
while num_per_page > 2 do
|
||||
local _, _, cell_w, _ = fit_cells(num_per_page, size)
|
||||
if cell_w * coordToPx > 350 then
|
||||
break
|
||||
end
|
||||
|
||||
num_per_page = num_per_page - 1
|
||||
end
|
||||
return num_per_page
|
||||
end
|
||||
|
||||
|
||||
local function get_formspec(dlgdata)
|
||||
local window_padding = contentdb.get_formspec_padding()
|
||||
local size = contentdb.get_formspec_size()
|
||||
|
||||
if contentdb.loading then
|
||||
return get_info_formspec(fgettext("Loading..."))
|
||||
return get_info_formspec(size, window_padding, fgettext("Loading..."))
|
||||
end
|
||||
if contentdb.load_error then
|
||||
return get_info_formspec(fgettext("No packages could be retrieved"))
|
||||
return get_info_formspec(size, window_padding, fgettext("No packages could be retrieved"))
|
||||
end
|
||||
assert(contentdb.load_ok)
|
||||
|
||||
contentdb.update_paths()
|
||||
|
||||
local num_per_page = dlgdata.num_per_page
|
||||
dlgdata.pagemax = math.max(math.ceil(#contentdb.packages / num_per_page), 1)
|
||||
if cur_page > dlgdata.pagemax then
|
||||
cur_page = 1
|
||||
end
|
||||
|
||||
local W = 15.75
|
||||
local H = 9.5
|
||||
local W = size.x - window_padding.x * 2
|
||||
local H = size.y - window_padding.y * 2
|
||||
|
||||
local category_x = 0
|
||||
local number_category_buttons = 4
|
||||
local max_button_w = (W - 0.375 - 0.25 - 7) / number_category_buttons
|
||||
local category_button_w = math.min(max_button_w, 3)
|
||||
local function make_category_button(name, label, selected)
|
||||
category_x = category_x + 1
|
||||
local color = selected and mt_color_green or ""
|
||||
return ("style[%s;bgcolor=%s]button[%f,0;%f,0.8;%s;%s]"):format(name, color,
|
||||
(category_x - 1) * category_button_w, category_button_w, name, label)
|
||||
end
|
||||
|
||||
|
||||
local selected_type = filter_type
|
||||
|
||||
local search_box_width = W - 0.375 - 0.25 - 2*0.8
|
||||
- number_category_buttons * category_button_w
|
||||
local formspec = {
|
||||
"formspec_version[6]",
|
||||
"size[15.75,9.5]",
|
||||
core.settings:get_bool("touch_gui") and "padding[0.01,0.01]" or "position[0.5,0.55]",
|
||||
"formspec_version[7]",
|
||||
"size[", size.x, ",", size.y, "]",
|
||||
"padding[0,0]",
|
||||
"bgcolor[;true]",
|
||||
|
||||
"style[status,downloading,queued;border=false]",
|
||||
"container[", window_padding.x, ",", window_padding.y, "]",
|
||||
|
||||
"container[0.375,0.375]",
|
||||
"field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]",
|
||||
-- Top-left: categories
|
||||
make_category_button("type_all", fgettext("All"), selected_type == nil),
|
||||
make_category_button("type_game", fgettext("Games"), selected_type == "game"),
|
||||
make_category_button("type_mod", fgettext("Mods"), selected_type == "mod"),
|
||||
make_category_button("type_txp", fgettext("Texture Packs"), selected_type == "txp"),
|
||||
|
||||
-- Top-right: Search
|
||||
"container[", W - search_box_width - 0.8*2, ",0]",
|
||||
"field[0,0;", search_box_width, ",0.8;search_string;;", core.formspec_escape(search_string), "]",
|
||||
"field_enter_after_edit[search_string;true]",
|
||||
"image_button[7.3,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
|
||||
"image_button[8.125,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]",
|
||||
"dropdown[9.175,0;2.7875,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]",
|
||||
"image_button[", search_box_width, ",0;0.8,0.8;",
|
||||
core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
|
||||
"image_button[", search_box_width + 0.8, ",0;0.8,0.8;",
|
||||
core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]",
|
||||
"container_end[]",
|
||||
|
||||
-- Page nav buttons
|
||||
"container[0,", H - 0.8 - 0.375, "]",
|
||||
"button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]",
|
||||
-- Bottom strip start
|
||||
"container[0,", H - 0.8, "]",
|
||||
"button[0,0;2,0.8;back;", fgettext("Back"), "]",
|
||||
|
||||
"container[", W - 0.375 - 0.8*4 - 2, ",0]",
|
||||
"image_button[0,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "start_icon.png;pstart;]",
|
||||
"image_button[0.8,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "prev_icon.png;pback;]",
|
||||
-- Bottom-center: Page nav buttons
|
||||
"container[", (W - 1*4 - 2) / 2, ",0]",
|
||||
"image_button[0,0;1,0.8;", core.formspec_escape(defaulttexturedir), "start_icon.png;pstart;]",
|
||||
"image_button[1,0;1,0.8;", core.formspec_escape(defaulttexturedir), "prev_icon.png;pback;]",
|
||||
"style[pagenum;border=false]",
|
||||
"button[1.6,0;2,0.8;pagenum;", tonumber(cur_page), " / ", tonumber(dlgdata.pagemax), "]",
|
||||
"image_button[3.6,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "next_icon.png;pnext;]",
|
||||
"image_button[4.4,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "end_icon.png;pend;]",
|
||||
"container_end[]",
|
||||
"button[2,0;2,0.8;pagenum;", tonumber(cur_page), " / ", tonumber(dlgdata.pagemax), "]",
|
||||
"image_button[4,0;1,0.8;", core.formspec_escape(defaulttexturedir), "next_icon.png;pnext;]",
|
||||
"image_button[5,0;1,0.8;", core.formspec_escape(defaulttexturedir), "end_icon.png;pend;]",
|
||||
"container_end[]", -- page nav end
|
||||
|
||||
"container_end[]",
|
||||
-- Bottom-right: updating
|
||||
"container[", W - 3, ",0]",
|
||||
"style[status,downloading,queued;border=false]",
|
||||
}
|
||||
|
||||
if contentdb.number_downloading > 0 then
|
||||
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;downloading;"
|
||||
formspec[#formspec + 1] = "button[0,0;3,0.8;downloading;"
|
||||
if #contentdb.download_queue > 0 then
|
||||
formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued",
|
||||
contentdb.number_downloading, #contentdb.download_queue)
|
||||
|
@ -260,16 +291,19 @@ local function get_formspec(dlgdata)
|
|||
end
|
||||
|
||||
if num_avail_updates == 0 then
|
||||
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;status;"
|
||||
formspec[#formspec + 1] = "button[0,0;3,0.8;status;"
|
||||
formspec[#formspec + 1] = fgettext("No updates")
|
||||
formspec[#formspec + 1] = "]"
|
||||
else
|
||||
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;update_all;"
|
||||
formspec[#formspec + 1] = "button[0,0;3,0.8;update_all;"
|
||||
formspec[#formspec + 1] = fgettext("Update All [$1]", num_avail_updates)
|
||||
formspec[#formspec + 1] = "]"
|
||||
end
|
||||
end
|
||||
|
||||
formspec[#formspec + 1] = "container_end[]" -- updating end
|
||||
formspec[#formspec + 1] = "container_end[]" -- bottom strip end
|
||||
|
||||
if #contentdb.packages == 0 then
|
||||
formspec[#formspec + 1] = "label[4,4.75;"
|
||||
formspec[#formspec + 1] = fgettext("No results")
|
||||
|
@ -281,81 +315,86 @@ local function get_formspec(dlgdata)
|
|||
formspec[#formspec + 1] = "tooltip[downloading;" .. fgettext("Downloading...") .. tooltip_colors
|
||||
formspec[#formspec + 1] = "tooltip[queued;" .. fgettext("Queued") .. tooltip_colors
|
||||
|
||||
formspec[#formspec + 1] = "container[0,1.425]"
|
||||
|
||||
local cell_spacing, columns, cell_w, cell_h = fit_cells(num_per_page, {
|
||||
x = W,
|
||||
y = H - 1.425 - 0.25 - 0.8
|
||||
})
|
||||
local img_w = cell_h * 3 / 2
|
||||
|
||||
local start_idx = (cur_page - 1) * num_per_page + 1
|
||||
for i=start_idx, math.min(#contentdb.packages, start_idx+num_per_page-1) do
|
||||
local package = contentdb.packages[i]
|
||||
local container_y = (i - start_idx) * 1.375 + (2*0.375 + 0.8)
|
||||
formspec[#formspec + 1] = "container[0.375,"
|
||||
formspec[#formspec + 1] = container_y
|
||||
formspec[#formspec + 1] = "]"
|
||||
|
||||
-- image
|
||||
formspec[#formspec + 1] = "image[0,0;1.5,1;"
|
||||
formspec[#formspec + 1] = core.formspec_escape(get_screenshot(package))
|
||||
formspec[#formspec + 1] = "]"
|
||||
table.insert_all(formspec, {
|
||||
"container[",
|
||||
(cell_w + cell_spacing) * ((i - start_idx) % columns),
|
||||
",",
|
||||
(cell_h + cell_spacing) * math.floor((i - start_idx) / columns),
|
||||
"]",
|
||||
|
||||
-- title
|
||||
formspec[#formspec + 1] = "label[1.875,0.1;"
|
||||
formspec[#formspec + 1] = core.formspec_escape(
|
||||
core.colorize(mt_color_green, package.title) ..
|
||||
core.colorize("#BFBFBF", " by " .. package.author))
|
||||
formspec[#formspec + 1] = "]"
|
||||
"box[0,0;", cell_w, ",", cell_h, ";#ffffff11]",
|
||||
|
||||
-- buttons
|
||||
local description_width = W - 2.625 - 2 * 0.7 - 2 * 0.15
|
||||
-- image,
|
||||
"image[0,0;", img_w, ",", cell_h, ";",
|
||||
core.formspec_escape(get_screenshot(package, package.thumbnail, 2)), "]",
|
||||
|
||||
local second_base = "image_button[-1.55,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir)
|
||||
local third_base = "image_button[-2.4,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir)
|
||||
formspec[#formspec + 1] = "container["
|
||||
formspec[#formspec + 1] = W - 0.375*2
|
||||
formspec[#formspec + 1] = ",0.1]"
|
||||
"label[", img_w + 0.25 + 0.05, ",0.5;",
|
||||
core.formspec_escape(
|
||||
core.colorize(mt_color_green, package.title) ..
|
||||
core.colorize("#BFBFBF", " by " .. package.author)), "]",
|
||||
|
||||
if package.downloading then
|
||||
formspec[#formspec + 1] = "animated_image[-1.7,-0.15;1,1;downloading;"
|
||||
formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
|
||||
formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
|
||||
elseif package.queued then
|
||||
formspec[#formspec + 1] = second_base
|
||||
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]"
|
||||
formspec[#formspec + 1] = second_base .. "cdb_add.png;" .. elem_name .. "]"
|
||||
formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Install") .. tooltip_colors
|
||||
else
|
||||
if package.installed_release < package.release then
|
||||
-- The install_ action also handles updating
|
||||
local elem_name = "install_" .. i .. ";"
|
||||
formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#28ccdf]"
|
||||
formspec[#formspec + 1] = third_base .. "cdb_update.png;" .. elem_name .. "]"
|
||||
formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Update") .. tooltip_colors
|
||||
"textarea[", img_w + 0.25, ",0.75;", cell_w - img_w - 0.25, ",", cell_h - 0.75, ";;;",
|
||||
core.formspec_escape(package.short_description), "]",
|
||||
|
||||
description_width = description_width - 0.7 - 0.15
|
||||
end
|
||||
"style[view_", i, ";border=false]",
|
||||
"style[view_", i, ":hovered;bgimg=", core.formspec_escape(defaulttexturedir .. "button_hover_semitrans.png"), "]",
|
||||
"style[view_", i, ":pressed;bgimg=", core.formspec_escape(defaulttexturedir .. "button_press_semitrans.png"), "]",
|
||||
"button[0,0;", cell_w, ",", cell_h, ";view_", i, ";]",
|
||||
})
|
||||
|
||||
local elem_name = "uninstall_" .. i .. ";"
|
||||
formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#a93b3b]"
|
||||
formspec[#formspec + 1] = second_base .. "cdb_clear.png;" .. elem_name .. "]"
|
||||
formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Uninstall") .. tooltip_colors
|
||||
if package.featured then
|
||||
table.insert_all(formspec, {
|
||||
"tooltip[0,0;0.8,0.8;", fgettext("Featured"), "]",
|
||||
"image[0.2,0.2;0.4,0.4;", core.formspec_escape(defaulttexturedir .. "server_favorite.png"), "]",
|
||||
})
|
||||
end
|
||||
|
||||
local web_elem_name = "view_" .. i .. ";"
|
||||
formspec[#formspec + 1] = "image_button[-0.7,0;0.7,0.7;" ..
|
||||
core.formspec_escape(defaulttexturedir) .. "cdb_viewonline.png;" .. web_elem_name .. "]"
|
||||
formspec[#formspec + 1] = "tooltip[" .. web_elem_name ..
|
||||
fgettext("View more information in a web browser") .. tooltip_colors
|
||||
formspec[#formspec + 1] = "container_end[]"
|
||||
table.insert_all(formspec, {
|
||||
"container[", cell_w - 0.625,",", 0.25, "]",
|
||||
})
|
||||
|
||||
-- description
|
||||
formspec[#formspec + 1] = "textarea[1.855,0.3;"
|
||||
formspec[#formspec + 1] = tostring(description_width)
|
||||
formspec[#formspec + 1] = ",0.8;;;"
|
||||
formspec[#formspec + 1] = core.formspec_escape(package.short_description)
|
||||
formspec[#formspec + 1] = "]"
|
||||
if package.downloading then
|
||||
table.insert_all(formspec, {
|
||||
"animated_image[0,0;0.5,0.5;downloading;", core.formspec_escape(defaulttexturedir .. "cdb_downloading.png"),
|
||||
";3;400;;]",
|
||||
})
|
||||
elseif package.queued then
|
||||
table.insert_all(formspec, {
|
||||
"image[0,0;0.5,0.5;", core.formspec_escape(defaulttexturedir .. "cdb_queued.png"), "]",
|
||||
})
|
||||
elseif package.path then
|
||||
if package.installed_release < package.release then
|
||||
table.insert_all(formspec, {
|
||||
"image[0,0;0.5,0.5;", core.formspec_escape(defaulttexturedir .. "cdb_update.png"), "]",
|
||||
})
|
||||
else
|
||||
table.insert_all(formspec, {
|
||||
"image[0.1,0.1;0.3,0.3;", core.formspec_escape(defaulttexturedir .. "checkbox_64.png"), "]",
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
formspec[#formspec + 1] = "container_end[]"
|
||||
table.insert_all(formspec, {
|
||||
"container_end[]",
|
||||
"container_end[]",
|
||||
})
|
||||
end
|
||||
|
||||
formspec[#formspec + 1] = "container_end[]"
|
||||
formspec[#formspec + 1] = "container_end[]"
|
||||
|
||||
return table.concat(formspec)
|
||||
end
|
||||
|
||||
|
@ -364,14 +403,14 @@ local function handle_submit(this, fields)
|
|||
if fields.search or fields.key_enter_field == "search_string" then
|
||||
search_string = fields.search_string:trim()
|
||||
cur_page = 1
|
||||
contentdb.filter_packages(search_string, filter_types_type[filter_type])
|
||||
contentdb.filter_packages(search_string, filter_type)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.clear then
|
||||
search_string = ""
|
||||
cur_page = 1
|
||||
contentdb.filter_packages("", filter_types_type[filter_type])
|
||||
contentdb.filter_packages("", filter_type)
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -407,12 +446,11 @@ local function handle_submit(this, fields)
|
|||
return true
|
||||
end
|
||||
|
||||
if fields.type then
|
||||
local new_type = table.indexof(filter_types_titles, fields.type)
|
||||
if new_type ~= filter_type then
|
||||
filter_type = new_type
|
||||
for _, pair in ipairs(filter_type_names) do
|
||||
if fields[pair[1]] then
|
||||
filter_type = pair[2]
|
||||
cur_page = 1
|
||||
contentdb.filter_packages(search_string, filter_types_type[filter_type])
|
||||
contentdb.filter_packages(search_string, filter_type)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -428,32 +466,20 @@ local function handle_submit(this, fields)
|
|||
return true
|
||||
end
|
||||
|
||||
local num_per_page = this.data.num_per_page
|
||||
local start_idx = (cur_page - 1) * num_per_page + 1
|
||||
assert(start_idx ~= nil)
|
||||
for i=start_idx, math.min(#contentdb.packages, start_idx+num_per_page-1) do
|
||||
local package = contentdb.packages[i]
|
||||
assert(package)
|
||||
|
||||
if fields["install_" .. i] then
|
||||
install_or_update_package(this, package)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["uninstall_" .. i] then
|
||||
local dlg = create_delete_content_dlg(package)
|
||||
if fields["view_" .. i] or fields["title_" .. i] or fields["author_" .. i] then
|
||||
local dlg = create_package_dialog(package)
|
||||
dlg:set_parent(this)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields["view_" .. i] then
|
||||
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
|
||||
end
|
||||
|
||||
return false
|
||||
|
@ -462,8 +488,8 @@ end
|
|||
|
||||
local function handle_events(event)
|
||||
if event == "DialogShow" then
|
||||
-- On touchscreen, don't show the "MINETEST" header behind the dialog.
|
||||
mm_game_theme.set_engine(core.settings:get_bool("touch_gui"))
|
||||
-- Don't show the header image behind the dialog.
|
||||
mm_game_theme.set_engine(true)
|
||||
|
||||
-- If ContentDB is already loaded, auto-install packages here.
|
||||
do_auto_install()
|
||||
|
@ -471,6 +497,11 @@ local function handle_events(event)
|
|||
return true
|
||||
end
|
||||
|
||||
if event == "WindowInfoChange" then
|
||||
ui.update()
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -485,17 +516,7 @@ end
|
|||
function create_contentdb_dlg(type, install_spec)
|
||||
search_string = ""
|
||||
cur_page = 1
|
||||
if type then
|
||||
-- table.indexof does not work on tables that contain `nil`
|
||||
for i, v in pairs(filter_types_type) do
|
||||
if v == type then
|
||||
filter_type = i
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
filter_type = 1
|
||||
end
|
||||
filter_type = type
|
||||
|
||||
-- Keep the old auto_install_spec if the caller doesn't specify one.
|
||||
if install_spec then
|
||||
|
@ -504,8 +525,10 @@ function create_contentdb_dlg(type, install_spec)
|
|||
|
||||
load()
|
||||
|
||||
return dialog_create("contentdb",
|
||||
local dlg = dialog_create("contentdb",
|
||||
get_formspec,
|
||||
handle_submit,
|
||||
handle_events)
|
||||
dlg.data.num_per_page = calculate_num_per_page()
|
||||
return dlg
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2018-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -244,3 +244,45 @@ function create_install_dialog(package)
|
|||
|
||||
return dlg
|
||||
end
|
||||
|
||||
|
||||
function install_or_update_package(parent, package)
|
||||
local install_parent
|
||||
if package.type == "mod" then
|
||||
install_parent = core.get_modpath()
|
||||
elseif package.type == "game" then
|
||||
install_parent = core.get_gamepath()
|
||||
elseif package.type == "txp" then
|
||||
install_parent = core.get_texturepath()
|
||||
else
|
||||
error("Unknown package type: " .. package.type)
|
||||
end
|
||||
|
||||
if package.queued or package.downloading then
|
||||
return
|
||||
end
|
||||
|
||||
local function on_confirm()
|
||||
local dlg = create_install_dialog(package)
|
||||
dlg:set_parent(parent)
|
||||
parent:hide()
|
||||
dlg:show()
|
||||
|
||||
dlg:load_deps()
|
||||
end
|
||||
|
||||
if package.type == "mod" and #pkgmgr.games == 0 then
|
||||
local dlg = messagebox("install_game",
|
||||
fgettext("You need to install a game before you can install a mod"))
|
||||
dlg:set_parent(parent)
|
||||
parent:hide()
|
||||
dlg:show()
|
||||
elseif not package.path and core.is_dir(install_parent .. DIR_DELIM .. package.name) then
|
||||
local dlg = create_confirm_overwrite(package, on_confirm)
|
||||
dlg:set_parent(parent)
|
||||
parent:hide()
|
||||
dlg:show()
|
||||
else
|
||||
on_confirm()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2018-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
329
builtin/mainmenu/content/dlg_package.lua
Normal file
329
builtin/mainmenu/content/dlg_package.lua
Normal file
|
@ -0,0 +1,329 @@
|
|||
--Luanti
|
||||
--Copyright (C) 2018-24 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 get_info_formspec(size, padding, text)
|
||||
return table.concat({
|
||||
"formspec_version[6]",
|
||||
"size[", size.x, ",", size.y, "]",
|
||||
"padding[0,0]",
|
||||
"bgcolor[;true]",
|
||||
|
||||
"label[4,4.35;", text, "]",
|
||||
"container[", padding.x, ",", size.y - 0.8 - padding.y, "]",
|
||||
"button[0,0;2,0.8;back;", fgettext("Back"), "]",
|
||||
"container_end[]",
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
local function get_formspec(data)
|
||||
local window_padding = contentdb.get_formspec_padding()
|
||||
local size = contentdb.get_formspec_size()
|
||||
size.x = math.min(size.x, 20)
|
||||
local W = size.x - window_padding.x * 2
|
||||
local H = size.y - window_padding.y * 2
|
||||
|
||||
if not data.info then
|
||||
if not data.loading and not data.loading_error then
|
||||
data.loading = true
|
||||
|
||||
contentdb.get_full_package_info(data.package, function(info)
|
||||
data.loading = false
|
||||
|
||||
if info == nil then
|
||||
data.loading_error = true
|
||||
ui.update()
|
||||
return
|
||||
end
|
||||
|
||||
assert(data.package.name == info.name)
|
||||
data.info = info
|
||||
ui.update()
|
||||
end)
|
||||
end
|
||||
|
||||
-- get_full_package_info can return cached info immediately, so
|
||||
-- check to see if that happened
|
||||
if not data.info then
|
||||
if data.loading_error then
|
||||
return get_info_formspec(size, window_padding, fgettext("No packages could be retrieved"))
|
||||
end
|
||||
return get_info_formspec(size, window_padding, fgettext("Loading..."))
|
||||
end
|
||||
end
|
||||
|
||||
-- Check installation status
|
||||
contentdb.update_paths()
|
||||
|
||||
local info = data.info
|
||||
|
||||
local info_line =
|
||||
fgettext("by $1 — $2 downloads — +$3 / $4 / -$5",
|
||||
info.author, info.downloads,
|
||||
info.reviews.positive, info.reviews.neutral, info.reviews.negative)
|
||||
|
||||
local bottom_buttons_y = H - 0.8
|
||||
|
||||
local formspec = {
|
||||
"formspec_version[7]",
|
||||
"size[", size.x, ",", size.y, "]",
|
||||
"padding[0,0]",
|
||||
"bgcolor[;true]",
|
||||
|
||||
"container[", window_padding.x, ",", window_padding.y, "]",
|
||||
|
||||
"button[0,", bottom_buttons_y, ";2,0.8;back;", fgettext("Back"), "]",
|
||||
"button[", W - 3, ",", bottom_buttons_y, ";3,0.8;open_contentdb;", fgettext("ContentDB page"), "]",
|
||||
|
||||
"style_type[label;font_size=+24;font=bold]",
|
||||
"label[0,0.4;", core.formspec_escape(info.title), "]",
|
||||
"style_type[label;font_size=;font=]",
|
||||
|
||||
"label[0,1.2;", core.formspec_escape(info_line), "]",
|
||||
}
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"container[", W - 6, ",0]"
|
||||
})
|
||||
|
||||
local left_button_rect = "0,0;2.875,1"
|
||||
local right_button_rect = "3.125,0;2.875,1"
|
||||
if data.package.downloading then
|
||||
formspec[#formspec + 1] = "animated_image[5,0;1,1;downloading;"
|
||||
formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
|
||||
formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
|
||||
elseif data.package.queued then
|
||||
formspec[#formspec + 1] = "style[queued;border=false]"
|
||||
formspec[#formspec + 1] = "image_button[5,0;1,1;" .. core.formspec_escape(defaulttexturedir)
|
||||
formspec[#formspec + 1] = "cdb_queued.png;queued;]"
|
||||
elseif not data.package.path then
|
||||
formspec[#formspec + 1] = "style[install;bgcolor=green]"
|
||||
formspec[#formspec + 1] = "button["
|
||||
formspec[#formspec + 1] = right_button_rect
|
||||
formspec[#formspec + 1] =";install;"
|
||||
formspec[#formspec + 1] = fgettext("Install [$1]", info.download_size)
|
||||
formspec[#formspec + 1] = "]"
|
||||
else
|
||||
if data.package.installed_release < data.package.release then
|
||||
-- The install_ action also handles updating
|
||||
formspec[#formspec + 1] = "style[install;bgcolor=#28ccdf]"
|
||||
formspec[#formspec + 1] = "button["
|
||||
formspec[#formspec + 1] = left_button_rect
|
||||
formspec[#formspec + 1] = ";install;"
|
||||
formspec[#formspec + 1] = fgettext("Update")
|
||||
formspec[#formspec + 1] = "]"
|
||||
end
|
||||
|
||||
formspec[#formspec + 1] = "style[uninstall;bgcolor=#a93b3b]"
|
||||
formspec[#formspec + 1] = "button["
|
||||
formspec[#formspec + 1] = right_button_rect
|
||||
formspec[#formspec + 1] = ";uninstall;"
|
||||
formspec[#formspec + 1] = fgettext("Uninstall")
|
||||
formspec[#formspec + 1] = "]"
|
||||
end
|
||||
|
||||
local current_tab = data.current_tab or 1
|
||||
local tab_titles = {
|
||||
fgettext("Description"),
|
||||
fgettext("Information"),
|
||||
}
|
||||
|
||||
local tab_body_height = bottom_buttons_y - 2.8
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"container_end[]",
|
||||
|
||||
"box[0,2.55;", W, ",", tab_body_height, ";#ffffff11]",
|
||||
|
||||
"tabheader[0,2.55;", W, ",0.8;tabs;",
|
||||
table.concat(tab_titles, ","), ";", current_tab, ";true;true]",
|
||||
|
||||
"container[0,2.8]",
|
||||
})
|
||||
|
||||
if current_tab == 1 then
|
||||
-- Screenshots and description
|
||||
local hypertext = "<big><b>" .. core.hypertext_escape(info.short_description) .. "</b></big>\n"
|
||||
local winfo = core.get_window_info()
|
||||
local fs_to_px = winfo.size.x / winfo.max_formspec_size.x
|
||||
for i, ss in ipairs(info.screenshots) do
|
||||
local path = get_screenshot(data.package, ss.url, 2)
|
||||
hypertext = hypertext .. "<action name=\"ss_" .. i .. "\"><img name=\"" ..
|
||||
core.hypertext_escape(path) .. "\" width=" .. (3 * fs_to_px) ..
|
||||
" height=" .. (2 * fs_to_px) .. "></action>"
|
||||
if i ~= #info.screenshots then
|
||||
hypertext = hypertext .. "<img name=\"blank.png\" width=" .. (0.25 * fs_to_px) ..
|
||||
" height=" .. (2.25 * fs_to_px).. ">"
|
||||
end
|
||||
end
|
||||
hypertext = hypertext .. "\n" .. info.long_description.head
|
||||
|
||||
local first = true
|
||||
local function add_link_button(label, name)
|
||||
if info[name] then
|
||||
if not first then
|
||||
hypertext = hypertext .. " | "
|
||||
end
|
||||
hypertext = hypertext .. "<action name=link_" .. name .. ">" .. core.hypertext_escape(label) .. "</action>"
|
||||
info.long_description.links["link_" .. name] = info[name]
|
||||
first = false
|
||||
end
|
||||
end
|
||||
|
||||
add_link_button(fgettext("Donate"), "donate_url")
|
||||
add_link_button(fgettext("Website"), "website")
|
||||
add_link_button(fgettext("Source"), "repo")
|
||||
add_link_button(fgettext("Issue Tracker"), "issue_tracker")
|
||||
add_link_button(fgettext("Translate"), "translation_url")
|
||||
add_link_button(fgettext("Forum Topic"), "forum_url")
|
||||
|
||||
hypertext = hypertext .. "\n\n" .. info.long_description.body
|
||||
|
||||
hypertext = hypertext:gsub("<img name=\"?blank.png\"? ",
|
||||
"<img name=\"" .. core.hypertext_escape(defaulttexturedir) .. "blank.png\" ")
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"hypertext[0,0;", W, ",", tab_body_height - 0.375,
|
||||
";desc;", core.formspec_escape(hypertext), "]",
|
||||
|
||||
})
|
||||
|
||||
elseif current_tab == 2 then
|
||||
local hypertext = info.info_hypertext.head .. info.info_hypertext.body
|
||||
|
||||
table.insert_all(formspec, {
|
||||
"hypertext[0,0;", W, ",", tab_body_height - 0.375,
|
||||
";info;", core.formspec_escape(hypertext), "]",
|
||||
})
|
||||
else
|
||||
error("Unknown tab " .. current_tab)
|
||||
end
|
||||
|
||||
formspec[#formspec + 1] = "container_end[]"
|
||||
formspec[#formspec + 1] = "container_end[]"
|
||||
|
||||
return table.concat(formspec)
|
||||
end
|
||||
|
||||
|
||||
local function handle_hypertext_event(this, event, hypertext_object)
|
||||
if not (event and event:sub(1, 7) == "action:") then
|
||||
return
|
||||
end
|
||||
|
||||
for i, ss in ipairs(this.data.info.screenshots) do
|
||||
if event == "action:ss_" .. i then
|
||||
core.open_url(ss.url)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local base_url = core.settings:get("contentdb_url"):gsub("(%W)", "%%%1")
|
||||
for key, url in pairs(hypertext_object.links) do
|
||||
if event == "action:" .. key then
|
||||
local author, name = url:match("^" .. base_url .. "/?packages/([A-Za-z0-9 _-]+)/([a-z0-9_]+)/?$")
|
||||
if author and name then
|
||||
local package2 = contentdb.get_package_by_info(author, name)
|
||||
if package2 then
|
||||
local dlg = create_package_dialog(package2)
|
||||
dlg:set_parent(this)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
core.open_url_dialog(url)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function handle_submit(this, fields)
|
||||
local info = this.data.info
|
||||
local package = this.data.package
|
||||
|
||||
if fields.back then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
if not info then
|
||||
return false
|
||||
end
|
||||
|
||||
if fields.open_contentdb then
|
||||
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
|
||||
|
||||
if fields.install then
|
||||
install_or_update_package(this, package)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.uninstall then
|
||||
local dlg = create_delete_content_dlg(package)
|
||||
dlg:set_parent(this)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.tabs then
|
||||
this.data.current_tab = tonumber(fields.tabs)
|
||||
return true
|
||||
end
|
||||
|
||||
if handle_hypertext_event(this, fields.desc, info.long_description) or
|
||||
handle_hypertext_event(this, fields.info, info.info_hypertext) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function handle_events(event)
|
||||
if event == "WindowInfoChange" then
|
||||
ui.update()
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function create_package_dialog(package)
|
||||
assert(package)
|
||||
|
||||
local dlg = dialog_create("package_dialog_" .. package.id,
|
||||
get_formspec,
|
||||
handle_submit,
|
||||
handle_events)
|
||||
local data = dlg.data
|
||||
|
||||
data.package = package
|
||||
data.info = nil
|
||||
data.loading = false
|
||||
data.loading_error = nil
|
||||
data.current_tab = 1
|
||||
return dlg
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2023 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -23,4 +23,5 @@ dofile(path .. DIR_DELIM .. "update_detector.lua")
|
|||
dofile(path .. DIR_DELIM .. "screenshots.lua")
|
||||
dofile(path .. DIR_DELIM .. "dlg_install.lua")
|
||||
dofile(path .. DIR_DELIM .. "dlg_overwrite.lua")
|
||||
dofile(path .. DIR_DELIM .. "dlg_package.lua")
|
||||
dofile(path .. DIR_DELIM .. "dlg_contentdb.lua")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -840,7 +840,7 @@ function pkgmgr.get_contentdb_id(content)
|
|||
return content.author:lower() .. "/" .. content.name
|
||||
end
|
||||
|
||||
-- Until Minetest 5.8.0, Minetest Game was bundled with Minetest.
|
||||
-- Until version 5.8.0, Minetest Game was bundled with the engine.
|
||||
-- Unfortunately, the bundled MTG was not versioned (missing "release"
|
||||
-- field in game.conf).
|
||||
-- Therefore, we consider any installation of MTG that is not versioned,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2023-24 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -23,23 +23,40 @@ local screenshot_downloading = {}
|
|||
local screenshot_downloaded = {}
|
||||
|
||||
|
||||
local function get_filename(path)
|
||||
local parts = path:split("/")
|
||||
return parts[#parts]
|
||||
end
|
||||
|
||||
|
||||
local function get_file_extension(path)
|
||||
local parts = path:split(".")
|
||||
return parts[#parts]
|
||||
end
|
||||
|
||||
|
||||
function get_screenshot(package)
|
||||
if not package.thumbnail then
|
||||
function get_screenshot(package, screenshot_url, level)
|
||||
if not screenshot_url then
|
||||
return defaulttexturedir .. "no_screenshot.png"
|
||||
elseif screenshot_downloading[package.thumbnail] then
|
||||
end
|
||||
|
||||
-- Luanti only supports png and jpg
|
||||
local ext = get_file_extension(screenshot_url)
|
||||
if ext ~= "png" and ext ~= "jpg" then
|
||||
screenshot_url = screenshot_url:sub(0, -#ext - 1) .. "png"
|
||||
end
|
||||
|
||||
-- Set thumbnail level
|
||||
screenshot_url = screenshot_url:gsub("/thumbnails/[0-9]+/", "/thumbnails/" .. level .. "/")
|
||||
screenshot_url = screenshot_url:gsub("/uploads/", "/thumbnails/" .. level .. "/")
|
||||
|
||||
if screenshot_downloading[screenshot_url] then
|
||||
return defaulttexturedir .. "loading_screenshot.png"
|
||||
end
|
||||
|
||||
-- Get tmp screenshot path
|
||||
local ext = get_file_extension(package.thumbnail)
|
||||
local filepath = screenshot_dir .. DIR_DELIM ..
|
||||
("%s-%s-%s.%s"):format(package.type, package.author, package.name, ext)
|
||||
("%s-%s-%s-l%d-%s"):format(package.type, package.author, package.name,
|
||||
level, get_filename(screenshot_url))
|
||||
|
||||
-- Return if already downloaded
|
||||
local file = io.open(filepath, "r")
|
||||
|
@ -49,7 +66,7 @@ function get_screenshot(package)
|
|||
end
|
||||
|
||||
-- Show error if we've failed to download before
|
||||
if screenshot_downloaded[package.thumbnail] then
|
||||
if screenshot_downloaded[screenshot_url] then
|
||||
return defaulttexturedir .. "error_screenshot.png"
|
||||
end
|
||||
|
||||
|
@ -59,16 +76,16 @@ function get_screenshot(package)
|
|||
return core.download_file(params.url, params.dest)
|
||||
end
|
||||
local function callback(success)
|
||||
screenshot_downloading[package.thumbnail] = nil
|
||||
screenshot_downloaded[package.thumbnail] = true
|
||||
screenshot_downloading[screenshot_url] = nil
|
||||
screenshot_downloaded[screenshot_url] = true
|
||||
if not success then
|
||||
core.log("warning", "Screenshot download failed for some reason")
|
||||
end
|
||||
ui.update()
|
||||
end
|
||||
if core.handle_async(download_screenshot,
|
||||
{ dest = filepath, url = package.thumbnail }, callback) then
|
||||
screenshot_downloading[package.thumbnail] = true
|
||||
{ dest = filepath, url = screenshot_url }, callback) then
|
||||
screenshot_downloading[screenshot_url] = true
|
||||
else
|
||||
core.log("error", "ERROR: async event failed")
|
||||
return defaulttexturedir .. "error_screenshot.png"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2023 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
"Desour/DS",
|
||||
"srifqi",
|
||||
"Gregor Parzefall (grorp)",
|
||||
"Lars Müller (luatic)"
|
||||
"Lars Müller (luatic)",
|
||||
"cx384",
|
||||
"sfence"
|
||||
],
|
||||
"previous_core_developers": [
|
||||
"BlockMen",
|
||||
|
@ -44,30 +46,25 @@
|
|||
],
|
||||
"#": "For updating active/previous contributors, see the script in ./util/gather_git_credits.py",
|
||||
"contributors": [
|
||||
"cx384",
|
||||
"numzero",
|
||||
"AFCMS",
|
||||
"sfence",
|
||||
"Wuzzy",
|
||||
"ROllerozxa",
|
||||
"JosiahWI",
|
||||
"OgelGames",
|
||||
"David Heidelberg",
|
||||
"1F616EMO",
|
||||
"HybridDog",
|
||||
"Bradley Pierce (Thresher)",
|
||||
"savilli",
|
||||
"Stvk imension",
|
||||
"y5nw",
|
||||
"Erich Schubert",
|
||||
"numzero",
|
||||
"red-001 <red-001@outlook.ie>",
|
||||
"David Heidelberg",
|
||||
"Wuzzy",
|
||||
"paradust7",
|
||||
"HybridDog",
|
||||
"Zemtzov7",
|
||||
"kromka-chleba",
|
||||
"AFCMS",
|
||||
"chmodsayshello",
|
||||
"jordan4ibanez",
|
||||
"superfloh247"
|
||||
"OgelGames"
|
||||
],
|
||||
"previous_contributors": [
|
||||
"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest logo]",
|
||||
"red-001 <red-001@outlook.ie>",
|
||||
"Ælla Chiana Moskopp (erle) <erle@dieweltistgarnichtso.net> [Logo]",
|
||||
"Giuseppe Bilotta",
|
||||
"HybridDog",
|
||||
"ClobberXD",
|
||||
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
|
||||
"MirceaKitsune <mirceakitsune@gmail.com>",
|
||||
|
@ -75,6 +72,7 @@
|
|||
"MoNTE48",
|
||||
"Constantin Wenger (SpeedProg)",
|
||||
"Ciaran Gultnieks (CiaranG)",
|
||||
"ROllerozxa",
|
||||
"Paul Ouellette (pauloue)",
|
||||
"stujones11",
|
||||
"Rogier <rogier777@gmail.com>",
|
||||
|
|
49
builtin/mainmenu/dlg_clients_list.lua
Normal file
49
builtin/mainmenu/dlg_clients_list.lua
Normal file
|
@ -0,0 +1,49 @@
|
|||
-- Luanti
|
||||
-- Copyright (C) 2024 siliconsniffer
|
||||
-- SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
|
||||
local function clients_list_formspec(dialogdata)
|
||||
local TOUCH_GUI = core.settings:get_bool("touch_gui")
|
||||
local clients_list = dialogdata.server.clients_list
|
||||
local servername = dialogdata.server.name
|
||||
|
||||
local function fmt_formspec_list(clients_list)
|
||||
local escaped = {}
|
||||
for i, str in ipairs(clients_list) do
|
||||
escaped[i] = core.formspec_escape(str)
|
||||
end
|
||||
return table.concat(escaped, ",")
|
||||
end
|
||||
|
||||
local formspec = {
|
||||
"formspec_version[8]",
|
||||
"size[6,9.5]",
|
||||
TOUCH_GUI and "padding[0.01,0.01]" or "",
|
||||
"hypertext[0,0;6,1.5;;<global margin=5 halign=center valign=middle>",
|
||||
fgettext("This is the list of clients connected to\n$1",
|
||||
"<b>" .. core.hypertext_escape(servername) .. "</b>") .. "]",
|
||||
"textlist[0.5,1.5;5,6.8;;" .. fmt_formspec_list(clients_list) .. "]",
|
||||
"button[1.5,8.5;3,0.8;quit;OK]"
|
||||
}
|
||||
return table.concat(formspec, "")
|
||||
end
|
||||
|
||||
|
||||
local function clients_list_buttonhandler(this, fields)
|
||||
if fields.quit then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function create_clientslist_dialog(server)
|
||||
local retval = dialog_create("dlg_clients_list",
|
||||
clients_list_formspec,
|
||||
clients_list_buttonhandler,
|
||||
nil)
|
||||
retval.data.server = server
|
||||
return retval
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2023 Gregor Parzefall
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -68,15 +68,15 @@ end
|
|||
local function get_formspec(dialogdata)
|
||||
local markup = table.concat({
|
||||
"<big>", fgettext("Minetest Game is no longer installed by default"), "</big>\n",
|
||||
fgettext("For a long time, the Minetest engine shipped with a default game called \"Minetest Game\". " ..
|
||||
"Since Minetest 5.8.0, Minetest ships without a default game."), "\n",
|
||||
fgettext("For a long time, Luanti shipped with a default game called \"Minetest Game\". " ..
|
||||
"Since version 5.8.0, Luanti ships without a default game."), "\n",
|
||||
fgettext("If you want to continue playing in your Minetest Game worlds, you need to reinstall Minetest Game."),
|
||||
})
|
||||
|
||||
return table.concat({
|
||||
"formspec_version[6]",
|
||||
"size[12.8,7]",
|
||||
"hypertext[0.375,0.375;12.05,5.2;text;", minetest.formspec_escape(markup), "]",
|
||||
"hypertext[0.375,0.375;12.05,5.2;text;", core.formspec_escape(markup), "]",
|
||||
"container[0.375,5.825]",
|
||||
"style[dismiss;bgcolor=red]",
|
||||
"button[0,0;4,0.8;dismiss;", fgettext("Dismiss"), "]",
|
||||
|
@ -114,7 +114,7 @@ local function eventhandler(event)
|
|||
return true
|
||||
elseif event == "MenuQuit" then
|
||||
-- Don't allow closing the dialog with ESC, but still allow exiting
|
||||
-- Minetest.
|
||||
-- Luanti
|
||||
core.close()
|
||||
return true
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--[[
|
||||
Minetest
|
||||
Luanti
|
||||
Copyright (C) 2018-2020 SmallJoker, 2022 rubenwardy
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -55,6 +55,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
|
|||
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua")
|
||||
|
||||
local tabs = {
|
||||
content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"),
|
||||
|
@ -133,4 +134,5 @@ local function init_globals()
|
|||
check_new_version()
|
||||
end
|
||||
|
||||
assert(os.execute == nil)
|
||||
init_globals()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2020 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -67,6 +67,19 @@ function make.heading(text)
|
|||
end
|
||||
|
||||
|
||||
function make.note(text)
|
||||
return {
|
||||
full_width = true,
|
||||
get_formspec = function(self, avail_w)
|
||||
-- Assuming label height 0.4:
|
||||
-- Position at y=0 to eat 0.2 of the padding above, leave 0.05.
|
||||
-- The returned used_height doesn't include padding.
|
||||
return ("label[0,0;%s]"):format(core.colorize("#bbb", core.formspec_escape(text))), 0.2
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
--- Used for string and numeric style fields
|
||||
---
|
||||
--- @param converter Function to coerce values from strings.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2015 PilzAdam
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -123,6 +123,22 @@ local function load()
|
|||
end,
|
||||
}
|
||||
|
||||
local touchscreen_layout = {
|
||||
query_text = "Touchscreen layout",
|
||||
requires = {
|
||||
touchscreen = true,
|
||||
},
|
||||
get_formspec = function(self, avail_w)
|
||||
local btn_w = math.min(avail_w, 6)
|
||||
return ("button[0,0;%f,0.8;btn_touch_layout;%s]"):format(btn_w, fgettext("Touchscreen layout")), 0.8
|
||||
end,
|
||||
on_submit = function(self, fields)
|
||||
if fields.btn_touch_layout then
|
||||
core.show_touchscreen_layout()
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
add_page({
|
||||
id = "accessibility",
|
||||
title = fgettext_ne("Accessibility"),
|
||||
|
@ -151,10 +167,27 @@ local function load()
|
|||
load_settingtypes()
|
||||
|
||||
table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys)
|
||||
-- insert after "touch_controls"
|
||||
table.insert(page_by_id.controls_touchscreen.content, 2, touchscreen_layout)
|
||||
do
|
||||
local content = page_by_id.graphics_and_audio_shaders.content
|
||||
local content = page_by_id.graphics_and_audio_effects.content
|
||||
local idx = table.indexof(content, "enable_dynamic_shadows")
|
||||
table.insert(content, idx, shadows_component)
|
||||
|
||||
idx = table.indexof(content, "enable_auto_exposure") + 1
|
||||
local note = component_funcs.note(fgettext_ne("(The game will need to enable automatic exposure as well)"))
|
||||
note.requires = get_setting_info("enable_auto_exposure").requires
|
||||
table.insert(content, idx, note)
|
||||
|
||||
idx = table.indexof(content, "enable_bloom") + 1
|
||||
note = component_funcs.note(fgettext_ne("(The game will need to enable bloom as well)"))
|
||||
note.requires = get_setting_info("enable_bloom").requires
|
||||
table.insert(content, idx, note)
|
||||
|
||||
idx = table.indexof(content, "enable_volumetric_lighting") + 1
|
||||
note = component_funcs.note(fgettext_ne("(The game will need to enable volumetric lighting as well)"))
|
||||
note.requires = get_setting_info("enable_volumetric_lighting").requires
|
||||
table.insert(content, idx, note)
|
||||
end
|
||||
|
||||
-- These must not be translated, as they need to show in the local
|
||||
|
@ -222,6 +255,12 @@ local function load()
|
|||
zh_CN = "中文 (简体) [zh_CN]",
|
||||
zh_TW = "正體中文 (繁體) [zh_TW]",
|
||||
}
|
||||
|
||||
get_setting_info("touch_controls").option_labels = {
|
||||
["auto"] = fgettext_ne("Auto"),
|
||||
["true"] = fgettext_ne("Enabled"),
|
||||
["false"] = fgettext_ne("Disabled"),
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -320,13 +359,17 @@ local function check_requirements(name, requires)
|
|||
end
|
||||
|
||||
local video_driver = core.get_active_driver()
|
||||
local shaders_support = video_driver == "opengl" or video_driver == "opengl3" or video_driver == "ogles2"
|
||||
local touch_support = core.irrlicht_device_supports_touch()
|
||||
local touch_controls = core.settings:get("touch_controls")
|
||||
local special = {
|
||||
android = PLATFORM == "Android",
|
||||
desktop = PLATFORM ~= "Android",
|
||||
shaders_support = shaders_support,
|
||||
shaders = core.settings:get_bool("enable_shaders") and shaders_support,
|
||||
opengl = video_driver == "opengl",
|
||||
touch_support = touch_support,
|
||||
-- When touch_controls is "auto", we don't know which input method will
|
||||
-- be used, so we show settings for both.
|
||||
touchscreen = touch_support and (touch_controls == "auto" or core.is_yes(touch_controls)),
|
||||
keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)),
|
||||
opengl = (video_driver == "opengl" or video_driver == "opengl3"),
|
||||
gles = video_driver:sub(1, 5) == "ogles",
|
||||
}
|
||||
|
||||
|
@ -334,7 +377,7 @@ local function check_requirements(name, requires)
|
|||
if special[req_key] == nil then
|
||||
local required_setting = get_setting_info(req_key)
|
||||
if required_setting == nil then
|
||||
core.log("warning", "Unknown setting " .. req_key .. " required by " .. name)
|
||||
core.log("warning", "Unknown setting " .. req_key .. " required by " .. (name or "???"))
|
||||
end
|
||||
local actual_value = core.settings:get_bool(req_key,
|
||||
required_setting and core.is_yes(required_setting.default))
|
||||
|
@ -433,19 +476,6 @@ local function build_page_components(page)
|
|||
end
|
||||
|
||||
|
||||
--- Creates a scrollbaroptions for a scroll_container
|
||||
--
|
||||
-- @param visible_l the length of the scroll_container and scrollbar
|
||||
-- @param total_l length of the scrollable area
|
||||
-- @param scroll_factor as passed to scroll_container
|
||||
local function make_scrollbaroptions_for_scroll_container(visible_l, total_l, scroll_factor)
|
||||
assert(total_l >= visible_l)
|
||||
local max = total_l - visible_l
|
||||
local thumb_size = (visible_l / total_l) * max
|
||||
return ("scrollbaroptions[min=0;max=%f;thumbsize=%f]"):format(max / scroll_factor, thumb_size / scroll_factor)
|
||||
end
|
||||
|
||||
|
||||
local formspec_show_hack = false
|
||||
|
||||
|
||||
|
@ -507,8 +537,8 @@ local function get_formspec(dialogdata)
|
|||
"tooltip[search;", fgettext("Search"), "]",
|
||||
"tooltip[search_clear;", fgettext("Clear"), "]",
|
||||
"container_end[]",
|
||||
"scroll_container[0.25,1.25;", tostring(left_pane_width), ",",
|
||||
tostring(tabsize.height - 1.5), ";leftscroll;vertical;0.1]",
|
||||
("scroll_container[0.25,1.25;%f,%f;leftscroll;vertical;0.1;0]"):format(
|
||||
left_pane_width, tabsize.height - 1.5),
|
||||
"style_type[button;border=false;bgcolor=#3333]",
|
||||
"style_type[button:hover;border=false;bgcolor=#6663]",
|
||||
}
|
||||
|
@ -538,7 +568,6 @@ local function get_formspec(dialogdata)
|
|||
fs[#fs + 1] = "scroll_container_end[]"
|
||||
|
||||
if y >= tabsize.height - 1.25 then
|
||||
fs[#fs + 1] = make_scrollbaroptions_for_scroll_container(tabsize.height - 1.5, y, 0.1)
|
||||
fs[#fs + 1] = ("scrollbar[%f,1.25;%f,%f;vertical;leftscroll;%f]"):format(
|
||||
left_pane_width + 0.25, scrollbar_w, tabsize.height - 1.5, dialogdata.leftscroll or 0)
|
||||
end
|
||||
|
@ -550,7 +579,7 @@ local function get_formspec(dialogdata)
|
|||
end
|
||||
|
||||
local right_pane_width = tabsize.width - left_pane_width - 0.375 - 2*scrollbar_w - 0.25
|
||||
fs[#fs + 1] = ("scroll_container[%f,0;%f,%f;rightscroll;vertical;0.1]"):format(
|
||||
fs[#fs + 1] = ("scroll_container[%f,0;%f,%f;rightscroll;vertical;0.1;0.25]"):format(
|
||||
tabsize.width - right_pane_width - scrollbar_w, right_pane_width, tabsize.height)
|
||||
|
||||
y = 0.25
|
||||
|
@ -606,7 +635,6 @@ local function get_formspec(dialogdata)
|
|||
fs[#fs + 1] = "scroll_container_end[]"
|
||||
|
||||
if y >= tabsize.height then
|
||||
fs[#fs + 1] = make_scrollbaroptions_for_scroll_container(tabsize.height, y + 0.375, 0.1)
|
||||
fs[#fs + 1] = ("scrollbar[%f,0;%f,%f;vertical;rightscroll;%f]"):format(
|
||||
tabsize.width - scrollbar_w, scrollbar_w, tabsize.height, dialogdata.rightscroll or 0)
|
||||
end
|
||||
|
@ -624,6 +652,18 @@ function write_settings_early()
|
|||
end
|
||||
end
|
||||
|
||||
local function regenerate_page_list(dialogdata)
|
||||
local suggested_page_id = update_filtered_pages(dialogdata.query)
|
||||
|
||||
dialogdata.components = nil
|
||||
|
||||
if not filtered_page_by_id[dialogdata.page_id] then
|
||||
dialogdata.leftscroll = 0
|
||||
dialogdata.rightscroll = 0
|
||||
|
||||
dialogdata.page_id = suggested_page_id
|
||||
end
|
||||
end
|
||||
|
||||
local function buttonhandler(this, fields)
|
||||
local dialogdata = this.data
|
||||
|
@ -648,27 +688,7 @@ local function buttonhandler(this, fields)
|
|||
local value = core.is_yes(fields.show_advanced)
|
||||
core.settings:set_bool("show_advanced", value)
|
||||
write_settings_early()
|
||||
end
|
||||
|
||||
-- touch_controls is a checkbox in a setting component. We handle this
|
||||
-- setting differently so we can hide/show pages using the next if-statement
|
||||
if fields.touch_controls ~= nil then
|
||||
local value = core.is_yes(fields.touch_controls)
|
||||
core.settings:set_bool("touch_controls", value)
|
||||
write_settings_early()
|
||||
end
|
||||
|
||||
if fields.show_advanced ~= nil or fields.touch_controls ~= nil then
|
||||
local suggested_page_id = update_filtered_pages(dialogdata.query)
|
||||
|
||||
dialogdata.components = nil
|
||||
|
||||
if not filtered_page_by_id[dialogdata.page_id] then
|
||||
dialogdata.leftscroll = 0
|
||||
dialogdata.rightscroll = 0
|
||||
|
||||
dialogdata.page_id = suggested_page_id
|
||||
end
|
||||
regenerate_page_list(dialogdata)
|
||||
|
||||
return true
|
||||
end
|
||||
|
@ -701,20 +721,26 @@ local function buttonhandler(this, fields)
|
|||
end
|
||||
end
|
||||
|
||||
for i, comp in ipairs(dialogdata.components) do
|
||||
if comp.on_submit and comp:on_submit(fields, this) then
|
||||
write_settings_early()
|
||||
|
||||
local function after_setting_change(comp)
|
||||
write_settings_early()
|
||||
if comp.setting and comp.setting.name == "touch_controls" then
|
||||
-- Changing the "touch_controls" setting may result in a different
|
||||
-- page list.
|
||||
regenerate_page_list(dialogdata)
|
||||
else
|
||||
-- Clear components so they regenerate
|
||||
dialogdata.components = nil
|
||||
end
|
||||
end
|
||||
|
||||
for i, comp in ipairs(dialogdata.components) do
|
||||
if comp.on_submit and comp:on_submit(fields, this) then
|
||||
after_setting_change(comp)
|
||||
return true
|
||||
end
|
||||
if comp.setting and fields["reset_" .. i] then
|
||||
core.settings:remove(comp.setting.name)
|
||||
write_settings_early()
|
||||
|
||||
-- Clear components so they regenerate
|
||||
dialogdata.components = nil
|
||||
after_setting_change(comp)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -725,7 +751,7 @@ end
|
|||
|
||||
local function eventhandler(event)
|
||||
if event == "DialogShow" then
|
||||
-- Don't show the "MINETEST" header behind the dialog.
|
||||
-- Don't show the header image behind the dialog.
|
||||
mm_game_theme.set_engine(true)
|
||||
return true
|
||||
end
|
||||
|
|
|
@ -13,10 +13,10 @@ local minetest_example_header = [[
|
|||
# ../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".
|
||||
# to the program, eg. "luanti.exe --config ../minetest.conf.example".
|
||||
|
||||
# Further documentation:
|
||||
# https://wiki.minetest.net/
|
||||
# https://wiki.luanti.org/
|
||||
|
||||
]]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2022 rubenwardy
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2015 PilzAdam
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2021-2 x2048
|
||||
--Copyright (C) 2022-3 rubenwardy
|
||||
--
|
||||
|
@ -82,7 +82,6 @@ end
|
|||
return {
|
||||
query_text = "Shadows",
|
||||
requires = {
|
||||
shaders = true,
|
||||
opengl = true,
|
||||
},
|
||||
get_formspec = function(self, avail_w)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2013 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -19,12 +19,7 @@
|
|||
local function prepare_credits(dest, source)
|
||||
local string = table.concat(source, "\n") .. "\n"
|
||||
|
||||
local hypertext_escapes = {
|
||||
["\\"] = "\\\\",
|
||||
["<"] = "\\<",
|
||||
[">"] = "\\>",
|
||||
}
|
||||
string = string:gsub("[\\<>]", hypertext_escapes)
|
||||
string = core.hypertext_escape(string)
|
||||
string = string:gsub("%[.-%]", "<gray>%1</gray>")
|
||||
|
||||
table.insert(dest, string)
|
||||
|
@ -37,6 +32,27 @@ local function get_credits()
|
|||
return json
|
||||
end
|
||||
|
||||
local function get_renderer_info()
|
||||
local ret = {}
|
||||
|
||||
-- OpenGL version, stripped to just the important part
|
||||
local s1 = core.get_active_renderer()
|
||||
if s1:sub(1, 7) == "OpenGL " then
|
||||
s1 = s1:sub(8)
|
||||
end
|
||||
local m = s1:match("^[%d.]+")
|
||||
if not m then
|
||||
m = s1:match("^ES [%d.]+")
|
||||
end
|
||||
ret[#ret+1] = m or s1
|
||||
-- video driver
|
||||
ret[#ret+1] = core.get_active_driver():lower()
|
||||
-- irrlicht device
|
||||
ret[#ret+1] = core.get_active_irrlicht_device():upper()
|
||||
|
||||
return table.concat(ret, " / ")
|
||||
end
|
||||
|
||||
return {
|
||||
name = "about",
|
||||
caption = fgettext("About"),
|
||||
|
@ -83,23 +99,15 @@ return {
|
|||
"style[label_button;border=false]" ..
|
||||
"button[0.1,3.4;5.3,0.5;label_button;" ..
|
||||
core.formspec_escape(version.project .. " " .. version.string) .. "]" ..
|
||||
"button_url[1.5,4.1;2.5,0.8;homepage;minetest.net;https://www.minetest.net/]" ..
|
||||
"hypertext[5.5,0.25;9.75,6.6;credits;" .. minetest.formspec_escape(hypertext) .. "]"
|
||||
"button_url[1.5,4.1;2.5,0.8;homepage;luanti.org;https://www.luanti.org/]" ..
|
||||
"hypertext[5.5,0.25;9.75,6.6;credits;" .. core.formspec_escape(hypertext) .. "]"
|
||||
|
||||
-- Render information
|
||||
local active_renderer_info = fgettext("Active renderer:") .. " " ..
|
||||
core.formspec_escape(core.get_active_renderer())
|
||||
local active_renderer_info = fgettext("Active renderer:") .. "\n" ..
|
||||
core.formspec_escape(get_renderer_info())
|
||||
fs = fs .. "style[label_button2;border=false]" ..
|
||||
"button[0.1,6;5.3,0.5;label_button2;" .. active_renderer_info .. "]"..
|
||||
"button[0.1,6;5.3,1;label_button2;" .. active_renderer_info .. "]"..
|
||||
"tooltip[label_button2;" .. active_renderer_info .. "]"
|
||||
|
||||
-- Irrlicht device information
|
||||
local irrlicht_device_info = fgettext("Irrlicht device:") .. " " ..
|
||||
core.formspec_escape(core.get_active_irrlicht_device())
|
||||
fs = fs .. "style[label_button3;border=false]" ..
|
||||
"button[0.1,6.5;5.3,0.5;label_button3;" .. irrlicht_device_info .. "]"..
|
||||
"tooltip[label_button3;" .. irrlicht_device_info .. "]"
|
||||
|
||||
if PLATFORM == "Android" then
|
||||
fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
|
||||
else
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
--
|
||||
|
@ -118,7 +118,7 @@ local function get_formspec(tabview, name, tabdata)
|
|||
|
||||
local title_and_name
|
||||
if selected_pkg.type == "game" then
|
||||
title_and_name = selected_pkg.name
|
||||
title_and_name = selected_pkg.title or selected_pkg.name
|
||||
else
|
||||
title_and_name = (selected_pkg.title or selected_pkg.name) .. "\n" ..
|
||||
core.colorize("#BFBFBF", selected_pkg.name)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -92,11 +92,11 @@ function singleplayer_refresh_gamebar()
|
|||
end
|
||||
end
|
||||
|
||||
local ENABLE_TOUCH = core.settings:get_bool("enable_touch")
|
||||
local TOUCH_GUI = core.settings:get_bool("touch_gui")
|
||||
|
||||
local gamebar_pos_y = MAIN_TAB_H
|
||||
+ TABHEADER_H -- tabheader included in formspec size
|
||||
+ (ENABLE_TOUCH and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP)
|
||||
+ (TOUCH_GUI and GAMEBAR_OFFSET_TOUCH or GAMEBAR_OFFSET_DESKTOP)
|
||||
|
||||
local btnbar = buttonbar_create(
|
||||
"game_button_bar",
|
||||
|
@ -166,8 +166,8 @@ local function get_formspec(tabview, name, tabdata)
|
|||
local H = tabview.height
|
||||
|
||||
local hypertext = "<global valign=middle halign=center size=18>" ..
|
||||
fgettext_ne("Minetest is a game-creation platform that allows you to play many different games.") .. "\n" ..
|
||||
fgettext_ne("Minetest doesn't come with a game by default.") .. " " ..
|
||||
fgettext_ne("Luanti is a game-creation platform that allows you to play many different games.") .. "\n" ..
|
||||
fgettext_ne("Luanti doesn't come with a game by default.") .. " " ..
|
||||
fgettext_ne("You need to install a game before you can create a world.")
|
||||
|
||||
local button_y = H * 2/3 - 0.6
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2014 sapier
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
@ -75,6 +75,51 @@ local function get_sorted_servers()
|
|||
return servers
|
||||
end
|
||||
|
||||
local function is_selected_fav(server)
|
||||
local address = core.settings:get("address")
|
||||
local port = tonumber(core.settings:get("remote_port"))
|
||||
|
||||
for _, fav in ipairs(serverlistmgr.get_favorites()) do
|
||||
if address == fav.address and port == fav.port then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Persists the selected server in the "address" and "remote_port" settings
|
||||
|
||||
local function set_selected_server(server)
|
||||
if server == nil then -- reset selection
|
||||
core.settings:remove("address")
|
||||
core.settings:remove("remote_port")
|
||||
return
|
||||
end
|
||||
local address = server.address
|
||||
local port = server.port
|
||||
gamedata.serverdescription = server.description
|
||||
|
||||
if address and port then
|
||||
core.settings:set("address", address)
|
||||
core.settings:set("remote_port", port)
|
||||
end
|
||||
end
|
||||
|
||||
local function find_selected_server()
|
||||
local address = core.settings:get("address")
|
||||
local port = tonumber(core.settings:get("remote_port"))
|
||||
for _, server in ipairs(serverlistmgr.servers) do
|
||||
if server.address == address and server.port == port then
|
||||
return server
|
||||
end
|
||||
end
|
||||
for _, server in ipairs(serverlistmgr.get_favorites()) do
|
||||
if server.address == address and server.port == port then
|
||||
return server
|
||||
end
|
||||
end
|
||||
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.
|
||||
|
@ -127,17 +172,51 @@ local function get_formspec(tabview, name, tabdata)
|
|||
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
|
||||
local selected_server = find_selected_server()
|
||||
|
||||
if selected_server then
|
||||
if gamedata.serverdescription then
|
||||
retval = retval .. "textarea[0.25,1.85;5.25,2.7;;;" ..
|
||||
core.formspec_escape(gamedata.serverdescription) .. "]"
|
||||
end
|
||||
|
||||
local clients_list = selected_server.clients_list
|
||||
local can_view_clients_list = clients_list and #clients_list > 0
|
||||
if can_view_clients_list then
|
||||
table.sort(clients_list, function(a, b)
|
||||
return a:lower() < b:lower()
|
||||
end)
|
||||
local max_clients = 5
|
||||
if #clients_list > max_clients then
|
||||
retval = retval .. "tooltip[btn_view_clients;" ..
|
||||
fgettext("Clients:\n$1", table.concat(clients_list, "\n", 1, max_clients)) .. "\n..." .. "]"
|
||||
else
|
||||
retval = retval .. "tooltip[btn_view_clients;" ..
|
||||
fgettext("Clients:\n$1", table.concat(clients_list, "\n")) .. "]"
|
||||
end
|
||||
retval = retval .. "style[btn_view_clients;padding=6]"
|
||||
retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
|
||||
"server_view_clients.png") .. ";btn_view_clients;]"
|
||||
end
|
||||
|
||||
if selected_server.url then
|
||||
retval = retval .. "tooltip[btn_server_url;" .. fgettext("Open server website") .. "]"
|
||||
retval = retval .. "style[btn_server_url;padding=6]"
|
||||
retval = retval .. "image_button[" .. (can_view_clients_list and "4" or "4.5") .. ",1.3;0.5,0.5;" ..
|
||||
core.formspec_escape(defaulttexturedir .. "server_url.png") .. ";btn_server_url;]"
|
||||
end
|
||||
|
||||
if is_selected_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;]"
|
||||
else
|
||||
retval = retval .. "tooltip[btn_add_favorite;" .. fgettext("Add favorite") .. "]"
|
||||
retval = retval .. "style[btn_add_favorite;padding=6]"
|
||||
retval = retval .. "image_button[5,1.3;0.5,0.5;" ..
|
||||
core.formspec_escape(defaulttexturedir .. "server_favorite.png") .. ";btn_add_favorite;]"
|
||||
end
|
||||
end
|
||||
|
||||
retval = retval .. "container_end[]"
|
||||
|
@ -196,11 +275,17 @@ local function get_formspec(tabview, name, tabdata)
|
|||
|
||||
retval = retval .. table.concat(rows, ",")
|
||||
|
||||
if tabdata.selected then
|
||||
retval = retval .. ";" .. tabdata.selected .. "]"
|
||||
else
|
||||
retval = retval .. ";0]"
|
||||
local selected_row_idx = 0
|
||||
if selected_server then
|
||||
for i, server in pairs(tabdata.lookup) do
|
||||
if selected_server.address == server.address and
|
||||
selected_server.port == server.port then
|
||||
selected_row_idx = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
retval = retval .. ";" .. selected_row_idx .. "]"
|
||||
|
||||
return retval
|
||||
end
|
||||
|
@ -216,8 +301,7 @@ local function search_server_list(input)
|
|||
-- setup the keyword list
|
||||
local keywords = {}
|
||||
for word in input:gmatch("%S+") do
|
||||
word = word:gsub("(%W)", "%%%1")
|
||||
table.insert(keywords, word)
|
||||
table.insert(keywords, word:lower())
|
||||
end
|
||||
|
||||
if #keywords == 0 then
|
||||
|
@ -228,26 +312,17 @@ local function search_server_list(input)
|
|||
|
||||
-- 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
|
||||
for i, server in ipairs(serverlistmgr.servers) do
|
||||
local name_matches, description_matches = true, true
|
||||
for _, keyword in ipairs(keywords) do
|
||||
name_matches = name_matches and not not
|
||||
(server.name or ""):lower():find(keyword, 1, true)
|
||||
description_matches = description_matches and not not
|
||||
(server.description or ""):lower():find(keyword, 1, true)
|
||||
end
|
||||
if found > 0 then
|
||||
local points = (#serverlistmgr.servers - i) / 5 + found
|
||||
server.points = points
|
||||
if name_matches or description_matches then
|
||||
server.points = #serverlistmgr.servers - i
|
||||
+ (name_matches and 50 or 0)
|
||||
table.insert(search_result, server)
|
||||
end
|
||||
end
|
||||
|
@ -262,35 +337,6 @@ local function search_server_list(input)
|
|||
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
|
||||
|
@ -321,19 +367,23 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
gamedata.serverdescription = server.description
|
||||
|
||||
if gamedata.address and gamedata.port then
|
||||
core.settings:set("address", gamedata.address)
|
||||
core.settings:set("remote_port", gamedata.port)
|
||||
set_selected_server(server)
|
||||
core.start()
|
||||
end
|
||||
return true
|
||||
end
|
||||
if event.type == "CHG" then
|
||||
set_selected_server(tabdata, event.row, server)
|
||||
set_selected_server(server)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if fields.btn_add_favorite then
|
||||
serverlistmgr.add_favorite(find_selected_server())
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_delete_favorite then
|
||||
local idx = core.get_table_index("servers")
|
||||
if not idx then return end
|
||||
|
@ -341,8 +391,20 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
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])
|
||||
set_selected_server(server)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_server_url then
|
||||
core.open_url_dialog(find_selected_server().url)
|
||||
return true
|
||||
end
|
||||
|
||||
if fields.btn_view_clients then
|
||||
local dlg = create_clientslist_dialog(find_selected_server())
|
||||
dlg:set_parent(tabview)
|
||||
tabview:hide()
|
||||
dlg:show()
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -356,8 +418,8 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
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])
|
||||
-- Note: This clears the selection if there are no results
|
||||
set_selected_server(menudata.search_result[1])
|
||||
end
|
||||
|
||||
return true
|
||||
|
@ -384,8 +446,6 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
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
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
--Minetest
|
||||
--Luanti
|
||||
--Copyright (C) 2016 T4im
|
||||
--
|
||||
--This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
#
|
||||
# # This is a comment
|
||||
# #
|
||||
# # Requires: shaders, enable_dynamic_shadows, !touch_controls
|
||||
# # Requires: enable_dynamic_shadows, !enable_waving_leaves
|
||||
# name (Readable name) type type_args
|
||||
#
|
||||
# A requirement can be the name of a boolean setting or an engine-defined value.
|
||||
|
@ -69,17 +69,19 @@
|
|||
#
|
||||
# * The value of a boolean setting, such as enable_dynamic_shadows
|
||||
# * An engine-defined value:
|
||||
# * shaders_support (a video driver that supports shaders, may not be enabled)
|
||||
# * shaders (both enable_shaders and shaders_support)
|
||||
# * desktop / android
|
||||
# * touchscreen / keyboard_mouse
|
||||
# * opengl / gles
|
||||
# * You can negate any requirement by prepending with !
|
||||
#
|
||||
# Sections are marked by a single line in the format: [Section Name]
|
||||
# Sub-section are marked by adding * in front of the section name: [*Sub-section]
|
||||
# Sub-sub-sections have two * etc.
|
||||
# There shouldn't be too much settings per category; settings that shouldn't be
|
||||
# modified by the "average user" should be in (sub-)categories called "Advanced".
|
||||
# There shouldn't be too many settings per category.
|
||||
#
|
||||
# The top-level categories "Advanced", "Client and Server" and "Mapgen" are
|
||||
# handled specially and its contents only shown when a checkbox is checked.
|
||||
# They contain settings not intended for the "average user".
|
||||
|
||||
|
||||
[Controls]
|
||||
|
@ -91,7 +93,7 @@ camera_smoothing (Camera smoothing) float 0.0 0.0 0.99
|
|||
|
||||
# Smooths rotation of camera when in cinematic mode, 0 to disable. Enter cinematic mode by using the key set in Controls.
|
||||
#
|
||||
# Requires: !touch_controls
|
||||
# Requires: keyboard_mouse
|
||||
cinematic_camera_smoothing (Camera smoothing in cinematic mode) float 0.7 0.0 0.99
|
||||
|
||||
# If enabled, you can place nodes at the position (feet + eye level) where you stand.
|
||||
|
@ -112,7 +114,7 @@ always_fly_fast (Always fly fast) bool true
|
|||
# The time in seconds it takes between repeated node placements when holding
|
||||
# the place button.
|
||||
#
|
||||
# Requires: !touch_controls
|
||||
# Requires: keyboard_mouse
|
||||
repeat_place_time (Place repetition interval) float 0.25 0.16 2.0
|
||||
|
||||
# The minimum time in seconds it takes between digging nodes when holding
|
||||
|
@ -131,60 +133,64 @@ safe_dig_and_place (Safe digging and placing) bool false
|
|||
|
||||
# Invert vertical mouse movement.
|
||||
#
|
||||
# Requires: !touch_controls
|
||||
# Requires: keyboard_mouse
|
||||
invert_mouse (Invert mouse) bool false
|
||||
|
||||
# Mouse sensitivity multiplier.
|
||||
#
|
||||
# Requires: !touch_controls
|
||||
# Requires: keyboard_mouse
|
||||
mouse_sensitivity (Mouse sensitivity) float 0.2 0.001 10.0
|
||||
|
||||
# Enable mouse wheel (scroll) for item selection in hotbar.
|
||||
#
|
||||
# Requires: !touch_controls
|
||||
# Requires: keyboard_mouse
|
||||
enable_hotbar_mouse_wheel (Hotbar: Enable mouse wheel for selection) bool true
|
||||
|
||||
# Invert mouse wheel (scroll) direction for item selection in hotbar.
|
||||
#
|
||||
# Requires: !touch_controls
|
||||
# Requires: keyboard_mouse
|
||||
invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
|
||||
|
||||
[*Touchscreen]
|
||||
|
||||
# Enables the touchscreen controls, allowing you to play the game with a touchscreen.
|
||||
touch_controls (Enable touchscreen controls) bool true
|
||||
# "auto" means that the touchscreen controls will be enabled and disabled
|
||||
# automatically depending on the last used input method.
|
||||
#
|
||||
# Requires: touch_support
|
||||
touch_controls (Touchscreen controls) enum auto auto,true,false
|
||||
|
||||
# Touchscreen sensitivity multiplier.
|
||||
#
|
||||
# Requires: touch_controls
|
||||
# Requires: touchscreen
|
||||
touchscreen_sensitivity (Touchscreen sensitivity) float 0.2 0.001 10.0
|
||||
|
||||
# The length in pixels after which a touch interaction is considered movement.
|
||||
#
|
||||
# Requires: touch_controls
|
||||
# Requires: touchscreen
|
||||
touchscreen_threshold (Movement threshold) int 20 0 100
|
||||
|
||||
# The delay in milliseconds after which a touch interaction is considered a long tap.
|
||||
#
|
||||
# Requires: touch_controls
|
||||
# Requires: touchscreen
|
||||
touch_long_tap_delay (Threshold for long taps) int 400 100 1000
|
||||
|
||||
# Use crosshair to select object instead of whole screen.
|
||||
# If enabled, a crosshair will be shown and will be used for selecting object.
|
||||
#
|
||||
# Requires: touch_controls
|
||||
# Requires: touchscreen
|
||||
touch_use_crosshair (Use crosshair for touch screen) bool false
|
||||
|
||||
# Fixes the position of virtual joystick.
|
||||
# If disabled, virtual joystick will center to first-touch's position.
|
||||
#
|
||||
# Requires: touch_controls
|
||||
# Requires: touchscreen
|
||||
fixed_virtual_joystick (Fixed virtual joystick) bool false
|
||||
|
||||
# Use virtual joystick to trigger "Aux1" button.
|
||||
# If enabled, virtual joystick will also tap "Aux1" button when out of main circle.
|
||||
#
|
||||
# Requires: touch_controls
|
||||
# Requires: touchscreen
|
||||
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
|
||||
|
||||
# The gesture for punching players/entities.
|
||||
|
@ -194,10 +200,10 @@ virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool fals
|
|||
# Easy to use and well-known from other games that shall not be named.
|
||||
#
|
||||
# * long_tap
|
||||
# Known from the classic Minetest mobile controls.
|
||||
# Known from the classic Luanti mobile controls.
|
||||
# Combat is more or less impossible.
|
||||
#
|
||||
# Requires: touch_controls
|
||||
# Requires: touchscreen
|
||||
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
|
||||
|
||||
|
||||
|
@ -260,33 +266,10 @@ viewing_range (Viewing range) int 190 20 4000
|
|||
# to the game world only, keeping the GUI intact.
|
||||
# It should give a significant performance boost at the cost of less detailed image.
|
||||
# Higher values result in a less detailed image.
|
||||
# Note: Undersampling is currently not supported if the "3d_mode" setting is set
|
||||
# to a non-default value.
|
||||
undersampling (Undersampling) int 1 1 8
|
||||
|
||||
[**Graphics Effects]
|
||||
|
||||
# Allows liquids to be translucent.
|
||||
translucent_liquids (Translucent liquids) bool true
|
||||
|
||||
# Leaves style:
|
||||
# - Fancy: all faces visible
|
||||
# - Simple: only outer faces, if defined special_tiles are used
|
||||
# - Opaque: disable transparency
|
||||
leaves_style (Leaves style) enum fancy fancy,simple,opaque
|
||||
|
||||
# Connects glass if supported by node.
|
||||
connected_glass (Connect glass) bool false
|
||||
|
||||
# Enable smooth lighting with simple ambient occlusion.
|
||||
# Disable for speed or for different looks.
|
||||
smooth_lighting (Smooth lighting) bool true
|
||||
|
||||
# Enables tradeoffs that reduce CPU load or increase rendering performance
|
||||
# at the expense of minor visual glitches that do not impact game playability.
|
||||
performance_tradeoffs (Tradeoffs for performance) bool false
|
||||
|
||||
# Adds particles when digging a node.
|
||||
enable_particles (Digging particles) bool true
|
||||
|
||||
[**3D]
|
||||
|
||||
# 3D support.
|
||||
|
@ -297,7 +280,6 @@ enable_particles (Digging particles) bool true
|
|||
# - topbottom: split screen top/bottom.
|
||||
# - sidebyside: split screen side by side.
|
||||
# - crossview: Cross-eyed 3d
|
||||
# Note that the interlaced mode requires shaders to be enabled.
|
||||
3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,crossview
|
||||
|
||||
# Strength of 3D mode parallax.
|
||||
|
@ -431,16 +413,18 @@ anisotropic_filter (Anisotropic filtering) bool false
|
|||
# * None - No antialiasing (default)
|
||||
#
|
||||
# * FSAA - Hardware-provided full-screen antialiasing
|
||||
# (incompatible with Post Processing and Undersampling)
|
||||
# A.K.A multi-sample antialiasing (MSAA)
|
||||
# Smoothens out block edges but does not affect the insides of textures.
|
||||
# A restart is required to change this option.
|
||||
#
|
||||
# * FXAA - Fast approximate antialiasing (requires shaders)
|
||||
# If Post Processing is disabled, changing FSAA requires a restart.
|
||||
# Also, if Post Processing is disabled, FSAA will not work together with
|
||||
# undersampling or a non-default "3d_mode" setting.
|
||||
#
|
||||
# * FXAA - Fast approximate antialiasing
|
||||
# Applies a post-processing filter to detect and smoothen high-contrast edges.
|
||||
# Provides balance between speed and image quality.
|
||||
#
|
||||
# * SSAA - Super-sampling antialiasing (requires shaders)
|
||||
# * SSAA - Super-sampling antialiasing
|
||||
# Renders higher-resolution image of the scene, then scales down to reduce
|
||||
# the aliasing effects. This is the slowest and the most accurate method.
|
||||
antialiasing (Antialiasing method) enum none none,fsaa,fxaa,ssaa
|
||||
|
@ -466,29 +450,40 @@ enable_raytraced_culling (Enable Raytraced Culling) bool true
|
|||
|
||||
|
||||
|
||||
[*Shaders]
|
||||
[*Effects]
|
||||
|
||||
# Allows liquids to be translucent.
|
||||
translucent_liquids (Translucent liquids) bool true
|
||||
|
||||
# Leaves style:
|
||||
# - Fancy: all faces visible
|
||||
# - Simple: only outer faces
|
||||
# - Opaque: disable transparency
|
||||
leaves_style (Leaves style) enum fancy fancy,simple,opaque
|
||||
|
||||
# Connects glass if supported by node.
|
||||
connected_glass (Connect glass) bool false
|
||||
|
||||
# Enable smooth lighting with simple ambient occlusion.
|
||||
smooth_lighting (Smooth lighting) bool true
|
||||
|
||||
# Enables tradeoffs that reduce CPU load or increase rendering performance
|
||||
# at the expense of minor visual glitches that do not impact game playability.
|
||||
performance_tradeoffs (Tradeoffs for performance) bool false
|
||||
|
||||
# Adds particles when digging a node.
|
||||
enable_particles (Digging particles) bool true
|
||||
|
||||
# Shaders allow advanced visual effects and may increase performance on some video
|
||||
# cards.
|
||||
#
|
||||
# Requires: shaders_support
|
||||
enable_shaders (Shaders) bool true
|
||||
|
||||
[**Waving Nodes]
|
||||
|
||||
# Set to true to enable waving leaves.
|
||||
#
|
||||
# Requires: shaders
|
||||
enable_waving_leaves (Waving leaves) bool false
|
||||
|
||||
# Set to true to enable waving plants.
|
||||
#
|
||||
# Requires: shaders
|
||||
enable_waving_plants (Waving plants) bool false
|
||||
|
||||
# Set to true to enable waving liquids (like water).
|
||||
#
|
||||
# Requires: shaders
|
||||
enable_waving_water (Waving liquids) bool false
|
||||
|
||||
# The maximum height of the surface of waving liquids.
|
||||
|
@ -496,104 +491,83 @@ enable_waving_water (Waving liquids) bool false
|
|||
# 0.0 = Wave doesn't move at all.
|
||||
# Default is 1.0 (1/2 node).
|
||||
#
|
||||
# Requires: shaders, enable_waving_water
|
||||
# Requires: enable_waving_water
|
||||
water_wave_height (Waving liquids wave height) float 1.0 0.0 4.0
|
||||
|
||||
# Length of liquid waves.
|
||||
#
|
||||
# Requires: shaders, enable_waving_water
|
||||
# Requires: enable_waving_water
|
||||
water_wave_length (Waving liquids wavelength) float 20.0 0.1
|
||||
|
||||
# How fast liquid waves will move. Higher = faster.
|
||||
# If negative, liquid waves will move backwards.
|
||||
#
|
||||
# Requires: shaders, enable_waving_water
|
||||
# Requires: enable_waving_water
|
||||
water_wave_speed (Waving liquids wave speed) float 5.0
|
||||
|
||||
# When enabled, liquid reflections are simulated.
|
||||
#
|
||||
# Requires: shaders, enable_waving_water, enable_dynamic_shadows
|
||||
enable_water_reflections (Liquid reflections) bool false
|
||||
|
||||
[**Dynamic shadows]
|
||||
|
||||
# Set to true to enable Shadow Mapping.
|
||||
#
|
||||
# Requires: shaders, opengl
|
||||
# Requires: opengl
|
||||
enable_dynamic_shadows (Dynamic shadows) bool false
|
||||
|
||||
# Set the shadow strength gamma.
|
||||
# Adjusts the intensity of in-game dynamic shadows.
|
||||
# Lower value means lighter shadows, higher value means darker shadows.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_strength_gamma (Shadow strength gamma) float 1.0 0.1 10.0
|
||||
|
||||
# Maximum distance to render shadows.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 140.0 10.0 1000.0
|
||||
|
||||
# Texture size to render the shadow map on.
|
||||
# This must be a power of two.
|
||||
# Bigger numbers create better shadows but it is also more expensive.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_map_texture_size (Shadow map texture size) int 2048 128 8192
|
||||
|
||||
# Sets shadow texture quality to 32 bits.
|
||||
# On false, 16 bits texture will be used.
|
||||
# This can cause much more artifacts in the shadow.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true
|
||||
|
||||
# Enable Poisson disk filtering.
|
||||
# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
shadow_poisson_filter (Poisson filtering) bool true
|
||||
|
||||
# Define shadow filtering quality.
|
||||
# This simulates the soft shadows effect by applying a PCF or Poisson disk
|
||||
# but also uses more resources.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_filters (Shadow filter quality) enum 1 0,1,2
|
||||
|
||||
# Enable colored shadows.
|
||||
# On true translucent nodes cast colored shadows. This is expensive.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_map_color (Colored shadows) bool false
|
||||
|
||||
# Spread a complete update of shadow map over given number of frames.
|
||||
# Higher values might make shadows laggy, lower values
|
||||
# will consume more resources.
|
||||
# Minimum value: 1; maximum value: 16
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
shadow_update_frames (Map shadows update frames) int 8 1 16
|
||||
|
||||
# Set the soft shadow radius size.
|
||||
# Lower values mean sharper shadows, bigger values mean softer shadows.
|
||||
# Minimum value: 1.0; maximum value: 15.0
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0
|
||||
|
||||
# Set the default tilt of Sun/Moon orbit in degrees.
|
||||
# Games may change orbit tilt via API.
|
||||
# Value of 0 means no tilt / vertical orbit.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows, opengl
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 -60.0 60.0
|
||||
|
||||
[**Post Processing]
|
||||
|
||||
# Enables the post processing pipeline.
|
||||
#
|
||||
# Requires: shaders
|
||||
enable_post_processing (Enable Post Processing) bool true
|
||||
|
||||
# Enables Hable's 'Uncharted 2' filmic tone mapping.
|
||||
|
@ -601,7 +575,7 @@ enable_post_processing (Enable Post Processing) bool true
|
|||
# appearance of high dynamic range images. Mid-range contrast is slightly
|
||||
# enhanced, highlights and shadows are gradually compressed.
|
||||
#
|
||||
# Requires: shaders, enable_post_processing
|
||||
# Requires: enable_post_processing
|
||||
tone_mapping (Filmic tone mapping) bool false
|
||||
|
||||
# Enable automatic exposure correction
|
||||
|
@ -609,14 +583,14 @@ tone_mapping (Filmic tone mapping) bool false
|
|||
# automatically adjust to the brightness of the scene,
|
||||
# simulating the behavior of human eye.
|
||||
#
|
||||
# Requires: shaders, enable_post_processing
|
||||
# Requires: enable_post_processing
|
||||
enable_auto_exposure (Enable Automatic Exposure) bool false
|
||||
|
||||
# Set the exposure compensation in EV units.
|
||||
# Value of 0.0 (default) means no exposure compensation.
|
||||
# Range: from -1 to 1.0
|
||||
#
|
||||
# Requires: shaders, enable_post_processing, enable_auto_exposure
|
||||
# Requires: enable_post_processing, enable_auto_exposure
|
||||
exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0
|
||||
|
||||
# Apply dithering to reduce color banding artifacts.
|
||||
|
@ -627,62 +601,37 @@ exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0
|
|||
# With OpenGL ES, dithering only works if the shader supports high
|
||||
# floating-point precision and it may have a higher performance impact.
|
||||
#
|
||||
# Requires: shaders, enable_post_processing
|
||||
# Requires: enable_post_processing
|
||||
debanding (Enable Debanding) bool true
|
||||
|
||||
[**Bloom]
|
||||
|
||||
# Set to true to enable bloom effect.
|
||||
# Bright colors will bleed over the neighboring objects.
|
||||
#
|
||||
# Requires: shaders, enable_post_processing
|
||||
# Requires: enable_post_processing
|
||||
enable_bloom (Enable Bloom) bool false
|
||||
|
||||
# Set to true to render debugging breakdown of the bloom effect.
|
||||
# In debug mode, the screen is split into 4 quadrants:
|
||||
# top-left - processed base image, top-right - final image
|
||||
# bottom-left - raw base image, bottom-right - bloom texture.
|
||||
#
|
||||
# Requires: shaders, enable_post_processing, enable_bloom
|
||||
enable_bloom_debug (Enable Bloom Debug) bool false
|
||||
|
||||
# Defines how much bloom is applied to the rendered image
|
||||
# Smaller values make bloom more subtle
|
||||
# Range: from 0.01 to 1.0, default: 0.05
|
||||
#
|
||||
# Requires: shaders, enable_post_processing, enable_bloom
|
||||
bloom_intensity (Bloom Intensity) float 0.05 0.01 1.0
|
||||
|
||||
# Defines the magnitude of bloom overexposure.
|
||||
# Range: from 0.1 to 10.0, default: 1.0
|
||||
#
|
||||
# Requires: shaders, enable_post_processing, enable_bloom
|
||||
bloom_strength_factor (Bloom Strength Factor) float 1.0 0.1 10.0
|
||||
|
||||
# Logical value that controls how far the bloom effect spreads
|
||||
# from the bright objects.
|
||||
# Range: from 0.1 to 8, default: 1
|
||||
#
|
||||
# Requires: shaders, enable_post_processing, enable_bloom
|
||||
bloom_radius (Bloom Radius) float 1 0.1 8
|
||||
|
||||
# Set to true to enable volumetric lighting effect (a.k.a. "Godrays").
|
||||
#
|
||||
# Requires: shaders, enable_post_processing, enable_bloom
|
||||
# Requires: enable_post_processing, enable_bloom
|
||||
enable_volumetric_lighting (Volumetric lighting) bool false
|
||||
|
||||
[**Other Effects]
|
||||
|
||||
# Simulate translucency when looking at foliage in the sunlight.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows
|
||||
# Requires: enable_dynamic_shadows
|
||||
enable_translucent_foliage (Translucent foliage) bool false
|
||||
|
||||
# Apply specular shading to nodes.
|
||||
#
|
||||
# Requires: shaders, enable_dynamic_shadows
|
||||
# Requires: enable_dynamic_shadows
|
||||
enable_node_specular (Node specular) bool false
|
||||
|
||||
# When enabled, liquid reflections are simulated.
|
||||
#
|
||||
# Requires: enable_waving_water, enable_dynamic_shadows
|
||||
enable_water_reflections (Liquid reflections) bool false
|
||||
|
||||
[*Audio]
|
||||
|
||||
# Volume of all sounds.
|
||||
|
@ -764,6 +713,10 @@ show_debug (Show debug info) bool false
|
|||
# Radius to use when the block bounds HUD feature is set to near blocks.
|
||||
show_block_bounds_radius_near (Block bounds HUD radius) int 4 0 1000
|
||||
|
||||
# Maximum proportion of current window to be used for hotbar.
|
||||
# Useful if there's something to be displayed right or left of hotbar.
|
||||
hud_hotbar_max_width (Maximum hotbar width) float 1.0 0.001 1.0
|
||||
|
||||
[**Chat]
|
||||
|
||||
# Maximum number of recent chat messages to show
|
||||
|
@ -778,10 +731,6 @@ console_color (Console color) string (0,0,0)
|
|||
# In-game chat console background alpha (opaqueness, between 0 and 255).
|
||||
console_alpha (Console alpha) int 200 0 255
|
||||
|
||||
# Maximum proportion of current window to be used for hotbar.
|
||||
# Useful if there's something to be displayed right or left of hotbar.
|
||||
hud_hotbar_max_width (Maximum hotbar width) float 1.0 0.001 1.0
|
||||
|
||||
# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
|
||||
clickable_chat_weblinks (Chat weblinks) bool true
|
||||
|
||||
|
@ -796,9 +745,9 @@ chat_font_size (Chat font size) int 0 0 72
|
|||
[**Content Repository]
|
||||
|
||||
# The URL for the content repository
|
||||
contentdb_url (ContentDB URL) string https://content.minetest.net
|
||||
contentdb_url (ContentDB URL) string https://content.luanti.org
|
||||
|
||||
# If enabled and you have ContentDB packages installed, Minetest may contact ContentDB to
|
||||
# If enabled and you have ContentDB packages installed, Luanti may contact ContentDB to
|
||||
# check for package updates when opening the mainmenu.
|
||||
contentdb_enable_updates_indicator (Enable updates available indicator on content tab) bool true
|
||||
|
||||
|
@ -806,8 +755,8 @@ contentdb_enable_updates_indicator (Enable updates available indicator on conten
|
|||
# "nonfree" can be used to hide packages which do not qualify as 'free software',
|
||||
# as defined by the Free Software Foundation.
|
||||
# You can also specify content ratings.
|
||||
# These flags are independent from Minetest versions,
|
||||
# so see a full list at https://content.minetest.net/help/content_flags/
|
||||
# These flags are independent from Luanti versions,
|
||||
# so see a full list at https://content.luanti.org/help/content_flags/
|
||||
contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default
|
||||
|
||||
# Maximum number of concurrent downloads. Downloads exceeding this limit will be queued.
|
||||
|
@ -823,13 +772,13 @@ contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 1
|
|||
enable_local_map_saving (Saving map received from server) bool false
|
||||
|
||||
# URL to the server list displayed in the Multiplayer Tab.
|
||||
serverlist_url (Serverlist URL) string servers.minetest.net
|
||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
||||
|
||||
# If enabled, account registration is separate from login in the UI.
|
||||
# If disabled, new accounts will be registered automatically when logging in.
|
||||
enable_split_login_register (Enable split login/register) bool true
|
||||
|
||||
# URL to JSON file which provides information about the newest Minetest release.
|
||||
# URL to JSON file which provides information about the newest Luanti release.
|
||||
# If this is empty the engine will never check for updates.
|
||||
update_information_url (Update information URL) string https://www.minetest.net/release_info.json
|
||||
|
||||
|
@ -843,16 +792,16 @@ name (Admin name) string
|
|||
[**Serverlist and MOTD]
|
||||
|
||||
# Name of the server, to be displayed when players join and in the serverlist.
|
||||
server_name (Server name) string Minetest server
|
||||
server_name (Server name) string Luanti server
|
||||
|
||||
# Description of server, to be displayed when players join and in the serverlist.
|
||||
server_description (Server description) string mine here
|
||||
|
||||
# Domain name of server, to be displayed in the serverlist.
|
||||
server_address (Server address) string game.minetest.net
|
||||
server_address (Server address) string game.example.net
|
||||
|
||||
# Homepage of server, to be displayed in the serverlist.
|
||||
server_url (Server URL) string https://minetest.net
|
||||
server_url (Server URL) string https://game.example.net
|
||||
|
||||
# Automatically report to the serverlist.
|
||||
server_announce (Announce server) bool false
|
||||
|
@ -864,7 +813,7 @@ server_announce_send_players (Send player names to the server list) bool tru
|
|||
serverlist_lan (Show local servers) bool true
|
||||
|
||||
# Announce to this serverlist.
|
||||
serverlist_url (Serverlist URL) string servers.minetest.net
|
||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
||||
|
||||
# Message of the day displayed to players connecting.
|
||||
motd (Message of the day) string
|
||||
|
@ -893,7 +842,7 @@ strict_protocol_version_checking (Strict protocol checking) bool false
|
|||
# Older clients are compatible in the sense that they will not crash when connecting
|
||||
# to new servers, but they may not support all new features that you are expecting.
|
||||
# This allows for more fine-grained control than strict_protocol_version_checking.
|
||||
# Minetest still enforces its own internal minimum, and enabling
|
||||
# Luanti still enforces its own internal minimum, and enabling
|
||||
# strict_protocol_version_checking will effectively override this.
|
||||
protocol_version_min (Protocol version minimum) int 1 1 65535
|
||||
|
||||
|
@ -923,8 +872,13 @@ default_privs (Default privileges) string interact, shout
|
|||
# Privileges that players with basic_privs can grant
|
||||
basic_privs (Basic privileges) string interact, shout
|
||||
|
||||
# If enabled, disable cheat prevention in multiplayer.
|
||||
disable_anticheat (Disable anticheat) bool false
|
||||
# Server anticheat configuration.
|
||||
# Flags are positive. Uncheck the flag to disable corresponding anticheat module.
|
||||
anticheat_flags (Anticheat flags) flags digging,interaction,movement digging,interaction,movement
|
||||
|
||||
# Tolerance of movement cheat detector.
|
||||
# Increase the value if players experience stuttery movement.
|
||||
anticheat_movement_tolerance (Anticheat movement tolerance) float 1.0 1.0
|
||||
|
||||
# If enabled, actions are recorded for rollback.
|
||||
# This option is only read when server starts.
|
||||
|
@ -1837,7 +1791,7 @@ instrument.lbm (Loading Block Modifiers) bool true
|
|||
instrument.chatcommand (Chat commands) bool true
|
||||
|
||||
# Instrument global callback functions on registration.
|
||||
# (anything you pass to a minetest.register_*() function)
|
||||
# (anything you pass to a core.register_*() function)
|
||||
instrument.global_callback (Global callbacks) bool true
|
||||
|
||||
# Instrument builtin.
|
||||
|
@ -1869,9 +1823,10 @@ ignore_world_load_errors (Ignore world errors) bool false
|
|||
|
||||
[**Graphics]
|
||||
|
||||
# Enables debug and error-checking in the OpenGL driver.
|
||||
opengl_debug (OpenGL debug) bool false
|
||||
|
||||
# Path to shader directory. If no path is defined, default location will be used.
|
||||
#
|
||||
# Requires: shaders
|
||||
shader_path (Shader path) path
|
||||
|
||||
# The rendering back-end.
|
||||
|
@ -1884,6 +1839,11 @@ video_driver (Video driver) enum ,opengl,opengl3,ogles2
|
|||
# Set to 0 to disable it entirely.
|
||||
transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128
|
||||
|
||||
# Draw transparency sorted triangles grouped by their mesh buffers.
|
||||
# This breaks transparency sorting between mesh buffers, but avoids situations
|
||||
# where transparency sorting would be very slow otherwise.
|
||||
transparency_sorting_group_by_buffers (Transparency Sorting Group by Buffers) bool true
|
||||
|
||||
# Radius of cloud area stated in number of 64 node cloud squares.
|
||||
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
|
||||
cloud_radius (Cloud radius) int 12 1 62
|
||||
|
@ -1891,17 +1851,18 @@ cloud_radius (Cloud radius) int 12 1 62
|
|||
# Whether node texture animations should be desynchronized per mapblock.
|
||||
desynchronize_mapblock_texture_animation (Desynchronize block animation) bool false
|
||||
|
||||
# Enables caching of facedir rotated meshes.
|
||||
enable_mesh_cache (Mesh cache) bool false
|
||||
|
||||
# Delay between mesh updates on the client in ms. Increasing this will slow
|
||||
# down the rate of mesh updates, thus reducing jitter on slower clients.
|
||||
mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50
|
||||
|
||||
# Number of threads to use for mesh generation.
|
||||
# Value of 0 (default) will let Minetest autodetect the number of available threads.
|
||||
# Value of 0 (default) will let Luanti autodetect the number of available threads.
|
||||
mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8
|
||||
|
||||
# All mesh buffers with less than this number of vertices will be merged
|
||||
# during map rendering. This improves rendering performance.
|
||||
mesh_buffer_min_vertices (Minimum vertex count for mesh buffers) int 100 0 1000
|
||||
|
||||
# True = 256
|
||||
# False = 128
|
||||
# Usable to make minimap smoother on slower machines.
|
||||
|
@ -1940,8 +1901,34 @@ texture_min_size (Base texture size) int 64 1 32768
|
|||
# Systems with a low-end GPU (or no GPU) would benefit from smaller values.
|
||||
client_mesh_chunk (Client Mesh Chunksize) int 1 1 16
|
||||
|
||||
# Enables debug and error-checking in the OpenGL driver.
|
||||
opengl_debug (OpenGL debug) bool false
|
||||
# Decide the color depth of the texture used for the post-processing pipeline.
|
||||
# Reducing this can improve performance, but might cause some effects (e.g. bloom)
|
||||
# to not work.
|
||||
#
|
||||
# Requires: enable_post_processing
|
||||
post_processing_texture_bits (Color depth for post-processing texture) enum 16 8,10,16
|
||||
|
||||
# Enable Poisson disk filtering.
|
||||
# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering.
|
||||
#
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_poisson_filter (Poisson filtering) bool true
|
||||
|
||||
# Spread a complete update of shadow map over given number of frames.
|
||||
# Higher values might make shadows laggy, lower values
|
||||
# will consume more resources.
|
||||
# Minimum value: 1; maximum value: 16
|
||||
#
|
||||
# Requires: enable_dynamic_shadows, opengl
|
||||
shadow_update_frames (Map shadows update frames) int 8 1 16
|
||||
|
||||
# Set to true to render debugging breakdown of the bloom effect.
|
||||
# In debug mode, the screen is split into 4 quadrants:
|
||||
# top-left - processed base image, top-right - final image
|
||||
# bottom-left - raw base image, bottom-right - bloom texture.
|
||||
#
|
||||
# Requires: enable_post_processing, enable_bloom
|
||||
enable_bloom_debug (Enable Bloom Debug) bool false
|
||||
|
||||
[**Sound]
|
||||
# Comma-separated list of AL and ALC extensions that should not be used.
|
||||
|
@ -2025,7 +2012,7 @@ lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
|
|||
[**Networking]
|
||||
|
||||
# Prometheus listener address.
|
||||
# If Minetest is compiled with ENABLE_PROMETHEUS option enabled,
|
||||
# If Luanti is compiled with ENABLE_PROMETHEUS option enabled,
|
||||
# enable metrics listener for Prometheus on that address.
|
||||
# Metrics can be fetched on http://127.0.0.1:30000/metrics
|
||||
prometheus_listener_address (Prometheus listener address) string 127.0.0.1:30000
|
||||
|
@ -2085,6 +2072,8 @@ ask_reconnect_on_crash (Ask to reconnect after crash) bool false
|
|||
# Length of a server tick (the interval at which everything is generally updated),
|
||||
# stated in seconds.
|
||||
# Does not apply to sessions hosted from the client menu.
|
||||
# This is a lower bound, i.e. server steps may not be shorter than this, but
|
||||
# they are often longer.
|
||||
dedicated_server_step (Dedicated server step) float 0.09 0.0 1.0
|
||||
|
||||
# Whether players are shown to clients without any range limit.
|
||||
|
@ -2230,7 +2219,7 @@ curl_file_download_timeout (cURL file download timeout) int 300000 5000 21474836
|
|||
# Adjust the detected display density, used for scaling UI elements.
|
||||
display_density_factor (Display Density Scaling Factor) float 1 0.5 5.0
|
||||
|
||||
# Windows systems only: Start Minetest with the command line window in the background.
|
||||
# Windows systems only: Start Luanti with the command line window in the background.
|
||||
# Contains the same information as the file debug.txt (default name).
|
||||
enable_console (Enable console window) bool false
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue