Merge branch 'minetest:master' into bfs-water-shaders

This commit is contained in:
DragonWrangler1 2024-07-23 12:36:51 -05:00 committed by GitHub
commit c52ff46099
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
100 changed files with 45695 additions and 20802 deletions

View File

@ -36,6 +36,9 @@ Contributions are welcome! Here's how you can help:
- Follow the [C/C++](http://dev.minetest.net/Code_style_guidelines) and - Follow the [C/C++](http://dev.minetest.net/Code_style_guidelines) and
[Lua](http://dev.minetest.net/Lua_code_style_guidelines) code style guidelines. [Lua](http://dev.minetest.net/Lua_code_style_guidelines) code style guidelines.
- Check your code works as expected and document any changes to the Lua API. - Check your code works as expected and document any changes to the Lua API.
- To avoid conflicting changes between contributions, do not do the following manually. They will be done before each release.
- Run `updatepo.sh` or update `minetest.po{,t}` even if your code adds new translatable strings.
- Update `minetest.conf.example` and `settings_translation_file.cpp` even if your code adds new core settings.
4. Commit & [push](https://help.github.com/articles/pushing-to-a-remote/) your changes to a new branch (not `master`, one change per branch) 4. Commit & [push](https://help.github.com/articles/pushing-to-a-remote/) your changes to a new branch (not `master`, one change per branch)
- Commit messages should: - Commit messages should:

View File

@ -156,7 +156,7 @@ elseif(UNIX) # Linux, BSD etc
set(EXAMPLE_CONF_DIR ".") set(EXAMPLE_CONF_DIR ".")
set(MANDIR "unix/man") set(MANDIR "unix/man")
set(XDG_APPS_DIR "unix/applications") set(XDG_APPS_DIR "unix/applications")
set(APPDATADIR "unix/metainfo") set(METAINFODIR "unix/metainfo")
set(ICONDIR "unix/icons") set(ICONDIR "unix/icons")
set(LOCALEDIR "locale") set(LOCALEDIR "locale")
else() else()
@ -167,7 +167,7 @@ elseif(UNIX) # Linux, BSD etc
set(MANDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_MANDIR}") set(MANDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_MANDIR}")
set(EXAMPLE_CONF_DIR ${DOCDIR}) set(EXAMPLE_CONF_DIR ${DOCDIR})
set(XDG_APPS_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/applications") set(XDG_APPS_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/applications")
set(APPDATADIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/metainfo") set(METAINFODIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/metainfo")
set(ICONDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/icons") set(ICONDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/icons")
set(LOCALEDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LOCALEDIR}") set(LOCALEDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LOCALEDIR}")
endif() endif()
@ -258,7 +258,7 @@ install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6") install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}") install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
install(FILES "misc/net.minetest.minetest.appdata.xml" DESTINATION "${APPDATADIR}") install(FILES "misc/net.minetest.minetest.metainfo.xml" DESTINATION "${METAINFODIR}")
install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps") install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
install(FILES "misc/minetest-xorg-icon-128.png" install(FILES "misc/minetest-xorg-icon-128.png"
DESTINATION "${ICONDIR}/hicolor/128x128/apps" DESTINATION "${ICONDIR}/hicolor/128x128/apps"

View File

@ -102,14 +102,24 @@ local function buttonbar_formspec(self)
end end
local function buttonbar_buttonhandler(self, fields) local function buttonbar_buttonhandler(self, fields)
if fields[self.btn_prev_name] and self.cur_page > 1 then if fields[self.btn_prev_name] then
if self.cur_page > 1 then
self.cur_page = self.cur_page - 1 self.cur_page = self.cur_page - 1
return true return true
elseif self.cur_page == 1 then
self.cur_page = self.num_pages
return true
end
end end
if fields[self.btn_next_name] and self.cur_page < self.num_pages then if fields[self.btn_next_name] then
if self.cur_page < self.num_pages then
self.cur_page = self.cur_page + 1 self.cur_page = self.cur_page + 1
return true return true
elseif self.cur_page == self.num_pages then
self.cur_page = 1
return true
end
end end
for _, btn in ipairs(self.buttons) do for _, btn in ipairs(self.buttons) do

View File

@ -182,14 +182,26 @@ function contentdb.get_package_by_id(id)
end end
local function get_raw_dependencies(package) -- Create a coroutine from `fn` and provide results to `callback` when complete (dead).
if package.type ~= "mod" then -- Returns a resumer function.
return {} local function make_callback_coroutine(fn, callback)
local co = coroutine.create(fn)
local function resumer(...)
local ok, result = coroutine.resume(co, ...)
if not ok then
error(result)
elseif coroutine.status(co) == "dead" then
callback(result)
end end
if package.raw_deps then
return package.raw_deps
end end
return resumer
end
local function get_raw_dependencies_async(package)
local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s" local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s"
local version = core.get_version() local version = core.get_version()
local base_url = core.settings:get("contentdb_url") local base_url = core.settings:get("contentdb_url")
@ -198,11 +210,25 @@ local function get_raw_dependencies(package)
local http = core.get_http_api() local http = core.get_http_api()
local response = http.fetch_sync({ url = url }) local response = http.fetch_sync({ url = url })
if not response.succeeded then if not response.succeeded then
core.log("error", "Unable to fetch dependencies for " .. package.url_part) return nil
return end
return core.parse_json(response.data) or {}
end
local function get_raw_dependencies_co(package, resumer)
if package.type ~= "mod" then
return {}
end
if package.raw_deps then
return package.raw_deps
end end
local data = core.parse_json(response.data) or {} core.handle_async(get_raw_dependencies_async, package, resumer)
local data = coroutine.yield()
if not data then
return nil
end
for id, raw_deps in pairs(data) do for id, raw_deps in pairs(data) do
local package2 = contentdb.package_by_id[id:lower()] local package2 = contentdb.package_by_id[id:lower()]
@ -223,8 +249,8 @@ local function get_raw_dependencies(package)
end end
function contentdb.has_hard_deps(package) local function has_hard_deps_co(package, resumer)
local raw_deps = get_raw_dependencies(package) local raw_deps = get_raw_dependencies_co(package, resumer)
if not raw_deps then if not raw_deps then
return nil return nil
end end
@ -239,8 +265,14 @@ function contentdb.has_hard_deps(package)
end end
function contentdb.has_hard_deps(package, callback)
local resumer = make_callback_coroutine(has_hard_deps_co, callback)
resumer(package, resumer)
end
-- Recursively resolve dependencies, given the installed mods -- Recursively resolve dependencies, given the installed mods
local function resolve_dependencies_2(raw_deps, installed_mods, out) local function resolve_dependencies_2_co(raw_deps, installed_mods, out, resumer)
local function resolve_dep(dep) local function resolve_dep(dep)
-- Check whether it's already installed -- Check whether it's already installed
if installed_mods[dep.name] then if installed_mods[dep.name] then
@ -290,9 +322,9 @@ local function resolve_dependencies_2(raw_deps, installed_mods, out)
local result = resolve_dep(dep) local result = resolve_dep(dep)
out[dep.name] = result out[dep.name] = result
if result and result.package and not result.installed then if result and result.package and not result.installed then
local raw_deps2 = get_raw_dependencies(result.package) local raw_deps2 = get_raw_dependencies_co(result.package, resumer)
if raw_deps2 then if raw_deps2 then
resolve_dependencies_2(raw_deps2, installed_mods, out) resolve_dependencies_2_co(raw_deps2, installed_mods, out, resumer)
end end
end end
end end
@ -302,11 +334,10 @@ local function resolve_dependencies_2(raw_deps, installed_mods, out)
end end
-- Resolve dependencies for a package, calls the recursive version. local function resolve_dependencies_co(package, game, resumer)
function contentdb.resolve_dependencies(package, game)
assert(game) assert(game)
local raw_deps = get_raw_dependencies(package) local raw_deps = get_raw_dependencies_co(package, resumer)
local installed_mods = {} local installed_mods = {}
local mods = {} local mods = {}
@ -320,7 +351,7 @@ function contentdb.resolve_dependencies(package, game)
end end
local out = {} local out = {}
if not resolve_dependencies_2(raw_deps, installed_mods, out) then if not resolve_dependencies_2_co(raw_deps, installed_mods, out, resumer) then
return nil return nil
end end
@ -337,6 +368,13 @@ function contentdb.resolve_dependencies(package, game)
end end
-- Resolve dependencies for a package, calls the recursive version.
function contentdb.resolve_dependencies(package, game, callback)
local resumer = make_callback_coroutine(resolve_dependencies_co, callback)
resumer(package, game, resumer)
end
local function fetch_pkgs(params) local function fetch_pkgs(params)
local version = core.get_version() local version = core.get_version()
local base_url = core.settings:get("contentdb_url") local base_url = core.settings:get("contentdb_url")

View File

@ -63,21 +63,12 @@ local function install_or_update_package(this, package)
end end
local function on_confirm() local function on_confirm()
local has_hard_deps = contentdb.has_hard_deps(package)
if has_hard_deps then
local dlg = create_install_dialog(package) local dlg = create_install_dialog(package)
dlg:set_parent(this) dlg:set_parent(this)
this:hide() this:hide()
dlg:show() dlg:show()
elseif has_hard_deps == nil then
local dlg = messagebox("error_checking_deps", dlg:load_deps()
fgettext("Error getting dependencies for package"))
dlg:set_parent(this)
this:hide()
dlg:show()
else
contentdb.queue_download(package, package.path and contentdb.REASON_UPDATE or contentdb.REASON_NEW)
end
end end
if package.type == "mod" and #pkgmgr.games == 0 then if package.type == "mod" and #pkgmgr.games == 0 then

View File

@ -15,7 +15,31 @@
--with this program; if not, write to the Free Software Foundation, Inc., --with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local function is_still_visible(dlg)
local this = ui.find_by_name("install_dialog")
return this == dlg and not dlg.hidden
end
local function get_loading_formspec()
local ENABLE_TOUCH = core.settings:get_bool("enable_touch")
local w = ENABLE_TOUCH and 14 or 7
local formspec = {
"formspec_version[3]",
"size[", w, ",9.05]",
ENABLE_TOUCH and "padding[0.01,0.01]" or "position[0.5,0.55]",
"label[3,4.525;", fgettext("Loading..."), "]",
}
return table.concat(formspec)
end
local function get_formspec(data) local function get_formspec(data)
if not data.has_hard_deps_ready then
return get_loading_formspec()
end
local selected_game, selected_game_idx = pkgmgr.find_by_gameid(core.settings:get("menu_last_game")) local selected_game, selected_game_idx = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
if not selected_game_idx then if not selected_game_idx then
selected_game_idx = 1 selected_game_idx = 1
@ -27,15 +51,35 @@ local function get_formspec(data)
game_list[i] = core.formspec_escape(game.title) game_list[i] = core.formspec_escape(game.title)
end end
if not data.deps_ready[selected_game_idx] and
not data.deps_loading[selected_game_idx] then
data.deps_loading[selected_game_idx] = true
contentdb.resolve_dependencies(data.package, selected_game, function(deps)
if not is_still_visible(data.dlg) then
return
end
data.deps_ready[selected_game_idx] = deps
ui.update()
end)
end
-- The value of `data.deps_ready[selected_game_idx]` may have changed
-- since the last if statement since `contentdb.resolve_dependencies`
-- calls the callback immediately if the dependencies are already cached.
if not data.deps_ready[selected_game_idx] then
return get_loading_formspec()
end
local package = data.package local package = data.package
local will_install_deps = data.will_install_deps local will_install_deps = data.will_install_deps
local deps_to_install = 0 local deps_to_install = 0
local deps_not_found = 0 local deps_not_found = 0
data.dependencies = contentdb.resolve_dependencies(package, selected_game) data.deps_chosen = data.deps_ready[selected_game_idx]
local formatted_deps = {} local formatted_deps = {}
for _, dep in pairs(data.dependencies) do for _, dep in pairs(data.deps_chosen) do
formatted_deps[#formatted_deps + 1] = "#fff" formatted_deps[#formatted_deps + 1] = "#fff"
formatted_deps[#formatted_deps + 1] = core.formspec_escape(dep.name) formatted_deps[#formatted_deps + 1] = core.formspec_escape(dep.name)
if dep.installed then if dep.installed then
@ -128,7 +172,7 @@ local function handle_submit(this, fields)
contentdb.queue_download(data.package, contentdb.REASON_NEW) contentdb.queue_download(data.package, contentdb.REASON_NEW)
if data.will_install_deps then if data.will_install_deps then
for _, dep in pairs(data.dependencies) do for _, dep in pairs(data.deps_chosen) do
if not dep.is_optional and not dep.installed and dep.package then if not dep.is_optional and not dep.installed and dep.package then
contentdb.queue_download(dep.package, contentdb.REASON_DEPENDENCY) contentdb.queue_download(dep.package, contentdb.REASON_DEPENDENCY)
end end
@ -153,10 +197,50 @@ local function handle_submit(this, fields)
end end
local function load_deps(dlg)
local package = dlg.data.package
contentdb.has_hard_deps(package, function(result)
if not is_still_visible(dlg) then
return
end
if result == nil then
local parent = dlg.parent
dlg:delete()
local dlg2 = messagebox("error_checking_deps",
fgettext("Error getting dependencies for package $1", package.url_part))
dlg2:set_parent(parent)
parent:hide()
dlg2:show()
elseif result == false then
contentdb.queue_download(package, package.path and contentdb.REASON_UPDATE or contentdb.REASON_NEW)
dlg:delete()
else
assert(result == true)
dlg.data.has_hard_deps_ready = true
end
ui.update()
end)
end
function create_install_dialog(package) function create_install_dialog(package)
local dlg = dialog_create("install_dialog", get_formspec, handle_submit, nil) local dlg = dialog_create("install_dialog", get_formspec, handle_submit, nil)
dlg.data.dependencies = nil dlg.data.deps_chosen = nil
dlg.data.package = package dlg.data.package = package
dlg.data.will_install_deps = true dlg.data.will_install_deps = true
dlg.data.has_hard_deps_ready = false
dlg.data.deps_ready = {}
dlg.data.deps_loading = {}
dlg.load_deps = load_deps
-- `get_formspec` needs to access `dlg` to check whether it's still open.
-- It doesn't suffice to check that any "install_dialog" instance is open
-- via `ui.find_by_name`, it's necessary to check for this exact instance.
dlg.data.dlg = dlg
return dlg return dlg
end end

View File

@ -31,7 +31,7 @@ local cache_file_path = core.get_cache_path() .. DIR_DELIM .. "cdb" .. DIR_DELIM
local has_fetched = false local has_fetched = false
local latest_releases local latest_releases
do do
if check_cache_age("cdb_updates_last_checked", 3 * 3600) then if check_cache_age("cdb_updates_last_checked", 24 * 3600) then
local f = io.open(cache_file_path, "r") local f = io.open(cache_file_path, "r")
local data = "" local data = ""
if f then if f then

View File

@ -280,7 +280,7 @@ end
return { return {
name = "content", name = "content",
caption = function() caption = function()
local update_count = update_detector.get_count() local update_count = core.settings:get_bool("contentdb_enable_updates_indicator") and update_detector.get_count() or 0
if update_count == 0 then if update_count == 0 then
return fgettext("Content") return fgettext("Content")
else else

View File

@ -188,7 +188,7 @@ fixed_virtual_joystick (Fixed virtual joystick) bool false
# Requires: touchscreen_gui # Requires: touchscreen_gui
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
# The gesture for for punching players/entities. # The gesture for punching players/entities.
# This can be overridden by games and mods. # This can be overridden by games and mods.
# #
# * short_tap # * short_tap
@ -771,6 +771,10 @@ chat_font_size (Chat font size) int 0 0 72
# The URL for the content repository # The URL for the content repository
contentdb_url (ContentDB URL) string https://content.minetest.net contentdb_url (ContentDB URL) string https://content.minetest.net
# If enabled and you have ContentDB packages installed, Minetest 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
# Comma-separated list of flags to hide in the content repository. # Comma-separated list of flags to hide in the content repository.
# "nonfree" can be used to hide packages which do not qualify as 'free software', # "nonfree" can be used to hide packages which do not qualify as 'free software',
# as defined by the Free Software Foundation. # as defined by the Free Software Foundation.
@ -798,7 +802,7 @@ serverlist_url (Serverlist URL) string servers.minetest.net
# If disabled, new accounts will be registered automatically when logging in. # If disabled, new accounts will be registered automatically when logging in.
enable_split_login_register (Enable split login/register) bool true 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 Minetest release.
# If this is empty the engine will never check for updates. # 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 update_information_url (Update information URL) string https://www.minetest.net/release_info.json

View File

@ -4,6 +4,7 @@ Minetest Lua Modding API Reference
* More information at <http://www.minetest.net/> * More information at <http://www.minetest.net/>
* Developer Wiki: <http://dev.minetest.net/> * Developer Wiki: <http://dev.minetest.net/>
* (Unofficial) Minetest Modding Book by rubenwardy: <https://rubenwardy.com/minetest_modding_book/> * (Unofficial) Minetest Modding Book by rubenwardy: <https://rubenwardy.com/minetest_modding_book/>
* Modding tools: <https://github.com/minetest/modtools>
Introduction Introduction
------------ ------------
@ -456,6 +457,10 @@ i.e. without gamma-correction.
Textures can be overlaid by putting a `^` between them. Textures can be overlaid by putting a `^` between them.
Warning: If the lower and upper pixels are both semi-transparent, this operation
does *not* do alpha blending, and it is *not* associative. Otherwise it does
alpha blending in srgb color space.
Example: Example:
default_dirt.png^default_grass_side.png default_dirt.png^default_grass_side.png
@ -4084,9 +4089,9 @@ Translations
Texts can be translated client-side with the help of `minetest.translate` and Texts can be translated client-side with the help of `minetest.translate` and
translation files. translation files.
Consider using the script `util/mod_translation_updater.py` in the Minetest Consider using the script `mod_translation_updater.py` in the Minetest
repository to generate and update translation files automatically from the Lua [modtools](https://github.com/minetest/modtools) repository to generate and
sources. See `util/README_mod_translation_updater.md` for an explanation. update translation files automatically from the Lua sources.
Translating a string Translating a string
-------------------- --------------------

View File

@ -339,6 +339,10 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters &param) :
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
#if defined(SDL_HINT_APP_NAME)
SDL_SetHint(SDL_HINT_APP_NAME, "Minetest");
#endif
u32 flags = SDL_INIT_TIMER | SDL_INIT_EVENTS; u32 flags = SDL_INIT_TIMER | SDL_INIT_EVENTS;
if (CreationParams.DriverType != video::EDT_NULL) if (CreationParams.DriverType != video::EDT_NULL)
flags |= SDL_INIT_VIDEO; flags |= SDL_INIT_VIDEO;
@ -705,6 +709,7 @@ bool CIrrDeviceSDL::run()
while (!Close && wrap_PollEvent(&SDL_event)) { while (!Close && wrap_PollEvent(&SDL_event)) {
// os::Printer::log("event: ", core::stringc((int)SDL_event.type).c_str(), ELL_INFORMATION); // just for debugging // os::Printer::log("event: ", core::stringc((int)SDL_event.type).c_str(), ELL_INFORMATION); // just for debugging
memset(&irrevent, 0, sizeof(irrevent));
switch (SDL_event.type) { switch (SDL_event.type) {
case SDL_MOUSEMOTION: { case SDL_MOUSEMOTION: {

View File

@ -50,6 +50,11 @@
# type: float min: 0.16 max: 2 # type: float min: 0.16 max: 2
# repeat_place_time = 0.25 # repeat_place_time = 0.25
# The minimum time in seconds it takes between digging nodes when holding
# the dig button.
# type: float min: 0 max: 2
# repeat_dig_time = 0.0
# Automatically jump up single-node obstacles. # Automatically jump up single-node obstacles.
# type: bool # type: bool
# autojump = false # autojump = false
@ -80,14 +85,22 @@
## Touchscreen ## Touchscreen
# The length in pixels it takes for touchscreen interaction to start. # Enables touchscreen mode, allowing you to play the game with a touchscreen.
# type: int min: 0 max: 100 # type: bool
# touchscreen_threshold = 20 # enable_touch = true
# Touchscreen sensitivity multiplier. # Touchscreen sensitivity multiplier.
# type: float min: 0.001 max: 10 # type: float min: 0.001 max: 10
# touchscreen_sensitivity = 0.2 # touchscreen_sensitivity = 0.2
# The length in pixels after which a touch interaction is considered movement.
# type: int min: 0 max: 100
# touchscreen_threshold = 20
# The delay in milliseconds after which a touch interaction is considered a long tap.
# type: int min: 100 max: 1000
# touch_long_tap_delay = 400
# Use crosshair to select object instead of whole screen. # Use crosshair to select object instead of whole screen.
# If enabled, a crosshair will be shown and will be used for selecting object. # If enabled, a crosshair will be shown and will be used for selecting object.
# type: bool # type: bool
@ -103,6 +116,18 @@
# type: bool # type: bool
# virtual_joystick_triggers_aux1 = false # virtual_joystick_triggers_aux1 = false
# The gesture for for punching players/entities.
# This can be overridden by games and mods.
#
# * short_tap
# Easy to use and well-known from other games that shall not be named.
#
# * long_tap
# Known from the classic Minetest mobile controls.
# Combat is more or less impossible.
# type: enum values: short_tap, long_tap
# touch_punch_gesture = short_tap
# #
# Graphics and Audio # Graphics and Audio
# #
@ -167,9 +192,9 @@
### Graphics Effects ### Graphics Effects
# Makes all liquids opaque # Allows liquids to be translucent.
# type: bool # type: bool
# opaque_water = false # translucent_liquids = true
# Leaves style: # Leaves style:
# - Fancy: all faces visible # - Fancy: all faces visible
@ -348,7 +373,8 @@
# #
# * None - No antialiasing (default) # * None - No antialiasing (default)
# #
# * FSAA - Hardware-provided full-screen antialiasing (incompatible with shaders) # * FSAA - Hardware-provided full-screen antialiasing
# (incompatible with Post Processing and Undersampling)
# A.K.A multi-sample antialiasing (MSAA) # A.K.A multi-sample antialiasing (MSAA)
# Smoothens out block edges but does not affect the insides of textures. # Smoothens out block edges but does not affect the insides of textures.
# A restart is required to change this option. # A restart is required to change this option.
@ -389,7 +415,6 @@
# Shaders allow advanced visual effects and may increase performance on some video # Shaders allow advanced visual effects and may increase performance on some video
# cards. # cards.
# This only works with the OpenGL video backend.
# type: bool # type: bool
# enable_shaders = true # enable_shaders = true
@ -488,6 +513,10 @@
### Post Processing ### Post Processing
# Enables the post processing pipeline.
# type: bool
# enable_post_processing = true
# Enables Hable's 'Uncharted 2' filmic tone mapping. # Enables Hable's 'Uncharted 2' filmic tone mapping.
# Simulates the tone curve of photographic film and how this approximates the # Simulates the tone curve of photographic film and how this approximates the
# appearance of high dynamic range images. Mid-range contrast is slightly # appearance of high dynamic range images. Mid-range contrast is slightly
@ -508,6 +537,16 @@
# type: float min: -1 max: 1 # type: float min: -1 max: 1
# exposure_compensation = 0.0 # exposure_compensation = 0.0
# Apply dithering to reduce color banding artifacts.
# Dithering significantly increases the size of losslessly-compressed
# screenshots and it works incorrectly if the display or operating system
# performs additional dithering or if the color channels are not quantized
# to 8 bits.
# With OpenGL ES, dithering only works if the shader supports high
# floating-point precision and it may have a higher performance impact.
# type: bool
# debanding = true
### Bloom ### Bloom
# Set to true to enable bloom effect. # Set to true to enable bloom effect.
@ -539,6 +578,10 @@
# type: float min: 0.1 max: 8 # type: float min: 0.1 max: 8
# bloom_radius = 1 # bloom_radius = 1
# Set to true to enable volumetric lighting effect (a.k.a. "Godrays").
# type: bool
# enable_volumetric_lighting = false
## Audio ## Audio
# Volume of all sounds. # Volume of all sounds.
@ -546,6 +589,10 @@
# type: float min: 0 max: 1 # type: float min: 0 max: 1
# sound_volume = 0.8 # sound_volume = 0.8
# Volume multiplier when the window is unfocused.
# type: float min: 0 max: 1
# sound_volume_unfocused = 0.3
# Whether to mute sounds. You can unmute sounds at any time, unless the # Whether to mute sounds. You can unmute sounds at any time, unless the
# sound system is disabled (enable_sound=false). # sound system is disabled (enable_sound=false).
# In-game, you can toggle the mute state with the mute key or by using the # In-game, you can toggle the mute state with the mute key or by using the
@ -555,7 +602,7 @@
## User Interfaces ## User Interfaces
# Set the language. Leave empty to use the system language. # Set the language. By default, the system language is used.
# A restart is required after changing this. # A restart is required after changing this.
# type: enum values: , be, bg, ca, cs, da, de, el, en, eo, es, et, eu, fi, fr, gd, gl, hu, id, it, ja, jbo, kk, ko, lt, lv, ms, nb, nl, nn, pl, pt, pt_BR, ro, ru, sk, sl, sr_Cyrl, sr_Latn, sv, sw, tr, uk, vi, zh_CN, zh_TW # type: enum values: , be, bg, ca, cs, da, de, el, en, eo, es, et, eu, fi, fr, gd, gl, hu, id, it, ja, jbo, kk, ko, lt, lv, ms, nb, nl, nn, pl, pt, pt_BR, ro, ru, sk, sl, sr_Cyrl, sr_Latn, sv, sw, tr, uk, vi, zh_CN, zh_TW
# language = # language =
@ -694,6 +741,7 @@
# enable_split_login_register = true # enable_split_login_register = true
# URL to JSON file which provides information about the newest Minetest release # URL to JSON file which provides information about the newest Minetest release
# If this is empty the engine will never check for updates.
# type: string # type: string
# update_information_url = https://www.minetest.net/release_info.json # update_information_url = https://www.minetest.net/release_info.json
@ -763,8 +811,8 @@
# Define the oldest clients allowed to connect. # Define the oldest clients allowed to connect.
# Older clients are compatible in the sense that they will not crash when connecting # 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. # to new servers, but they may not support all new features that you are expecting.
# This allows more fine-grained control than strict_protocol_version_checking. # This allows for more fine-grained control than strict_protocol_version_checking.
# Minetest may still enforce its own internal minimum, and enabling # Minetest still enforces its own internal minimum, and enabling
# strict_protocol_version_checking will effectively override this. # strict_protocol_version_checking will effectively override this.
# type: int min: 1 max: 65535 # type: int min: 1 max: 65535
# protocol_version_min = 1 # protocol_version_min = 1
@ -1186,8 +1234,9 @@
# The 'snowbiomes' flag enables the new 5 biome system. # The 'snowbiomes' flag enables the new 5 biome system.
# When the 'snowbiomes' flag is enabled jungles are automatically enabled and # When the 'snowbiomes' flag is enabled jungles are automatically enabled and
# the 'jungles' flag is ignored. # the 'jungles' flag is ignored.
# type: flags possible values: jungles, biomeblend, mudflow, snowbiomes, flat, trees, nojungles, nobiomeblend, nomudflow, nosnowbiomes, noflat, notrees # The 'temples' flag disables generation of desert temples. Normal dungeons will appear instead.
# mgv6_spflags = jungles,biomeblend,mudflow,snowbiomes,noflat,trees # type: flags possible values: jungles, biomeblend, mudflow, snowbiomes, flat, trees, temples, nojungles, nobiomeblend, nomudflow, nosnowbiomes, noflat, notrees, notemples
# mgv6_spflags = jungles,biomeblend,mudflow,snowbiomes,noflat,trees,temples
# Deserts occur when np_biome exceeds this value. # Deserts occur when np_biome exceeds this value.
# When the 'snowbiomes' flag is enabled, this is ignored. # When the 'snowbiomes' flag is enabled, this is ignored.
@ -2591,6 +2640,10 @@
# type: bool # type: bool
# random_input = false # random_input = false
# Enable random mod loading (mainly used for testing).
# type: bool
# random_mod_load_order = false
# Enable mod channels support. # Enable mod channels support.
# type: bool # type: bool
# enable_mod_channels = false # enable_mod_channels = false
@ -2673,8 +2726,8 @@
# The rendering back-end. # The rendering back-end.
# Note: A restart is required after changing this! # Note: A restart is required after changing this!
# OpenGL is the default for desktop, and OGLES2 for Android. # OpenGL is the default for desktop, and OGLES2 for Android.
# Shaders are supported by OpenGL and OGLES2 (experimental). # Shaders are supported by everything but OGLES1.
# type: enum values: , opengl, ogles1, ogles2 # type: enum values: , opengl, opengl3, ogles1, ogles2
# video_driver = # video_driver =
# Distance in nodes at which transparency depth sorting is enabled # Distance in nodes at which transparency depth sorting is enabled
@ -2682,11 +2735,6 @@
# type: int min: 0 max: 128 # type: int min: 0 max: 128
# transparency_sorting_distance = 16 # transparency_sorting_distance = 16
# Enable vertex buffer objects.
# This should greatly improve graphics performance.
# type: bool
# enable_vbo = true
# Radius of cloud area stated in number of 64 node cloud squares. # 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. # Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
# type: int min: 1 max: 62 # type: int min: 1 max: 62
@ -2710,12 +2758,6 @@
# type: int min: 0 max: 8 # type: int min: 0 max: 8
# mesh_generation_threads = 0 # mesh_generation_threads = 0
# Size of the MapBlock cache of the mesh generator. Increasing this will
# increase the cache hit %, reducing the data being copied from the main
# thread, thus reducing jitter.
# type: int min: 0 max: 1000
# meshgen_block_cache_size = 20
# True = 256 # True = 256
# False = 128 # False = 128
# Usable to make minimap smoother on slower machines. # Usable to make minimap smoother on slower machines.
@ -2759,6 +2801,17 @@
# type: int min: 1 max: 16 # type: int min: 1 max: 16
# client_mesh_chunk = 1 # client_mesh_chunk = 1
# Enables debug and error-checking in the OpenGL driver.
# type: bool
# opengl_debug = false
### Sound
# Comma-separated list of AL and ALC extensions that should not be used.
# Useful for testing. See al_extensions.[h,cpp] for details.
# type: string
# sound_extensions_blacklist =
### Font ### Font
# type: bool # type: bool
@ -2937,9 +2990,10 @@
### Server/Env Performance ### Server/Env Performance
# Length of a server tick and the interval at which objects are generally updated over # Length of a server tick (the interval at which everything is generally updated),
# network, stated in seconds. # stated in seconds.
# type: float min: 0 # Does not apply to sessions hosted from the client menu.
# type: float min: 0 max: 1
# dedicated_server_step = 0.09 # dedicated_server_step = 0.09
# Whether players are shown to clients without any range limit. # Whether players are shown to clients without any range limit.
@ -3027,12 +3081,11 @@
# At this distance the server will aggressively optimize which blocks are sent to # At this distance the server will aggressively optimize which blocks are sent to
# clients. # clients.
# Small values potentially improve performance a lot, at the expense of visible # Small values potentially improve performance a lot, at the expense of visible
# rendering glitches (some blocks will not be rendered under water and in caves, # rendering glitches (some blocks might not be rendered correctly in caves).
# as well as sometimes on land).
# Setting this to a value greater than max_block_send_distance disables this # Setting this to a value greater than max_block_send_distance disables this
# optimization. # optimization.
# Stated in mapblocks (16 nodes). # Stated in MapBlocks (16 nodes).
# type: int min: 2 max: 32767 # type: int min: 2 max: 2047
# block_send_optimize_distance = 4 # block_send_optimize_distance = 4
# If enabled, the server will perform map block occlusion culling based on # If enabled, the server will perform map block occlusion culling based on
@ -3042,6 +3095,14 @@
# type: bool # type: bool
# server_side_occlusion_culling = true # server_side_occlusion_culling = true
# At this distance the server will perform a simpler and cheaper occlusion check.
# Smaller values potentially improve performance, at the expense of temporarily visible
# rendering glitches (missing blocks).
# This is especially useful for very large viewing range (upwards of 500).
# Stated in MapBlocks (16 nodes).
# type: int min: 2 max: 2047
# block_cull_optimize_distance = 25
### Mapgen ### Mapgen
# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes). # Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).
@ -3104,10 +3165,6 @@
### Miscellaneous ### Miscellaneous
# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
# type: int min: 1
# screen_dpi = 72
# Adjust the detected display density, used for scaling UI elements. # Adjust the detected display density, used for scaling UI elements.
# type: float min: 0.5 max: 5 # type: float min: 0.5 max: 5
# display_density_factor = 1 # display_density_factor = 1
@ -3261,23 +3318,6 @@
# type: bool # type: bool
# enable_sound = true # enable_sound = true
# Unix timestamp (integer) of when the client last checked for an update
# Set this value to "disabled" to never check for updates.
# type: string
# update_last_checked =
# Version number which was last seen during an update check.
#
# Representation: MMMIIIPPP, where M=Major, I=Minor, P=Patch
# Ex: 5.5.0 is 005005000
# type: int
# update_last_known = 0
# If this is set to true, the user will never (again) be shown the
# "reinstall Minetest Game" notification.
# type: bool
# no_mtg_notification = false
# Key for moving the player forward. # Key for moving the player forward.
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h # See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key # type: key
@ -3417,6 +3457,11 @@
# type: key # type: key
# keymap_screenshot = KEY_F12 # keymap_screenshot = KEY_F12
# Key for toggling fullscreen mode.
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key
# keymap_fullscreen = KEY_F11
# Key for dropping the currently selected item. # Key for dropping the currently selected item.
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h # See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key # type: key
@ -3605,9 +3650,9 @@
# Key for toggling the display of fog. # Key for toggling the display of fog.
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h # See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key # type: key
# keymap_toggle_force_fog_off = KEY_F3 # keymap_toggle_fog = KEY_F3
# Key for toggling the camera update. Only used for development # Key for toggling the camera update. Only usable with 'debug' privilege.
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h # See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key # type: key
# keymap_toggle_update_camera = # keymap_toggle_update_camera =
@ -3622,6 +3667,11 @@
# type: key # type: key
# keymap_toggle_profiler = KEY_F6 # keymap_toggle_profiler = KEY_F6
# Key for toggling the display of mapblock boundaries.
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key
# keymap_toggle_block_bounds =
# Key for switching between first- and third-person camera. # Key for switching between first- and third-person camera.
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h # See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key # type: key
@ -3636,3 +3686,4 @@
# See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h # See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h
# type: key # type: key
# keymap_decrease_viewing_range_min = - # keymap_decrease_viewing_range_min = -

View File

@ -1,87 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>net.minetest.minetest.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>LGPL-2.1+ and CC-BY-SA-3.0 and MIT and Apache-2.0</project_license>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">mild</content_attribute>
<content_attribute id="violence-fantasy">mild</content_attribute>
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-info">mild</content_attribute>
</content_rating>
<name>Minetest</name>
<summary>Multiplayer infinite-world block sandbox game</summary>
<summary xml:lang="de">Mehrspieler-Sandkastenspiel mit unendlichen Blockwelten</summary>
<description>
<p>
Minetest is an infinite-world block sandbox game and game engine.
</p><p xml:lang="de">
Minetest ist ein Sandkastenspiel und eine Spielengine mit unendlichen Welten.
</p><p>
Players can create and destroy various types of blocks in a
three-dimensional open world. This allows forming structures in
every possible creation, on multiplayer servers or in singleplayer.
</p><p xml:lang="de">
Spieler können in einer offenen 3D-Welt viele verschiedene Arten von
Blöcken platzieren und abbauen. Dies erlaubt das Bauen von vielfältigen
Strukturen im Einzelspieler oder auf Mehrspielerservern.
</p><p>
Minetest is designed to be simple, stable, and portable.
It is lightweight enough to run on fairly old hardware.
</p><p xml:lang="de">
Minetest wurde entworfen, um einfach, stabil und portabel zu sein.
Es ist leichtgewichtig genug, um auf relativ alter Hardware zu laufen.
</p><p>
Minetest has many features, including:
</p><p xml:lang="de">
Minetest besitzt viele Features, unter anderem:
</p>
<ul>
<li>Ability to walk around, dig, and build in a near-infinite voxel world</li>
<li xml:lang="de">Die Möglichkeit, in einer nahezu unendlichen Voxel-Welt herumzulaufen, zu graben und zu bauen</li>
<li>Crafting of items from raw materials</li>
<li xml:lang="de">Fertigen von Items aus Rohmaterialien</li>
<li>Fast and able to run on old and slow hardware</li>
<li xml:lang="de">Gute Performance selbst auf älterer und langsamer Hardware</li>
<li>A simple modding API that supports many additions and modifications to the game</li>
<li xml:lang="de">Eine einfache Modding-API, die viele Ergänzungen und Änderungen am Spiel unterstützt</li>
<li>Multiplayer support via servers hosted by users</li>
<li xml:lang="de">Mehrspieler auf selber gehosteten Servern</li>
<li>Beautiful lightning-fast map generator</li>
<li xml:lang="de">Wunderschöner, blitzschneller Kartengenerator</li>
</ul>
</description>
<screenshots>
<screenshot type="default">
<image>http://www.minetest.net/media/gallery/1.jpg</image>
</screenshot>
<screenshot>
<image>http://www.minetest.net/media/gallery/3.jpg</image>
</screenshot>
<screenshot>
<image>http://www.minetest.net/media/gallery/5.jpg</image>
</screenshot>
</screenshots>
<keywords>
<keyword>sandbox</keyword>
<keyword>world</keyword>
<keyword>mining</keyword>
<keyword>multiplayer</keyword>
</keywords>
<url type="homepage">https://www.minetest.net</url>
<url type="bugtracker">https://www.minetest.net/development/#reporting-issues</url>
<url type="translate">https://dev.minetest.net/Translation</url>
<url type="donation">https://www.minetest.net/development/#donate</url>
<url type="faq">https://wiki.minetest.net/FAQ</url>
<url type="help">https://wiki.minetest.net</url>
<url type="vcs-browser">https://github.com/minetest/minetest</url>
<url type="contribute">https://www.minetest.net/get-involved/</url>
<provides>
<binary>minetest</binary>
</provides>
<translation type="gettext">minetest</translation>
<update_contact>sfan5@live.de</update_contact>
<releases>
<release date="2023-12-04" version="5.8.0"/>
</releases>
</component>

View File

@ -1,13 +1,9 @@
[Desktop Entry] [Desktop Entry]
Name=Minetest Name=Minetest
GenericName=Minetest GenericName=Minetest
Comment=Multiplayer infinite-world block sandbox Comment=Block-based multiplayer game platform
Comment[de]=Mehrspieler-Sandkastenspiel mit unendlichen Blockwelten Comment[de]=Blockbasierte Mehrspieler-Spieleplattform
Comment[es]=Juego sandbox multijugador con mundos infinitos Comment[fr]=Plate-forme de jeu multijoueurs à base de blocs
Comment[fr]=Jeu multijoueurs de type bac à sable avec des mondes infinis
Comment[ja]=
Comment[ru]=Игра-песочница с безграничным миром, состоящим из блоков
Comment[tr]=Tek-Çok oyuncuyla küplerden sonsuz dünyalar inşa et
Exec=minetest Exec=minetest
Icon=minetest Icon=minetest
Terminal=false Terminal=false

View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>net.minetest.minetest</id>
<name>Minetest</name>
<summary>Block-based multiplayer game platform</summary>
<summary xml:lang="de">Blockbasierte Mehrspieler-Spieleplattform</summary>
<summary xml:lang="fr">Plate-forme de jeu multijoueurs à base de blocs</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>LGPL-2.1+ AND CC-BY-SA-3.0 AND MIT AND Apache-2.0</project_license>
<developer id="net.minetest">
<name>Minetest Team</name>
</developer>
<supports>
<control>pointing</control>
<control>keyboard</control>
<control>touch</control>
<internet>offline-only</internet>
</supports>
<requires>
<display_length compare="ge">360</display_length>
</requires>
<content_rating type="oars-1.0">
<content_attribute id="violence-cartoon">mild</content_attribute>
<content_attribute id="violence-fantasy">mild</content_attribute>
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-info">mild</content_attribute>
</content_rating>
<description>
<p>
Minetest is a block-based sandbox game platform.
</p>
<p xml:lang="de">
Minetest ist eine blockbasierte Sandbox-Spielplattform.
</p>
<p xml:lang="fr">
Minetest est une plateforme de jeu de type bac à sable à base de blocs.
</p>
<p>
Players can create and destroy various types of blocks in a
three-dimensional open world. This allows forming structures in
every possible creation, on multiplayer servers or in singleplayer.
</p>
<p xml:lang="de">
Spieler können in einer offenen 3D-Welt viele verschiedene Arten von
Blöcken platzieren und abbauen. Dies erlaubt das Bauen von vielfältigen
Strukturen im Einzelspieler oder auf Mehrspielerservern.
</p>
<p xml:lang="fr">
Les joueurs peuvent créer et détruire différents types de blocs dans un
monde ouvert tridimensionnel. Cela permet de créer des structures de toutes les
formes possibles, sur des serveurs multijoueurs ou en solo.
</p>
<p>
Minetest is designed to be simple, stable, and portable.
It is lightweight enough to run on fairly old hardware.
</p>
<p xml:lang="de">
Minetest wurde entworfen, um einfach, stabil und portabel zu sein.
Es ist leichtgewichtig genug, um auf relativ alter Hardware zu laufen.
</p>
<p xml:lang="fr">
Minetest est conçu pour être simple, stable et portable.
Il est suffisamment léger pour fonctionner sur du matériel relativement ancien.
</p>
<p>
Minetest has many features, including:
</p>
<p xml:lang="de">
Minetest besitzt viele Features, unter anderem:
</p>
<p xml:lang="fr">
Minetest offre de nombreuses fonctionnalités, notamment :
</p>
<ul>
<li>Ability to walk around, dig, and build in a near-infinite voxel world</li>
<li xml:lang="de">Die Möglichkeit, in einer nahezu unendlichen Voxel-Welt herumzulaufen, zu graben und zu
bauen
</li>
<li xml:lang="fr">La possibilité de se promener, de creuser et de construire dans un monde voxel quasi-infini
</li>
<li>Crafting of items from raw materials</li>
<li xml:lang="de">Fertigen von Items aus Rohmaterialien</li>
<li xml:lang="fr">Fabrication d'objets à partir de matières premières</li>
<li>A simple modding API that supports many additions and modifications to the game</li>
<li xml:lang="de">Eine einfache Modding-API, die viele Ergänzungen und Änderungen am Spiel unterstützt</li>
<li xml:lang="fr">Une API de modding simple qui permet de nombreux ajouts et modifications au jeu</li>
<li>Multiplayer support via servers hosted by users</li>
<li xml:lang="de">Mehrspieler auf selber gehosteten Servern</li>
<li xml:lang="fr">Prise en charge du multijoueur via des serveurs hébergés par les utilisateurs</li>
<li>Beautiful lightning-fast map generator</li>
<li xml:lang="de">Wunderschöner, blitzschneller Kartengenerator</li>
<li xml:lang="fr">Générateur de cartes très rapide</li>
</ul>
</description>
<launchable type="desktop-id">net.minetest.minetest.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>https://www.minetest.net/media/gallery/1.jpg</image>
</screenshot>
<screenshot>
<image>https://www.minetest.net/media/gallery/3.jpg</image>
</screenshot>
<screenshot>
<image>https://www.minetest.net/media/gallery/5.jpg</image>
</screenshot>
</screenshots>
<icon type="stock">minetest</icon>
<categories>
<category>Game</category>
<category>Simulation</category>
</categories>
<keywords>
<keyword>sandbox</keyword>
<keyword>world</keyword>
<keyword>mining</keyword>
<keyword>crafting</keyword>
<keyword>blocks</keyword>
<keyword>nodes</keyword>
<keyword>multiplayer</keyword>
<keyword>roleplaying</keyword>
</keywords>
<url type="homepage">https://www.minetest.net</url>
<url type="bugtracker">https://www.minetest.net/get-involved/#reporting-issues</url>
<url type="translate">https://dev.minetest.net/Translation</url>
<url type="donation">https://www.minetest.net/get-involved/#donate</url>
<url type="faq">https://wiki.minetest.net/FAQ</url>
<url type="help">https://wiki.minetest.net</url>
<url type="vcs-browser">https://github.com/minetest/minetest</url>
<url type="contribute">https://www.minetest.net/get-involved</url>
<provides>
<binary>minetest</binary>
</provides>
<translation type="gettext">minetest</translation>
<update_contact>celeron55@gmail.com</update_contact>
<releases>
<release date="2023-12-04" version="5.8.0"/>
</releases>
</component>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6256
po/kv/minetest.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: minetest\n" "Project-Id-Version: minetest\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-03 18:48+0100\n" "POT-Creation-Date: 2024-07-11 15:14+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -79,14 +79,14 @@ msgid "Command not available: "
msgstr "" msgstr ""
#: builtin/common/chatcommands.lua #: builtin/common/chatcommands.lua
msgid "[all | <cmd>]" msgid "[all | <cmd>] [-t]"
msgstr "" msgstr ""
#: builtin/common/chatcommands.lua #: builtin/common/chatcommands.lua
msgid "Get help for commands" msgid "Get help for commands (-t: output in chat)"
msgstr "" msgstr ""
#: builtin/fstk/dialog.lua builtin/fstk/ui.lua src/gui/modalMenu.cpp #: builtin/fstk/ui.lua
msgid "OK" msgid "OK"
msgstr "" msgstr ""
@ -134,175 +134,182 @@ msgstr ""
msgid "Protocol version mismatch. " msgid "Protocol version mismatch. "
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/contentdb.lua
msgid "ContentDB is not available when Minetest was compiled without cURL"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "All packages"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Games"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Mods"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Texture packs"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Failed to download \"$1\"" msgid "Failed to download \"$1\""
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/contentdb.lua
msgid "Failed to extract \"$1\" (unsupported file type or broken archive)" msgid ""
"Failed to extract \"$1\" (insufficient disk space, unsupported file type or "
"broken archive)"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/contentdb.lua
msgid "Error installing \"$1\": $2" msgid "Error installing \"$1\": $2"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/contentdb.lua
msgid "Failed to download $1" msgid "Failed to download $1"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "Already installed" msgid "ContentDB is not available when Minetest was compiled without cURL"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "$1 by $2" msgid "All packages"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "Not found" msgid "Games"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "$1 and $2 dependencies will be installed." msgid "Mods"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "$1 will be installed, and $2 dependencies will be skipped." msgid "Texture packs"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "$1 required dependencies could not be found." msgid "Error getting dependencies for package"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "Please check that the base game is correct."
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Install $1"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Base Game:"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/tab_content.lua
msgid "Dependencies:"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Install missing dependencies"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Install"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/dlg_create_world.lua
#: builtin/mainmenu/dlg_delete_content.lua
#: builtin/mainmenu/dlg_delete_world.lua builtin/mainmenu/dlg_register.lua
#: builtin/mainmenu/dlg_rename_modpack.lua
#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua
#: src/gui/guiKeyChangeMenu.cpp src/gui/guiPasswordChange.cpp
msgid "Cancel"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "\"$1\" already exists. Would you like to overwrite it?"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "Overwrite"
msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua
msgid "You need to install a game before you can install a mod" msgid "You need to install a game before you can install a mod"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "The package $1 was not found." msgid "The package $1 was not found."
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "Back to Main Menu" msgid "Back to Main Menu"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
#: builtin/mainmenu/serverlistmgr.lua src/client/game.cpp #: builtin/mainmenu/serverlistmgr.lua src/client/game.cpp
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "No packages could be retrieved" msgid "No packages could be retrieved"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "" msgid ""
"$1 downloading,\n" "$1 downloading,\n"
"$2 queued" "$2 queued"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "$1 downloading..." msgid "$1 downloading..."
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "No updates" msgid "No updates"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "Update All [$1]" msgid "Update All [$1]"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
#: builtin/mainmenu/settings/dlg_settings.lua #: builtin/mainmenu/settings/dlg_settings.lua
msgid "No results" msgid "No results"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "Downloading..." msgid "Downloading..."
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "Queued" msgid "Queued"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
#: builtin/mainmenu/tab_content.lua #: builtin/mainmenu/content/dlg_install.lua
msgid "Install"
msgstr ""
#: builtin/mainmenu/content/dlg_contentdb.lua builtin/mainmenu/tab_content.lua
msgid "Update" msgid "Update"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua builtin/mainmenu/tab_content.lua
#: builtin/mainmenu/tab_content.lua
msgid "Uninstall" msgid "Uninstall"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_contentstore.lua #: builtin/mainmenu/content/dlg_contentdb.lua
msgid "View more information in a web browser" msgid "View more information in a web browser"
msgstr "" msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "Already installed"
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "$1 by $2"
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "Not found"
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "$1 and $2 dependencies will be installed."
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "$1 will be installed, and $2 dependencies will be skipped."
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "$1 required dependencies could not be found."
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "Please check that the base game is correct."
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "Install $1"
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "Base Game:"
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/tab_content.lua
msgid "Dependencies:"
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
msgid "Install missing dependencies"
msgstr ""
#: builtin/mainmenu/content/dlg_install.lua
#: builtin/mainmenu/content/dlg_overwrite.lua
#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/dlg_create_world.lua
#: builtin/mainmenu/dlg_delete_content.lua
#: builtin/mainmenu/dlg_delete_world.lua builtin/mainmenu/dlg_register.lua
#: builtin/mainmenu/dlg_rename_modpack.lua
#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua
#: src/gui/guiKeyChangeMenu.cpp src/gui/guiOpenURL.cpp
#: src/gui/guiPasswordChange.cpp
msgid "Cancel"
msgstr ""
#: builtin/mainmenu/content/dlg_overwrite.lua
msgid "\"$1\" already exists. Would you like to overwrite it?"
msgstr ""
#: builtin/mainmenu/content/dlg_overwrite.lua
msgid "Overwrite"
msgstr ""
#: builtin/mainmenu/content/pkgmgr.lua #: builtin/mainmenu/content/pkgmgr.lua
msgid "$1 (Enabled)" msgid "$1 (Enabled)"
msgstr "" msgstr ""
@ -499,6 +506,16 @@ msgstr ""
msgid "Terrain surface erosion" msgid "Terrain surface erosion"
msgstr "" msgstr ""
#: builtin/mainmenu/dlg_create_world.lua
msgid "Desert temples"
msgstr ""
#: builtin/mainmenu/dlg_create_world.lua
msgid ""
"Different dungeon variant generated in desert biomes (only if dungeons "
"enabled)"
msgstr ""
#: builtin/mainmenu/dlg_create_world.lua #: builtin/mainmenu/dlg_create_world.lua
msgid "Temperate, Desert, Jungle, Tundra, Taiga" msgid "Temperate, Desert, Jungle, Tundra, Taiga"
msgstr "" msgstr ""
@ -801,27 +818,24 @@ msgstr ""
msgid "(No description of setting given)" msgid "(No description of setting given)"
msgstr "" msgstr ""
#: builtin/mainmenu/settings/dlg_settings.lua src/settings_translation_file.cpp
msgid "General"
msgstr ""
#: builtin/mainmenu/settings/dlg_settings.lua src/client/game.cpp #: builtin/mainmenu/settings/dlg_settings.lua src/client/game.cpp
msgid "Change Keys" #: src/settings_translation_file.cpp
msgid "Controls"
msgstr "" msgstr ""
#: builtin/mainmenu/settings/dlg_settings.lua #: builtin/mainmenu/settings/dlg_settings.lua
msgid "Accessibility" msgid "Accessibility"
msgstr "" msgstr ""
#: builtin/mainmenu/settings/dlg_settings.lua src/settings_translation_file.cpp
msgid "General"
msgstr ""
#: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp #: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Chat" msgid "Chat"
msgstr "" msgstr ""
#: builtin/mainmenu/settings/dlg_settings.lua src/settings_translation_file.cpp
msgid "Controls"
msgstr ""
#: builtin/mainmenu/settings/dlg_settings.lua #: builtin/mainmenu/settings/dlg_settings.lua
msgid "Movement" msgid "Movement"
msgstr "" msgstr ""
@ -1002,7 +1016,17 @@ msgid "Install games from ContentDB"
msgstr "" msgstr ""
#: builtin/mainmenu/tab_local.lua #: builtin/mainmenu/tab_local.lua
msgid "You have no games installed." msgid ""
"Minetest is a game-creation platform that allows you to play many different "
"games."
msgstr ""
#: builtin/mainmenu/tab_local.lua
msgid "Minetest doesn't come with a game by default."
msgstr ""
#: builtin/mainmenu/tab_local.lua
msgid "You need to install a game before you can create a world."
msgstr "" msgstr ""
#: builtin/mainmenu/tab_local.lua #: builtin/mainmenu/tab_local.lua
@ -1146,10 +1170,6 @@ msgstr ""
msgid "Main Menu" msgid "Main Menu"
msgstr "" msgstr ""
#: src/client/clientlauncher.cpp
msgid "Connection error (timed out?)"
msgstr ""
#: src/client/clientlauncher.cpp #: src/client/clientlauncher.cpp
msgid "Provided password file failed to open: " msgid "Provided password file failed to open: "
msgstr "" msgstr ""
@ -1174,8 +1194,8 @@ msgstr ""
msgid "Could not find or load game: " msgid "Could not find or load game: "
msgstr "" msgstr ""
#: src/client/clientlauncher.cpp #: src/client/clientmedia.cpp src/client/game.cpp
msgid "Invalid gamespec." msgid "Media..."
msgstr "" msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
@ -1247,10 +1267,6 @@ msgstr ""
msgid "Node definitions..." msgid "Node definitions..."
msgstr "" msgstr ""
#: src/client/game.cpp
msgid "Media..."
msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "KiB/s" msgid "KiB/s"
msgstr "" msgstr ""
@ -1284,10 +1300,6 @@ msgstr ""
msgid "Sound system is not supported on this build" msgid "Sound system is not supported on this build"
msgstr "" msgstr ""
#: src/client/game.cpp
msgid "ok"
msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Fly mode enabled" msgid "Fly mode enabled"
msgstr "" msgstr ""
@ -1356,10 +1368,6 @@ msgstr ""
msgid "Block bounds shown for nearby blocks" msgid "Block bounds shown for nearby blocks"
msgstr "" msgstr ""
#: src/client/game.cpp
msgid "Block bounds shown for all blocks"
msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Automatic forward enabled" msgid "Automatic forward enabled"
msgstr "" msgstr ""
@ -1373,13 +1381,17 @@ msgid "Minimap currently disabled by game or mod"
msgstr "" msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Fog disabled" msgid "Fog enabled by game or mod"
msgstr "" msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Fog enabled" msgid "Fog enabled"
msgstr "" msgstr ""
#: src/client/game.cpp
msgid "Fog disabled"
msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Debug info shown" msgid "Debug info shown"
msgstr "" msgstr ""
@ -1460,8 +1472,8 @@ msgid ""
"Controls:\n" "Controls:\n"
"No menu open:\n" "No menu open:\n"
"- slide finger: look around\n" "- slide finger: look around\n"
"- tap: place/use\n" "- tap: place/punch/use (default)\n"
"- long tap: dig/punch/use\n" "- long tap: dig/use (default)\n"
"Menu/inventory open:\n" "Menu/inventory open:\n"
"- double tap (outside):\n" "- double tap (outside):\n"
" --> close\n" " --> close\n"
@ -1471,25 +1483,6 @@ msgid ""
" --> place single item to slot\n" " --> place single item to slot\n"
msgstr "" msgstr ""
#: src/client/game.cpp
#, c-format
msgid ""
"Controls:\n"
"- %s: move forwards\n"
"- %s: move backwards\n"
"- %s: move left\n"
"- %s: move right\n"
"- %s: jump/climb up\n"
"- %s: dig/punch/use\n"
"- %s: place/use\n"
"- %s: sneak/climb down\n"
"- %s: drop item\n"
"- %s: inventory\n"
"- Mouse: turn/look\n"
"- Mouse wheel: select item\n"
"- %s: chat\n"
msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Continue" msgid "Continue"
msgstr "" msgstr ""
@ -1522,20 +1515,12 @@ msgstr ""
msgid "- Mode: " msgid "- Mode: "
msgstr "" msgstr ""
#: src/client/game.cpp
msgid "Remote server"
msgstr ""
#: src/client/game.cpp
msgid "- Address: "
msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Hosting server" msgid "Hosting server"
msgstr "" msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "- Port: " msgid "Remote server"
msgstr "" msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
@ -1568,12 +1553,16 @@ msgstr ""
msgid "A serialization error occurred:" msgid "A serialization error occurred:"
msgstr "" msgstr ""
#: src/client/game.cpp src/server.cpp #: src/client/game.cpp src/client/shader.cpp src/server.cpp
msgid "" msgid ""
"\n" "\n"
"Check debug.txt for details." "Check debug.txt for details."
msgstr "" msgstr ""
#: src/client/game.cpp
msgid "Connection error (timed out?)"
msgstr ""
#: src/client/gameui.cpp #: src/client/gameui.cpp
msgid "Chat shown" msgid "Chat shown"
msgstr "" msgstr ""
@ -1894,6 +1883,15 @@ msgstr ""
msgid "Minimap in texture mode" msgid "Minimap in texture mode"
msgstr "" msgstr ""
#: src/client/shader.cpp
msgid "Shaders are enabled but GLSL is not supported by the driver."
msgstr ""
#: src/client/shader.cpp
#, c-format
msgid "Failed to compile the \"%s\" shader."
msgstr ""
#: src/content/mod_configuration.cpp #: src/content/mod_configuration.cpp
msgid "Some mods have unsatisfied dependencies:" msgid "Some mods have unsatisfied dependencies:"
msgstr "" msgstr ""
@ -2083,6 +2081,18 @@ msgstr ""
msgid "Toggle fog" msgid "Toggle fog"
msgstr "" msgstr ""
#: src/gui/guiOpenURL.cpp
msgid "Open URL?"
msgstr ""
#: src/gui/guiOpenURL.cpp
msgid "Unable to open URL"
msgstr ""
#: src/gui/guiOpenURL.cpp
msgid "Open"
msgstr ""
#: src/gui/guiPasswordChange.cpp #: src/gui/guiPasswordChange.cpp
msgid "Old Password" msgid "Old Password"
msgstr "" msgstr ""
@ -2125,6 +2135,7 @@ msgstr ""
#. This is a special string which needs to contain the translation's #. This is a special string which needs to contain the translation's
#. language code (e.g. "de" for German). #. language code (e.g. "de" for German).
#: src/network/clientpackethandler.cpp src/script/lua_api/l_client.cpp #: src/network/clientpackethandler.cpp src/script/lua_api/l_client.cpp
#: src/script/lua_api/l_mainmenu.cpp
msgid "LANG_CODE" msgid "LANG_CODE"
msgstr "" msgstr ""
@ -2150,7 +2161,7 @@ msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "" msgid ""
"Smooths rotation of camera when in cinematic mode, 0 to disable. Enter " "Smooths rotation of camera when in cinematic mode, 0 to disable. Enter "
"cinematic mode by using the key set in Change Keys." "cinematic mode by using the key set in Controls."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -2203,6 +2214,16 @@ msgid ""
"the place button." "the place button."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Minimum dig repetition interval"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"The minimum time in seconds it takes between digging nodes when holding\n"
"the dig button."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Automatically jump up single-node obstacles." msgid "Automatically jump up single-node obstacles."
msgstr "" msgstr ""
@ -2260,11 +2281,12 @@ msgid "Touchscreen"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Touchscreen threshold" msgid "Enable touchscreen"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "The length in pixels it takes for touchscreen interaction to start." msgid ""
"Enables touchscreen mode, allowing you to play the game with a touchscreen."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -2275,6 +2297,25 @@ msgstr ""
msgid "Touchscreen sensitivity multiplier." msgid "Touchscreen sensitivity multiplier."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Movement threshold"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"The length in pixels after which a touch interaction is considered movement."
msgstr ""
#: src/settings_translation_file.cpp
msgid "Threshold for long taps"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"The delay in milliseconds after which a touch interaction is considered a "
"long tap."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Use crosshair for touch screen" msgid "Use crosshair for touch screen"
msgstr "" msgstr ""
@ -2306,6 +2347,23 @@ msgid ""
"circle." "circle."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Punch gesture"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"The gesture for for punching players/entities.\n"
"This can be overridden by games and mods.\n"
"\n"
"* short_tap\n"
"Easy to use and well-known from other games that shall not be named.\n"
"\n"
"* long_tap\n"
"Known from the classic Minetest mobile controls.\n"
"Combat is more or less impossible."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Graphics and Audio" msgid "Graphics and Audio"
msgstr "" msgstr ""
@ -2432,11 +2490,11 @@ msgid "Graphics Effects"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Opaque liquids" msgid "Translucent liquids"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Makes all liquids opaque" msgid "Allows liquids to be translucent."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -2771,8 +2829,8 @@ msgid ""
"\n" "\n"
"* None - No antialiasing (default)\n" "* None - No antialiasing (default)\n"
"\n" "\n"
"* FSAA - Hardware-provided full-screen antialiasing (incompatible with " "* FSAA - Hardware-provided full-screen antialiasing\n"
"shaders)\n" "(incompatible with Post Processing and Undersampling)\n"
"A.K.A multi-sample antialiasing (MSAA)\n" "A.K.A multi-sample antialiasing (MSAA)\n"
"Smoothens out block edges but does not affect the insides of textures.\n" "Smoothens out block edges but does not affect the insides of textures.\n"
"A restart is required to change this option.\n" "A restart is required to change this option.\n"
@ -2835,8 +2893,7 @@ msgstr ""
msgid "" msgid ""
"Shaders allow advanced visual effects and may increase performance on some " "Shaders allow advanced visual effects and may increase performance on some "
"video\n" "video\n"
"cards.\n" "cards."
"This only works with the OpenGL video backend."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -3012,6 +3069,14 @@ msgstr ""
msgid "Post Processing" msgid "Post Processing"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Enable Post Processing"
msgstr ""
#: src/settings_translation_file.cpp
msgid "Enables the post processing pipeline."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Filmic tone mapping" msgid "Filmic tone mapping"
msgstr "" msgstr ""
@ -3047,6 +3112,21 @@ msgid ""
"Range: from -1 to 1.0" "Range: from -1 to 1.0"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Enable Debanding"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"Apply dithering to reduce color banding artifacts.\n"
"Dithering significantly increases the size of losslessly-compressed\n"
"screenshots and it works incorrectly if the display or operating system\n"
"performs additional dithering or if the color channels are not quantized\n"
"to 8 bits.\n"
"With OpenGL ES, dithering only works if the shader supports high\n"
"floating-point precision and it may have a higher performance impact."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Bloom" msgid "Bloom"
msgstr "" msgstr ""
@ -3105,6 +3185,14 @@ msgid ""
"Range: from 0.1 to 8, default: 1" "Range: from 0.1 to 8, default: 1"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Volumetric lighting"
msgstr ""
#: src/settings_translation_file.cpp
msgid "Set to true to enable volumetric lighting effect (a.k.a. \"Godrays\")."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Audio" msgid "Audio"
msgstr "" msgstr ""
@ -3119,6 +3207,14 @@ msgid ""
"Requires the sound system to be enabled." "Requires the sound system to be enabled."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Volume when unfocused"
msgstr ""
#: src/settings_translation_file.cpp
msgid "Volume multiplier when the window is unfocused."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Mute sound" msgid "Mute sound"
msgstr "" msgstr ""
@ -3141,7 +3237,7 @@ msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "" msgid ""
"Set the language. Leave empty to use the system language.\n" "Set the language. By default, the system language is used.\n"
"A restart is required after changing this." "A restart is required after changing this."
msgstr "" msgstr ""
@ -3403,7 +3499,9 @@ msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "" msgid ""
"URL to JSON file which provides information about the newest Minetest release" "URL to JSON file which provides information about the newest Minetest "
"release\n"
"If this is empty the engine will never check for updates."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -3531,6 +3629,23 @@ msgid ""
"expecting." "expecting."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Protocol version minimum"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"Define the oldest clients allowed to connect.\n"
"Older clients are compatible in the sense that they will not crash when "
"connecting\n"
"to new servers, but they may not support all new features that you are "
"expecting.\n"
"This allows for more fine-grained control than "
"strict_protocol_version_checking.\n"
"Minetest still enforces its own internal minimum, and enabling\n"
"strict_protocol_version_checking will effectively override this."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Remote media" msgid "Remote media"
msgstr "" msgstr ""
@ -4124,7 +4239,9 @@ msgid ""
"Map generation attributes specific to Mapgen v6.\n" "Map generation attributes specific to Mapgen v6.\n"
"The 'snowbiomes' flag enables the new 5 biome system.\n" "The 'snowbiomes' flag enables the new 5 biome system.\n"
"When the 'snowbiomes' flag is enabled jungles are automatically enabled and\n" "When the 'snowbiomes' flag is enabled jungles are automatically enabled and\n"
"the 'jungles' flag is ignored." "the 'jungles' flag is ignored.\n"
"The 'temples' flag disables generation of desert temples. Normal dungeons "
"will appear instead."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -4960,6 +5077,14 @@ msgstr ""
msgid "Enable random user input (only used for testing)." msgid "Enable random user input (only used for testing)."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Random mod load order"
msgstr ""
#: src/settings_translation_file.cpp
msgid "Enable random mod loading (mainly used for testing)."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Mod channels" msgid "Mod channels"
msgstr "" msgstr ""
@ -5122,7 +5247,7 @@ msgid ""
"The rendering back-end.\n" "The rendering back-end.\n"
"Note: A restart is required after changing this!\n" "Note: A restart is required after changing this!\n"
"OpenGL is the default for desktop, and OGLES2 for Android.\n" "OpenGL is the default for desktop, and OGLES2 for Android.\n"
"Shaders are supported by OpenGL and OGLES2 (experimental)." "Shaders are supported by everything but OGLES1."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -5135,16 +5260,6 @@ msgid ""
"Use this to limit the performance impact of transparency depth sorting" "Use this to limit the performance impact of transparency depth sorting"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "VBO"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"Enable vertex buffer objects.\n"
"This should greatly improve graphics performance."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Cloud radius" msgid "Cloud radius"
msgstr "" msgstr ""
@ -5193,17 +5308,6 @@ msgid ""
"threads." "threads."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Mapblock mesh generator's MapBlock cache size in MB"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"Size of the MapBlock cache of the mesh generator. Increasing this will\n"
"increase the cache hit %, reducing the data being copied from the main\n"
"thread, thus reducing jitter."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Minimap scan height" msgid "Minimap scan height"
msgstr "" msgstr ""
@ -5272,6 +5376,28 @@ msgid ""
"Systems with a low-end GPU (or no GPU) would benefit from smaller values." "Systems with a low-end GPU (or no GPU) would benefit from smaller values."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "OpenGL debug"
msgstr ""
#: src/settings_translation_file.cpp
msgid "Enables debug and error-checking in the OpenGL driver."
msgstr ""
#: src/settings_translation_file.cpp
msgid "Sound"
msgstr ""
#: src/settings_translation_file.cpp
msgid "Sound Extensions Blacklist"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"Comma-separated list of AL and ALC extensions that should not be used.\n"
"Useful for testing. See al_extensions.[h,cpp] for details."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Font" msgid "Font"
msgstr "" msgstr ""
@ -5601,9 +5727,10 @@ msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "" msgid ""
"Length of a server tick and the interval at which objects are generally " "Length of a server tick (the interval at which everything is generally "
"updated over\n" "updated),\n"
"network, stated in seconds." "stated in seconds.\n"
"Does not apply to sessions hosted from the client menu."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -5781,12 +5908,10 @@ msgid ""
"clients.\n" "clients.\n"
"Small values potentially improve performance a lot, at the expense of " "Small values potentially improve performance a lot, at the expense of "
"visible\n" "visible\n"
"rendering glitches (some blocks will not be rendered under water and in " "rendering glitches (some blocks might not be rendered correctly in caves).\n"
"caves,\n"
"as well as sometimes on land).\n"
"Setting this to a value greater than max_block_send_distance disables this\n" "Setting this to a value greater than max_block_send_distance disables this\n"
"optimization.\n" "optimization.\n"
"Stated in mapblocks (16 nodes)." "Stated in MapBlocks (16 nodes)."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
@ -5801,6 +5926,21 @@ msgid ""
"invisible blocks, so that the utility of noclip mode is reduced." "invisible blocks, so that the utility of noclip mode is reduced."
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "Block cull optimize distance"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"At this distance the server will perform a simpler and cheaper occlusion "
"check.\n"
"Smaller values potentially improve performance, at the expense of "
"temporarily visible\n"
"rendering glitches (missing blocks).\n"
"This is especially useful for very large viewing range (upwards of 500).\n"
"Stated in MapBlocks (16 nodes)."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Chunk size" msgid "Chunk size"
msgstr "" msgstr ""
@ -5910,16 +6050,6 @@ msgstr ""
msgid "Miscellaneous" msgid "Miscellaneous"
msgstr "" msgstr ""
#: src/settings_translation_file.cpp
msgid "DPI"
msgstr ""
#: src/settings_translation_file.cpp
msgid ""
"Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k "
"screens."
msgstr ""
#: src/settings_translation_file.cpp #: src/settings_translation_file.cpp
msgid "Display Density Scaling Factor" msgid "Display Density Scaling Factor"
msgstr "" msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6196
po/tok/minetest.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -420,12 +420,11 @@ void blit_pixel(video::SColor src_col, video::SColor &dst_col)
return; return;
} }
// A semi-transparent pixel is on top of a // A semi-transparent pixel is on top of a
// semi-transparent pixel -> general alpha compositing // semi-transparent pixel -> weird overlaying
u16 a_new_255 = src_a * 255 + (255 - src_a) * dst_a; dst.r = (dst.r * (255 - src_a) + src.r * src_a) / 255;
dst.r = (dst.r * (255 - src_a) * dst_a + src.r * src_a * 255) / a_new_255; dst.g = (dst.g * (255 - src_a) + src.g * src_a) / 255;
dst.g = (dst.g * (255 - src_a) * dst_a + src.g * src_a * 255) / a_new_255; dst.b = (dst.b * (255 - src_a) + src.b * src_a) / 255;
dst.b = (dst.b * (255 - src_a) * dst_a + src.b * src_a * 255) / a_new_255; dst_a = dst_a + (255 - dst_a) * src_a * src_a / (255 * 255);
dst_a = (a_new_255 + 127) / 255;
dst_col.set(dst_a, dst.r, dst.g, dst.b); dst_col.set(dst_a, dst.r, dst.g, dst.b);
} }

View File

@ -32,9 +32,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <hiredis.h> #include <hiredis.h>
#include <cassert> #include <cassert>
#if VERSION_MAJOR > 5 || VERSION_MINOR > 9 /*
#define DEPRECATION_PERIOD_OVER * Redis is not a good fit for Minetest and only still supported for legacy as
#endif * well as advanced use case reasons, see:
* <https://github.com/minetest/minetest/issues/14822>
*
* Do NOT extend this backend with any new functionality.
*/
Database_Redis::Database_Redis(Settings &conf) Database_Redis::Database_Redis(Settings &conf)
{ {
@ -70,13 +74,8 @@ Database_Redis::Database_Redis(Settings &conf)
freeReplyObject(reply); freeReplyObject(reply);
} }
warningstream << "/!\\ You are using the deprecated redis backend. " dstream << "Note: When storing data in Redis you need to ensure that eviction"
#ifdef DEPRECATION_PERIOD_OVER " is disabled, or you risk DATA LOSS." << std::endl;
<< "This backend is only still supported for migrations. /!\\\n"
#else
<< "This backend will become read-only in the next release. /!\\\n"
#endif
<< "Please migrate to SQLite3 or PostgreSQL instead." << std::endl;
} }
Database_Redis::~Database_Redis() Database_Redis::~Database_Redis()
@ -86,16 +85,12 @@ Database_Redis::~Database_Redis()
void Database_Redis::beginSave() void Database_Redis::beginSave()
{ {
#ifdef DEPRECATION_PERIOD_OVER
throw DatabaseException("Redis backend is read-only, see deprecation notice.");
#else
redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "MULTI")); redisReply *reply = static_cast<redisReply *>(redisCommand(ctx, "MULTI"));
if (!reply) { if (!reply) {
throw DatabaseException(std::string( throw DatabaseException(std::string(
"Redis command 'MULTI' failed: ") + ctx->errstr); "Redis command 'MULTI' failed: ") + ctx->errstr);
} }
freeReplyObject(reply); freeReplyObject(reply);
#endif
} }
void Database_Redis::endSave() void Database_Redis::endSave()

View File

@ -403,6 +403,7 @@ void set_default_settings()
// ContentDB // ContentDB
settings->setDefault("contentdb_url", "https://content.minetest.net"); settings->setDefault("contentdb_url", "https://content.minetest.net");
settings->setDefault("contentdb_enable_updates_indicator", "true");
settings->setDefault("contentdb_max_concurrent_downloads", "3"); settings->setDefault("contentdb_max_concurrent_downloads", "3");
#ifdef __ANDROID__ #ifdef __ANDROID__

View File

@ -692,7 +692,7 @@ void *EmergeThread::run()
"EmergeThread: Lua on_generated", SPT_AVG); "EmergeThread: Lua on_generated", SPT_AVG);
try { try {
m_script->on_generated(&bmdata); m_script->on_generated(&bmdata, m_mapgen->blockseed);
} catch (const LuaError &e) { } catch (const LuaError &e) {
m_server->setAsyncFatalError(e); m_server->setAsyncFatalError(e);
error = true; error = true;

View File

@ -50,6 +50,7 @@ class ModApiMapgen;
// Structure containing inputs/outputs for chunk generation // Structure containing inputs/outputs for chunk generation
struct BlockMakeData { struct BlockMakeData {
MMVManip *vmanip = nullptr; MMVManip *vmanip = nullptr;
// Global map seed
u64 seed = 0; u64 seed = 0;
v3s16 blockpos_min; v3s16 blockpos_min;
v3s16 blockpos_max; v3s16 blockpos_max;

View File

@ -954,13 +954,22 @@ bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string
const io::IFileList* files_in_zip = opened_zip->getFileList(); const io::IFileList* files_in_zip = opened_zip->getFileList();
for (u32 i = 0; i < files_in_zip->getFileCount(); i++) { for (u32 i = 0; i < files_in_zip->getFileCount(); i++) {
std::string fullpath = destination + DIR_DELIM;
fullpath += files_in_zip->getFullFileName(i).c_str();
std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
if (files_in_zip->isDirectory(i)) if (files_in_zip->isDirectory(i))
continue; // ignore, we create dirs as necessary continue; // ignore, we create dirs as necessary
const auto &filename = files_in_zip->getFullFileName(i);
std::string fullpath = destination + DIR_DELIM;
fullpath += filename.c_str();
fullpath = fs::RemoveRelativePathComponents(fullpath);
if (!fs::PathStartsWith(fullpath, destination)) {
warningstream << "fs::extractZipFile(): refusing to extract file \""
<< filename.c_str() << "\"" << std::endl;
continue;
}
std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir))
return false; return false;

View File

@ -4098,6 +4098,8 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
skin->setFont(m_font); skin->setFont(m_font);
bool retval = hovered->OnEvent(event); bool retval = hovered->OnEvent(event);
skin->setFont(old_font); skin->setFont(old_font);
// This is expected to be set to BET_OTHER with mouse UP event
m_held_mouse_button = BET_OTHER;
return retval; return retval;
} }
} }

View File

@ -40,10 +40,17 @@ static std::unordered_map<u64, std::queue<HTTPFetchResult>>
g_httpfetch_results; g_httpfetch_results;
static PcgRandom g_callerid_randomness; static PcgRandom g_callerid_randomness;
static std::string default_user_agent()
{
std::string ret(PROJECT_NAME_C "/");
ret.append(g_version_string).append(" (").append(porting::get_sysinfo()).append(")");
return ret;
}
HTTPFetchRequest::HTTPFetchRequest() : HTTPFetchRequest::HTTPFetchRequest() :
timeout(g_settings->getS32("curl_timeout")), timeout(g_settings->getS32("curl_timeout")),
connect_timeout(10 * 1000), connect_timeout(10 * 1000),
useragent(std::string(PROJECT_NAME_C "/") + g_version_hash + " (" + porting::get_sysinfo() + ")") useragent(default_user_agent())
{ {
timeout = std::max(timeout, MIN_HTTPFETCH_TIMEOUT_INTERACTIVE); timeout = std::max(timeout, MIN_HTTPFETCH_TIMEOUT_INTERACTIVE);
} }
@ -749,19 +756,6 @@ static void httpfetch_request_clear(u64 caller)
} }
} }
static void httpfetch_sync(const HTTPFetchRequest &fetch_request,
HTTPFetchResult &fetch_result)
{
// Create ongoing fetch data and make a cURL handle
// Set cURL options based on HTTPFetchRequest
CurlHandlePool pool;
HTTPFetchOngoing ongoing(fetch_request, &pool);
// Do the fetch (curl_easy_perform)
CURLcode res = ongoing.start(nullptr);
// Update fetch result
fetch_result = *ongoing.complete(res);
}
bool httpfetch_sync_interruptible(const HTTPFetchRequest &fetch_request, bool httpfetch_sync_interruptible(const HTTPFetchRequest &fetch_request,
HTTPFetchResult &fetch_result, long interval) HTTPFetchResult &fetch_result, long interval)
{ {
@ -779,7 +773,8 @@ bool httpfetch_sync_interruptible(const HTTPFetchRequest &fetch_request,
} while (!httpfetch_async_get(req.caller, fetch_result)); } while (!httpfetch_async_get(req.caller, fetch_result));
httpfetch_caller_free(req.caller); httpfetch_caller_free(req.caller);
} else { } else {
httpfetch_sync(fetch_request, fetch_result); throw ModError(std::string("You have tried to execute a synchronous HTTP request on the main thread! "
"This offense shall be punished. (").append(fetch_request.url).append(")"));
} }
return true; return true;
} }

View File

@ -167,6 +167,7 @@ private:
*/ */
class Mapgen { class Mapgen {
public: public:
// Seed used for noises (truncated from the map seed)
s32 seed = 0; s32 seed = 0;
int water_level = 0; int water_level = 0;
int mapgen_limit = 0; int mapgen_limit = 0;
@ -180,6 +181,7 @@ public:
EmergeParams *m_emerge = nullptr; EmergeParams *m_emerge = nullptr;
const NodeDefManager *ndef = nullptr; const NodeDefManager *ndef = nullptr;
// Chunk-specific seed used to place ores and decorations
u32 blockseed; u32 blockseed;
s16 *heightmap = nullptr; s16 *heightmap = nullptr;
biome_t *biomemap = nullptr; biome_t *biomemap = nullptr;

View File

@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif #endif
#if defined(__ANDROID__) #if defined(__ANDROID__)
#include "porting_android.h" #include "porting_android.h"
#include <android/api-level.h>
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
@ -205,7 +206,10 @@ bool detectMSVCBuildDir(const std::string &path)
return (!removeStringEnd(path, ends).empty()); return (!removeStringEnd(path, ends).empty());
} }
std::string get_sysinfo() // Note that the system info is sent in every HTTP request, so keep it reasonably
// privacy-conserving while ideally still being meaningful.
static std::string detectSystemInfo()
{ {
#ifdef _WIN32 #ifdef _WIN32
std::ostringstream oss; std::ostringstream oss;
@ -251,14 +255,34 @@ std::string get_sysinfo()
delete[] filePath; delete[] filePath;
return oss.str(); return oss.str();
#else #elif defined(__ANDROID__)
std::ostringstream oss;
struct utsname osinfo; struct utsname osinfo;
uname(&osinfo); uname(&osinfo);
return std::string(osinfo.sysname) + "/" int api = android_get_device_api_level();
+ osinfo.release + " " + osinfo.machine;
oss << "Android/" << api << " " << osinfo.machine;
return oss.str();
#else /* POSIX */
struct utsname osinfo;
uname(&osinfo);
std::string_view release(osinfo.release);
// cut off anything but the primary version number
release = release.substr(0, release.find_first_not_of("0123456789."));
std::string ret = osinfo.sysname;
ret.append("/").append(release).append(" ").append(osinfo.machine);
return ret;
#endif #endif
} }
const std::string &get_sysinfo()
{
static std::string ret = detectSystemInfo();
return ret;
}
bool getCurrentWorkingDir(char *buf, size_t len) bool getCurrentWorkingDir(char *buf, size_t len)
{ {

View File

@ -138,7 +138,7 @@ void initializePaths();
Return system information Return system information
e.g. "Linux/3.12.7 x86_64" e.g. "Linux/3.12.7 x86_64"
*/ */
std::string get_sysinfo(); const std::string &get_sysinfo();
// Monotonic timer // Monotonic timer

View File

@ -45,7 +45,7 @@ void ScriptApiMapgen::on_shutdown()
runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
} }
void ScriptApiMapgen::on_generated(BlockMakeData *bmdata) void ScriptApiMapgen::on_generated(BlockMakeData *bmdata, u32 seed)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
@ -66,7 +66,7 @@ void ScriptApiMapgen::on_generated(BlockMakeData *bmdata)
lua_pushvalue(L, vmanip); lua_pushvalue(L, vmanip);
push_v3s16(L, minp); push_v3s16(L, minp);
push_v3s16(L, maxp); push_v3s16(L, maxp);
lua_pushnumber(L, bmdata->seed); lua_pushnumber(L, seed);
runCallbacks(4, RUN_CALLBACKS_MODE_FIRST); runCallbacks(4, RUN_CALLBACKS_MODE_FIRST);
lua_pop(L, 1); // return val lua_pop(L, 1); // return val

View File

@ -35,6 +35,6 @@ public:
void on_mods_loaded(); void on_mods_loaded();
void on_shutdown(); void on_shutdown();
// Called after generating a piece of map before writing it to the map // Called after generating a piece of map, before writing it to the map
void on_generated(BlockMakeData *bmdata); void on_generated(BlockMakeData *bmdata, u32 seed);
}; };

View File

@ -19,6 +19,8 @@ fake_function() {
gettext("If disabled, \"Aux1\" key is used to fly fast if both fly and fast mode are\nenabled."); gettext("If disabled, \"Aux1\" key is used to fly fast if both fly and fast mode are\nenabled.");
gettext("Place repetition interval"); gettext("Place repetition interval");
gettext("The time in seconds it takes between repeated node placements when holding\nthe place button."); gettext("The time in seconds it takes between repeated node placements when holding\nthe place button.");
gettext("Minimum dig repetition interval");
gettext("The minimum time in seconds it takes between digging nodes when holding\nthe dig button.");
gettext("Automatic jumping"); gettext("Automatic jumping");
gettext("Automatically jump up single-node obstacles."); gettext("Automatically jump up single-node obstacles.");
gettext("Safe digging and placing"); gettext("Safe digging and placing");
@ -33,16 +35,22 @@ fake_function() {
gettext("Hotbar: Invert mouse wheel direction"); gettext("Hotbar: Invert mouse wheel direction");
gettext("Invert mouse wheel (scroll) direction for item selection in hotbar."); gettext("Invert mouse wheel (scroll) direction for item selection in hotbar.");
gettext("Touchscreen"); gettext("Touchscreen");
gettext("Touchscreen threshold"); gettext("Enable touchscreen");
gettext("The length in pixels it takes for touchscreen interaction to start."); gettext("Enables touchscreen mode, allowing you to play the game with a touchscreen.");
gettext("Touchscreen sensitivity"); gettext("Touchscreen sensitivity");
gettext("Touchscreen sensitivity multiplier."); gettext("Touchscreen sensitivity multiplier.");
gettext("Movement threshold");
gettext("The length in pixels after which a touch interaction is considered movement.");
gettext("Threshold for long taps");
gettext("The delay in milliseconds after which a touch interaction is considered a long tap.");
gettext("Use crosshair for touch screen"); gettext("Use crosshair for touch screen");
gettext("Use crosshair to select object instead of whole screen.\nIf enabled, a crosshair will be shown and will be used for selecting object."); gettext("Use crosshair to select object instead of whole screen.\nIf enabled, a crosshair will be shown and will be used for selecting object.");
gettext("Fixed virtual joystick"); gettext("Fixed virtual joystick");
gettext("Fixes the position of virtual joystick.\nIf disabled, virtual joystick will center to first-touch's position."); gettext("Fixes the position of virtual joystick.\nIf disabled, virtual joystick will center to first-touch's position.");
gettext("Virtual joystick triggers Aux1 button"); gettext("Virtual joystick triggers Aux1 button");
gettext("Use virtual joystick to trigger \"Aux1\" button.\nIf enabled, virtual joystick will also tap \"Aux1\" button when out of main circle."); gettext("Use virtual joystick to trigger \"Aux1\" button.\nIf enabled, virtual joystick will also tap \"Aux1\" button when out of main circle.");
gettext("Punch gesture");
gettext("The gesture for for punching players/entities.\nThis can be overridden by games and mods.\n\n* short_tap\nEasy to use and well-known from other games that shall not be named.\n\n* long_tap\nKnown from the classic Minetest mobile controls.\nCombat is more or less impossible.");
gettext("Graphics and Audio"); gettext("Graphics and Audio");
gettext("Graphics"); gettext("Graphics");
gettext("Screen"); gettext("Screen");
@ -70,8 +78,8 @@ fake_function() {
gettext("Undersampling"); gettext("Undersampling");
gettext("Undersampling is similar to using a lower screen resolution, but it applies\nto the game world only, keeping the GUI intact.\nIt should give a significant performance boost at the cost of less detailed image.\nHigher values result in a less detailed image."); gettext("Undersampling is similar to using a lower screen resolution, but it applies\nto the game world only, keeping the GUI intact.\nIt should give a significant performance boost at the cost of less detailed image.\nHigher values result in a less detailed image.");
gettext("Graphics Effects"); gettext("Graphics Effects");
gettext("Opaque liquids"); gettext("Translucent liquids");
gettext("Makes all liquids opaque"); gettext("Allows liquids to be translucent.");
gettext("Leaves style"); gettext("Leaves style");
gettext("Leaves style:\n- Fancy: all faces visible\n- Simple: only outer faces, if defined special_tiles are used\n- Opaque: disable transparency"); gettext("Leaves style:\n- Fancy: all faces visible\n- Simple: only outer faces, if defined special_tiles are used\n- Opaque: disable transparency");
gettext("Connect glass"); gettext("Connect glass");
@ -143,7 +151,7 @@ fake_function() {
gettext("Anisotropic filtering"); gettext("Anisotropic filtering");
gettext("Use anisotropic filtering when looking at textures from an angle."); gettext("Use anisotropic filtering when looking at textures from an angle.");
gettext("Antialiasing method"); gettext("Antialiasing method");
gettext("Select the antialiasing method to apply.\n\n* None - No antialiasing (default)\n\n* FSAA - Hardware-provided full-screen antialiasing (incompatible with shaders)\nA.K.A multi-sample antialiasing (MSAA)\nSmoothens out block edges but does not affect the insides of textures.\nA restart is required to change this option.\n\n* FXAA - Fast approximate antialiasing (requires shaders)\nApplies a post-processing filter to detect and smoothen high-contrast edges.\nProvides balance between speed and image quality.\n\n* SSAA - Super-sampling antialiasing (requires shaders)\nRenders higher-resolution image of the scene, then scales down to reduce\nthe aliasing effects. This is the slowest and the most accurate method."); gettext("Select the antialiasing method to apply.\n\n* None - No antialiasing (default)\n\n* FSAA - Hardware-provided full-screen antialiasing\n(incompatible with Post Processing and Undersampling)\nA.K.A multi-sample antialiasing (MSAA)\nSmoothens out block edges but does not affect the insides of textures.\nA restart is required to change this option.\n\n* FXAA - Fast approximate antialiasing (requires shaders)\nApplies a post-processing filter to detect and smoothen high-contrast edges.\nProvides balance between speed and image quality.\n\n* SSAA - Super-sampling antialiasing (requires shaders)\nRenders higher-resolution image of the scene, then scales down to reduce\nthe aliasing effects. This is the slowest and the most accurate method.");
gettext("Anti-aliasing scale"); gettext("Anti-aliasing scale");
gettext("Defines the size of the sampling grid for FSAA and SSAA antialiasing methods.\nValue of 2 means taking 2x2 = 4 samples."); gettext("Defines the size of the sampling grid for FSAA and SSAA antialiasing methods.\nValue of 2 means taking 2x2 = 4 samples.");
gettext("Occlusion Culling"); gettext("Occlusion Culling");
@ -153,7 +161,7 @@ fake_function() {
gettext("Use raytraced occlusion culling in the new culler.\nThis flag enables use of raytraced occlusion culling test for\nclient mesh sizes smaller than 4x4x4 map blocks."); gettext("Use raytraced occlusion culling in the new culler.\nThis flag enables use of raytraced occlusion culling test for\nclient mesh sizes smaller than 4x4x4 map blocks.");
gettext("Shaders"); gettext("Shaders");
gettext("Shaders"); gettext("Shaders");
gettext("Shaders allow advanced visual effects and may increase performance on some video\ncards.\nThis only works with the OpenGL video backend."); gettext("Shaders allow advanced visual effects and may increase performance on some video\ncards.");
gettext("Waving Nodes"); gettext("Waving Nodes");
gettext("Waving leaves"); gettext("Waving leaves");
gettext("Set to true to enable waving leaves."); gettext("Set to true to enable waving leaves.");
@ -191,12 +199,16 @@ fake_function() {
gettext("Sky Body Orbit Tilt"); gettext("Sky Body Orbit Tilt");
gettext("Set the default tilt of Sun/Moon orbit in degrees.\nGames may change orbit tilt via API.\nValue of 0 means no tilt / vertical orbit."); gettext("Set the default tilt of Sun/Moon orbit in degrees.\nGames may change orbit tilt via API.\nValue of 0 means no tilt / vertical orbit.");
gettext("Post Processing"); gettext("Post Processing");
gettext("Enable Post Processing");
gettext("Enables the post processing pipeline.");
gettext("Filmic tone mapping"); gettext("Filmic tone mapping");
gettext("Enables Hable's 'Uncharted 2' filmic tone mapping.\nSimulates the tone curve of photographic film and how this approximates the\nappearance of high dynamic range images. Mid-range contrast is slightly\nenhanced, highlights and shadows are gradually compressed."); gettext("Enables Hable's 'Uncharted 2' filmic tone mapping.\nSimulates the tone curve of photographic film and how this approximates the\nappearance of high dynamic range images. Mid-range contrast is slightly\nenhanced, highlights and shadows are gradually compressed.");
gettext("Enable Automatic Exposure"); gettext("Enable Automatic Exposure");
gettext("Enable automatic exposure correction\nWhen enabled, the post-processing engine will\nautomatically adjust to the brightness of the scene,\nsimulating the behavior of human eye."); gettext("Enable automatic exposure correction\nWhen enabled, the post-processing engine will\nautomatically adjust to the brightness of the scene,\nsimulating the behavior of human eye.");
gettext("Exposure compensation"); gettext("Exposure compensation");
gettext("Set the exposure compensation in EV units.\nValue of 0.0 (default) means no exposure compensation.\nRange: from -1 to 1.0"); gettext("Set the exposure compensation in EV units.\nValue of 0.0 (default) means no exposure compensation.\nRange: from -1 to 1.0");
gettext("Enable Debanding");
gettext("Apply dithering to reduce color banding artifacts.\nDithering significantly increases the size of losslessly-compressed\nscreenshots and it works incorrectly if the display or operating system\nperforms additional dithering or if the color channels are not quantized\nto 8 bits.\nWith OpenGL ES, dithering only works if the shader supports high\nfloating-point precision and it may have a higher performance impact.");
gettext("Bloom"); gettext("Bloom");
gettext("Enable Bloom"); gettext("Enable Bloom");
gettext("Set to true to enable bloom effect.\nBright colors will bleed over the neighboring objects."); gettext("Set to true to enable bloom effect.\nBright colors will bleed over the neighboring objects.");
@ -208,14 +220,18 @@ fake_function() {
gettext("Defines the magnitude of bloom overexposure.\nRange: from 0.1 to 10.0, default: 1.0"); gettext("Defines the magnitude of bloom overexposure.\nRange: from 0.1 to 10.0, default: 1.0");
gettext("Bloom Radius"); gettext("Bloom Radius");
gettext("Logical value that controls how far the bloom effect spreads\nfrom the bright objects.\nRange: from 0.1 to 8, default: 1"); gettext("Logical value that controls how far the bloom effect spreads\nfrom the bright objects.\nRange: from 0.1 to 8, default: 1");
gettext("Volumetric lighting");
gettext("Set to true to enable volumetric lighting effect (a.k.a. \"Godrays\").");
gettext("Audio"); gettext("Audio");
gettext("Volume"); gettext("Volume");
gettext("Volume of all sounds.\nRequires the sound system to be enabled."); gettext("Volume of all sounds.\nRequires the sound system to be enabled.");
gettext("Volume when unfocused");
gettext("Volume multiplier when the window is unfocused.");
gettext("Mute sound"); gettext("Mute sound");
gettext("Whether to mute sounds. You can unmute sounds at any time, unless the\nsound system is disabled (enable_sound=false).\nIn-game, you can toggle the mute state with the mute key or by using the\npause menu."); gettext("Whether to mute sounds. You can unmute sounds at any time, unless the\nsound system is disabled (enable_sound=false).\nIn-game, you can toggle the mute state with the mute key or by using the\npause menu.");
gettext("User Interfaces"); gettext("User Interfaces");
gettext("Language"); gettext("Language");
gettext("Set the language. Leave empty to use the system language.\nA restart is required after changing this."); gettext("Set the language. By default, the system language is used.\nA restart is required after changing this.");
gettext("GUI"); gettext("GUI");
gettext("GUI scaling"); gettext("GUI scaling");
gettext("Scale GUI by a user specified value.\nUse a nearest-neighbor-anti-alias filter to scale the GUI.\nThis will smooth over some of the rough edges, and blend\npixels when scaling down, at the cost of blurring some\nedge pixels when images are scaled by non-integer sizes."); gettext("Scale GUI by a user specified value.\nUse a nearest-neighbor-anti-alias filter to scale the GUI.\nThis will smooth over some of the rough edges, and blend\npixels when scaling down, at the cost of blurring some\nedge pixels when images are scaled by non-integer sizes.");
@ -273,7 +289,7 @@ fake_function() {
gettext("Enable split login/register"); gettext("Enable split login/register");
gettext("If enabled, account registration is separate from login in the UI.\nIf disabled, new accounts will be registered automatically when logging in."); gettext("If enabled, account registration is separate from login in the UI.\nIf disabled, new accounts will be registered automatically when logging in.");
gettext("Update information URL"); gettext("Update information URL");
gettext("URL to JSON file which provides information about the newest Minetest release"); gettext("URL to JSON file which provides information about the newest Minetest release\nIf this is empty the engine will never check for updates.");
gettext("Server"); gettext("Server");
gettext("Admin name"); gettext("Admin name");
gettext("Name of the player.\nWhen running a server, clients connecting with this name are admins.\nWhen starting from the main menu, this is overridden."); gettext("Name of the player.\nWhen running a server, clients connecting with this name are admins.\nWhen starting from the main menu, this is overridden.");
@ -303,6 +319,8 @@ fake_function() {
gettext("The network interface that the server listens on."); gettext("The network interface that the server listens on.");
gettext("Strict protocol checking"); gettext("Strict protocol checking");
gettext("Enable to disallow old clients from connecting.\nOlder clients are compatible in the sense that they will not crash when connecting\nto new servers, but they may not support all new features that you are expecting."); gettext("Enable to disallow old clients from connecting.\nOlder clients are compatible in the sense that they will not crash when connecting\nto new servers, but they may not support all new features that you are expecting.");
gettext("Protocol version minimum");
gettext("Define the oldest clients allowed to connect.\nOlder clients are compatible in the sense that they will not crash when connecting\nto new servers, but they may not support all new features that you are expecting.\nThis allows for more fine-grained control than strict_protocol_version_checking.\nMinetest still enforces its own internal minimum, and enabling\nstrict_protocol_version_checking will effectively override this.");
gettext("Remote media"); gettext("Remote media");
gettext("Specifies URL from which client fetches media instead of using UDP.\n$filename should be accessible from $remote_media$filename via cURL\n(obviously, remote_media should end with a slash).\nFiles that are not present will be fetched the usual way."); gettext("Specifies URL from which client fetches media instead of using UDP.\n$filename should be accessible from $remote_media$filename via cURL\n(obviously, remote_media should end with a slash).\nFiles that are not present will be fetched the usual way.");
gettext("IPv6 server"); gettext("IPv6 server");
@ -436,7 +454,7 @@ fake_function() {
gettext("3D noise that determines number of dungeons per mapchunk."); gettext("3D noise that determines number of dungeons per mapchunk.");
gettext("Mapgen V6"); gettext("Mapgen V6");
gettext("Mapgen V6 specific flags"); gettext("Mapgen V6 specific flags");
gettext("Map generation attributes specific to Mapgen v6.\nThe 'snowbiomes' flag enables the new 5 biome system.\nWhen the 'snowbiomes' flag is enabled jungles are automatically enabled and\nthe 'jungles' flag is ignored."); gettext("Map generation attributes specific to Mapgen v6.\nThe 'snowbiomes' flag enables the new 5 biome system.\nWhen the 'snowbiomes' flag is enabled jungles are automatically enabled and\nthe 'jungles' flag is ignored.\nThe 'temples' flag disables generation of desert temples. Normal dungeons will appear instead.");
gettext("Desert noise threshold"); gettext("Desert noise threshold");
gettext("Deserts occur when np_biome exceeds this value.\nWhen the 'snowbiomes' flag is enabled, this is ignored."); gettext("Deserts occur when np_biome exceeds this value.\nWhen the 'snowbiomes' flag is enabled, this is ignored.");
gettext("Beach noise threshold"); gettext("Beach noise threshold");
@ -788,6 +806,8 @@ fake_function() {
gettext("Handling for deprecated Lua API calls:\n- none: Do not log deprecated calls\n- log: mimic and log backtrace of deprecated call (default).\n- error: abort on usage of deprecated call (suggested for mod developers)."); gettext("Handling for deprecated Lua API calls:\n- none: Do not log deprecated calls\n- log: mimic and log backtrace of deprecated call (default).\n- error: abort on usage of deprecated call (suggested for mod developers).");
gettext("Random input"); gettext("Random input");
gettext("Enable random user input (only used for testing)."); gettext("Enable random user input (only used for testing).");
gettext("Random mod load order");
gettext("Enable random mod loading (mainly used for testing).");
gettext("Mod channels"); gettext("Mod channels");
gettext("Enable mod channels support."); gettext("Enable mod channels support.");
gettext("Mod Profiler"); gettext("Mod Profiler");
@ -823,11 +843,9 @@ fake_function() {
gettext("Shader path"); gettext("Shader path");
gettext("Path to shader directory. If no path is defined, default location will be used."); gettext("Path to shader directory. If no path is defined, default location will be used.");
gettext("Video driver"); gettext("Video driver");
gettext("The rendering back-end.\nNote: A restart is required after changing this!\nOpenGL is the default for desktop, and OGLES2 for Android.\nShaders are supported by OpenGL and OGLES2 (experimental)."); gettext("The rendering back-end.\nNote: A restart is required after changing this!\nOpenGL is the default for desktop, and OGLES2 for Android.\nShaders are supported by everything but OGLES1.");
gettext("Transparency Sorting Distance"); gettext("Transparency Sorting Distance");
gettext("Distance in nodes at which transparency depth sorting is enabled\nUse this to limit the performance impact of transparency depth sorting"); gettext("Distance in nodes at which transparency depth sorting is enabled\nUse this to limit the performance impact of transparency depth sorting");
gettext("VBO");
gettext("Enable vertex buffer objects.\nThis should greatly improve graphics performance.");
gettext("Cloud radius"); gettext("Cloud radius");
gettext("Radius of cloud area stated in number of 64 node cloud squares.\nValues larger than 26 will start to produce sharp cutoffs at cloud area corners."); gettext("Radius of cloud area stated in number of 64 node cloud squares.\nValues larger than 26 will start to produce sharp cutoffs at cloud area corners.");
gettext("Desynchronize block animation"); gettext("Desynchronize block animation");
@ -838,8 +856,6 @@ fake_function() {
gettext("Delay between mesh updates on the client in ms. Increasing this will slow\ndown the rate of mesh updates, thus reducing jitter on slower clients."); gettext("Delay between mesh updates on the client in ms. Increasing this will slow\ndown the rate of mesh updates, thus reducing jitter on slower clients.");
gettext("Mapblock mesh generation threads"); gettext("Mapblock mesh generation threads");
gettext("Number of threads to use for mesh generation.\nValue of 0 (default) will let Minetest autodetect the number of available threads."); gettext("Number of threads to use for mesh generation.\nValue of 0 (default) will let Minetest autodetect the number of available threads.");
gettext("Mapblock mesh generator's MapBlock cache size in MB");
gettext("Size of the MapBlock cache of the mesh generator. Increasing this will\nincrease the cache hit %, reducing the data being copied from the main\nthread, thus reducing jitter.");
gettext("Minimap scan height"); gettext("Minimap scan height");
gettext("True = 256\nFalse = 128\nUsable to make minimap smoother on slower machines."); gettext("True = 256\nFalse = 128\nUsable to make minimap smoother on slower machines.");
gettext("World-aligned textures mode"); gettext("World-aligned textures mode");
@ -850,6 +866,11 @@ fake_function() {
gettext("When using bilinear/trilinear/anisotropic filters, low-resolution textures\ncan be blurred, so automatically upscale them with nearest-neighbor\ninterpolation to preserve crisp pixels. This sets the minimum texture size\nfor the upscaled textures; higher values look sharper, but require more\nmemory. Powers of 2 are recommended. This setting is ONLY applied if\nbilinear/trilinear/anisotropic filtering is enabled.\nThis is also used as the base node texture size for world-aligned\ntexture autoscaling."); gettext("When using bilinear/trilinear/anisotropic filters, low-resolution textures\ncan be blurred, so automatically upscale them with nearest-neighbor\ninterpolation to preserve crisp pixels. This sets the minimum texture size\nfor the upscaled textures; higher values look sharper, but require more\nmemory. Powers of 2 are recommended. This setting is ONLY applied if\nbilinear/trilinear/anisotropic filtering is enabled.\nThis is also used as the base node texture size for world-aligned\ntexture autoscaling.");
gettext("Client Mesh Chunksize"); gettext("Client Mesh Chunksize");
gettext("Side length of a cube of map blocks that the client will consider together\nwhen generating meshes.\nLarger values increase the utilization of the GPU by reducing the number of\ndraw calls, benefiting especially high-end GPUs.\nSystems with a low-end GPU (or no GPU) would benefit from smaller values."); gettext("Side length of a cube of map blocks that the client will consider together\nwhen generating meshes.\nLarger values increase the utilization of the GPU by reducing the number of\ndraw calls, benefiting especially high-end GPUs.\nSystems with a low-end GPU (or no GPU) would benefit from smaller values.");
gettext("OpenGL debug");
gettext("Enables debug and error-checking in the OpenGL driver.");
gettext("Sound");
gettext("Sound Extensions Blacklist");
gettext("Comma-separated list of AL and ALC extensions that should not be used.\nUseful for testing. See al_extensions.[h,cpp] for details.");
gettext("Font"); gettext("Font");
gettext("Font bold by default"); gettext("Font bold by default");
gettext("Font italic by default"); gettext("Font italic by default");
@ -920,7 +941,7 @@ fake_function() {
gettext("Whether to ask clients to reconnect after a (Lua) crash.\nSet this to true if your server is set up to restart automatically."); gettext("Whether to ask clients to reconnect after a (Lua) crash.\nSet this to true if your server is set up to restart automatically.");
gettext("Server/Env Performance"); gettext("Server/Env Performance");
gettext("Dedicated server step"); gettext("Dedicated server step");
gettext("Length of a server tick and the interval at which objects are generally updated over\nnetwork, stated in seconds."); gettext("Length of a server tick (the interval at which everything is generally updated),\nstated in seconds.\nDoes not apply to sessions hosted from the client menu.");
gettext("Unlimited player transfer distance"); gettext("Unlimited player transfer distance");
gettext("Whether players are shown to clients without any range limit.\nDeprecated, use the setting player_transfer_distance instead."); gettext("Whether players are shown to clients without any range limit.\nDeprecated, use the setting player_transfer_distance instead.");
gettext("Player transfer distance"); gettext("Player transfer distance");
@ -956,9 +977,11 @@ fake_function() {
gettext("Liquid update tick"); gettext("Liquid update tick");
gettext("Liquid update interval in seconds."); gettext("Liquid update interval in seconds.");
gettext("Block send optimize distance"); gettext("Block send optimize distance");
gettext("At this distance the server will aggressively optimize which blocks are sent to\nclients.\nSmall values potentially improve performance a lot, at the expense of visible\nrendering glitches (some blocks will not be rendered under water and in caves,\nas well as sometimes on land).\nSetting this to a value greater than max_block_send_distance disables this\noptimization.\nStated in mapblocks (16 nodes)."); gettext("At this distance the server will aggressively optimize which blocks are sent to\nclients.\nSmall values potentially improve performance a lot, at the expense of visible\nrendering glitches (some blocks might not be rendered correctly in caves).\nSetting this to a value greater than max_block_send_distance disables this\noptimization.\nStated in MapBlocks (16 nodes).");
gettext("Server-side occlusion culling"); gettext("Server-side occlusion culling");
gettext("If enabled, the server will perform map block occlusion culling based on\non the eye position of the player. This can reduce the number of blocks\nsent to the client by 50-80%. Clients will no longer receive most\ninvisible blocks, so that the utility of noclip mode is reduced."); gettext("If enabled, the server will perform map block occlusion culling based on\non the eye position of the player. This can reduce the number of blocks\nsent to the client by 50-80%. Clients will no longer receive most\ninvisible blocks, so that the utility of noclip mode is reduced.");
gettext("Block cull optimize distance");
gettext("At this distance the server will perform a simpler and cheaper occlusion check.\nSmaller values potentially improve performance, at the expense of temporarily visible\nrendering glitches (missing blocks).\nThis is especially useful for very large viewing range (upwards of 500).\nStated in MapBlocks (16 nodes).");
gettext("Mapgen"); gettext("Mapgen");
gettext("Chunk size"); gettext("Chunk size");
gettext("Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).\nWARNING: There is no benefit, and there are several dangers, in\nincreasing this value above 5.\nReducing this value increases cave and dungeon density.\nAltering this value is for special usage, leaving it unchanged is\nrecommended."); gettext("Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).\nWARNING: There is no benefit, and there are several dangers, in\nincreasing this value above 5.\nReducing this value increases cave and dungeon density.\nAltering this value is for special usage, leaving it unchanged is\nrecommended.");
@ -980,8 +1003,6 @@ fake_function() {
gettext("cURL file download timeout"); gettext("cURL file download timeout");
gettext("Maximum time a file download (e.g. a mod download) may take, stated in milliseconds."); gettext("Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.");
gettext("Miscellaneous"); gettext("Miscellaneous");
gettext("DPI");
gettext("Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.");
gettext("Display Density Scaling Factor"); gettext("Display Density Scaling Factor");
gettext("Adjust the detected display density, used for scaling UI elements."); gettext("Adjust the detected display density, used for scaling UI elements.");
gettext("Enable console window"); gettext("Enable console window");

View File

@ -1,216 +0,0 @@
# `mod_translation_updater.py`—Minetest Mod Translation Updater
This Python script is intended for use with localized Minetest mods, i.e., mods that use
`*.tr` and contain translatable strings of the form `S("This string can be translated")`.
It extracts the strings from the mod's source code and updates the localization files
accordingly. It can also be used to update the `*.tr` files in Minetest's `builtin` component.
## Preparing your source code
This script makes assumptions about your source code. Before it is usable, you first have
to prepare your source code accordingly.
### Choosing the textdomain name
It is recommended to set the textdomain name (for `minetest.get_translator`) to be identical
of the mod name as the script will automatically detect it. If the textdomain name differs,
you may have to manually change the `# textdomain:` line of newly generated files.
**Note:** In each `*.tr` file, there **must** be only one textdomain. Multiple textdomains in
the same file are not supported by this script and any additional textdomain line will be
removed.
### Defining the helper functions
In any source code file with translatable strings, you have to manually define helper
functions at the top with something like `local S = minetest.get_translator("<textdomain>")`.
Optionally, you can also define additional helper functions `FS`, `NS` and `NFS` if needed.
Here is the list of all recognized function names. All functions return a string.
* `S`: Returns translation of input. See Minetest's `lua_api.md`. You should always have at
least this function defined.
* `NS`: Returns the input. Useful to make a string visible to the script without actually
translating it here.
* `FS`: Same as `S`, but returns a formspec-escaped version of the translation of the input.
Supported for convenience.
* `NFS`: Returns a formspec-escaped version of the input, but not translated.
Supported for convenience.
Here is the boilerplate code you have to add at the top of your source code file:
local S = minetest.get_translator("<textdomain>")
local NS = function(s) return s end
local FS = function(...) return minetest.formspec_escape(S(...)) end
local NFS = function(s) return minetest.formspec_escape(s) end
Replace `<textdomain>` above and optionally delete `NS`, `FS` and/or `NFS` if you don't need
them.
### Preparing the strings
This script can detect translatable strings of the notations listed below.
Additional function arguments followed after a literal string are ignored.
* `S("literal")`: one literal string enclosed by the delimiters
`"..."`, `'...'` or `[[...]]`
* `S("foo " .. 'bar ' .. "baz")`: concatenation of multiple literal strings. Line
breaks are accepted.
The `S` may also be `NS`, `FS` and `NFS` (see above).
Undetectable notations:
* `S"literal"`: omitted function brackets
* `S(variable)`: requires the use of `NS`. See example below.
* `S("literal " .. variable)`: non-static content.
Use placeholders (`@1`, ...) for variable text.
* Any literal string concatenation using `[[...]]`
### A minimal example
This minimal code example sends "Hello world!" to all players, but translated according to
each player's language:
local S = minetest.get_translator("example")
minetest.chat_send_all(S("Hello world!"))
### How to use `NS`
The reason why `NS` exists is for cases like this: Sometimes, you want to define a list of
strings to they can be later output in a function. Like so:
local fruit = { "Apple", "Orange", "Pear" }
local function return_fruit(fruit_id)
return fruit[fruit_id]
end
If you want to translate the fruit names when `return_fruit` is run, but have the
*untranslated* fruit names in the `fruit` table stored, this is where `NS` will help.
It will show the script the string without Minetest translating it. The script could be made
translatable like this:
local fruit = { NS("Apple"), NS("Orange"), NS("Pear") }
local function return_fruit(fruit_id)
return S(fruit[fruit_id])
end
## How to run the script
First, change the working directory to the directory of the mod you want the files to be
updated. From this directory, run the script.
When you run the script, it will update the `template.txt` and any `*.tr` files present
in that mod's `/locale` folder. If the `/locale` folder or `template.txt` file don't
exist yet, they will be created.
This script will also work in the root directory of a modpack. It will run on each mod
inside the modpack in that situation. Alternatively, you can run the script to update
the files of all mods in subdirectories with the `-r` option, which is useful to update
the locale files in an entire game.
It has the following command line options:
mod_translation_updater.py [OPTIONS] [PATHS...]
--help, -h: prints this help message
--recursive, -r: run on all subfolders of paths given
--old-file, -o: create copies of files before updating them, named `<FILE NAME>.old`
--break-long-lines, -b: add extra line-breaks before and after long strings
--print-source, -p: add comments denoting the source file
--verbose, -v: add output information
--truncate-unused, -t: delete unused strings from files
## Script output
This section explains how the output of this script works, roughly. This script aims to make
the output more or less stable, i.e. given identical source files and arguments, the script
should produce the same output.
### Textdomain
The script will add (if not already present) a `# textdomain: <modname>` at the top, where
`<modname>` is identical to the mod directory name. If a `# textdomain` already exists, it
will be moved to the top, with the textdomain name being left intact (even if it differs
from the mod name).
**Note:** If there are multiple `# textdomain:` lines in the file, all of them except the
first one will be deleted. This script only supports one textdomain per `*.tr` file.
### Strings
The order of the strings is deterministic and follows certain rules: First, all strings are
grouped by the source `*.lua` file. The files are loaded in alphabetical order. In case of
subdirectories, the mod's root directory takes precedence, then the directories are traversed
in top-down alphabetical order. Second, within each file, the strings are then inserted in
the same order as they appear in the source code.
If a string appears multiple times in the source code, the string will be added when it was
first found only.
Don't bother to manually organize the order of the lines in the file yourself because the
script will just reorder everything.
If the mod's source changes in such a way that a line with an existing translation or comment
is no longer present, and `--truncate-unused` or `-t` are *not* provided as arguments, the
unused line will be moved to the bottom of the translation file under a special comment:
##### not used anymore #####
This allows for old translations and comments to be reused with new lines where appropriate.
This script doesn't attempt "fuzzy" matching of old strings to new, so even a single change
of punctuation or spelling will put strings into the "not used anymore" section and require
manual re-association with the new string.
### Comments
The script will preserve any comments in an existing `template.txt` or the various `*.tr`
files, associating them with the line that follows them. So for example:
# This comment pertains to Some Text
Some text=
# Multi-line comments
# are also supported
Text as well=
The script will also propagate comments from an existing `template.txt` to all `*.tr`
files and write it above existing comments (if exist).
There are also a couple of special comments that this script gives special treatment to.
#### Source file comments
If `--print-source` or `-p` is provided as option, the script will insert comments to show
from which file or files each string has come from.
This is the syntax of such a comment:
##[ file.lua ]##
This comment means that all lines following it belong to the file `file.lua`. In the special
case the same string was found in multiple files, multiple file name comments will be used in
row, like so:
##[ file1.lua ]##
##[ file2.lua ]##
##[ file3.lua ]##
example=Beispiel
This means the string "example" was found in the files `file1.lua`, `file2.lua` and
`file3.lua`.
If the print source option is not provided, these comments will disappear.
Note that all comments of the form `##[something]##` will be treated as "source file" comments
so they may be moved, changed or removed by the script at will.
#### "not used anymore" section
By default, the exact comment `##### not used anymore #####` will be automatically added to
mark the beginning of a section where old/unused strings will go. Leave the exact wording of
this comment intact so this line can be moved (or removed) properly in subsequent runs.
## Updating `builtin`
To update the `builtin` component of Minetest, change the working directory to `builtin` of
the Minetest source code repository, then run this script from there.

View File

@ -142,10 +142,10 @@ perform_release() {
local release_version=$1 local release_version=$1
RELEASE_DATE=$(date +%Y-%m-%d) RELEASE_DATE=$(date +%Y-%m-%d)
sed -i '/\<release/s/\(version\)="[^"]*"/\1="'"$release_version"'"/' misc/net.minetest.minetest.appdata.xml sed -i '/\<release/s/\(version\)="[^"]*"/\1="'"$release_version"'"/' misc/net.minetest.minetest.metainfo.xml
sed -i 's/\(<release date\)="[^"]*"/\1="'"$RELEASE_DATE"'"/' misc/net.minetest.minetest.appdata.xml sed -i 's/\(<release date\)="[^"]*"/\1="'"$RELEASE_DATE"'"/' misc/net.minetest.minetest.metainfo.xml
git add -f misc/net.minetest.minetest.appdata.xml git add -f misc/net.minetest.minetest.metainfo.xml
git commit -m "Bump version to $release_version" git commit -m "Bump version to $release_version"

View File

@ -1,538 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Script to generate Minetest translation template files and update
# translation files.
#
# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer,
# 2023 Wuzzy.
# License: LGPLv2.1 or later (see LICENSE file for details)
import os, fnmatch, re, shutil, errno
from sys import argv as _argv
from sys import stderr as _stderr
# Running params
params = {"recursive": False,
"help": False,
"verbose": False,
"folders": [],
"old-file": False,
"break-long-lines": False,
"print-source": False,
"truncate-unused": False,
}
# Available CLI options
options = {"recursive": ['--recursive', '-r'],
"help": ['--help', '-h'],
"verbose": ['--verbose', '-v'],
"old-file": ['--old-file', '-o'],
"break-long-lines": ['--break-long-lines', '-b'],
"print-source": ['--print-source', '-p'],
"truncate-unused": ['--truncate-unused', '-t'],
}
# Strings longer than this will have extra space added between
# them in the translation files to make it easier to distinguish their
# beginnings and endings at a glance
doublespace_threshold = 80
# These symbols mark comment lines showing the source file name.
# A comment may look like "##[ init.lua ]##".
symbol_source_prefix = "##["
symbol_source_suffix = "]##"
# comment to mark the section of old/unused strings
comment_unused = "##### not used anymore #####"
def set_params_folders(tab: list):
'''Initialize params["folders"] from CLI arguments.'''
# Discarding argument 0 (tool name)
for param in tab[1:]:
stop_param = False
for option in options:
if param in options[option]:
stop_param = True
break
if not stop_param:
params["folders"].append(os.path.abspath(param))
def set_params(tab: list):
'''Initialize params from CLI arguments.'''
for option in options:
for option_name in options[option]:
if option_name in tab:
params[option] = True
break
def print_help(name):
'''Prints some help message.'''
print(f'''SYNOPSIS
{name} [OPTIONS] [PATHS...]
DESCRIPTION
{', '.join(options["help"])}
prints this help message
{', '.join(options["recursive"])}
run on all subfolders of paths given
{', '.join(options["old-file"])}
create *.old files
{', '.join(options["break-long-lines"])}
add extra line breaks before and after long strings
{', '.join(options["print-source"])}
add comments denoting the source file
{', '.join(options["verbose"])}
add output information
{', '.join(options["truncate-unused"])}
delete unused strings from files
''')
def main():
'''Main function'''
set_params(_argv)
set_params_folders(_argv)
if params["help"]:
print_help(_argv[0])
else:
# Add recursivity message
print("Running ", end='')
if params["recursive"]:
print("recursively ", end='')
# Running
if len(params["folders"]) >= 2:
print("on folder list:", params["folders"])
for f in params["folders"]:
if params["recursive"]:
run_all_subfolders(f)
else:
update_folder(f)
elif len(params["folders"]) == 1:
print("on folder", params["folders"][0])
if params["recursive"]:
run_all_subfolders(params["folders"][0])
else:
update_folder(params["folders"][0])
else:
print("on folder", os.path.abspath("./"))
if params["recursive"]:
run_all_subfolders(os.path.abspath("./"))
else:
update_folder(os.path.abspath("./"))
# Compile pattern for matching lua function call
def compile_func_call_pattern(argument_pattern):
return re.compile(
# Look for beginning of file or anything that isn't a function identifier
r'(?:^|[\.=,{\(\s])' +
# Matches S, FS, NS, or NFS function call
r'N?F?S\s*' +
# The pattern to match argument
argument_pattern,
re.DOTALL)
# Add parentheses around a pattern
def parenthesize_pattern(pattern):
return (
# Start of argument: open parentheses and space (optional)
r'\(\s*' +
# The pattern to be parenthesized
pattern +
# End of argument or function call: space, comma, or close parentheses
r'[\s,\)]')
# Quoted string
# Group 2 will be the string, group 1 and group 3 will be the delimiters (" or ')
# See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
pattern_lua_quoted_string = r'(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)'
# Double square bracket string (multiline)
pattern_lua_square_bracket_string = r'\[\[(.*?)\]\]'
# Handles the " ... " or ' ... ' string delimiters
pattern_lua_quoted = compile_func_call_pattern(parenthesize_pattern(pattern_lua_quoted_string))
# Handles the [[ ... ]] string delimiters
pattern_lua_bracketed = compile_func_call_pattern(parenthesize_pattern(pattern_lua_square_bracket_string))
# Handles like pattern_lua_quoted, but for single parameter (without parentheses)
# See https://www.lua.org/pil/5.html for informations about single argument call
pattern_lua_quoted_single = compile_func_call_pattern(pattern_lua_quoted_string)
# Same as pattern_lua_quoted_single, but for [[ ... ]] string delimiters
pattern_lua_bracketed_single = compile_func_call_pattern(pattern_lua_square_bracket_string)
# Handles "concatenation" .. " of strings"
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
# Handles a translation line in *.tr file.
# Group 1 is the source string left of the equals sign.
# Group 2 is the translated string, right of the equals sign.
pattern_tr = re.compile(
r'(.*)' # Source string
# the separating equals sign, if NOT preceded by @, unless
# that @ is preceded by another @
r'(?:(?<!(?<!@)@)=)'
r'(.*)' # Translation string
)
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
pattern_tr_filename = re.compile(r'\.tr$')
# Matches bad use of @ signs in Lua string
pattern_bad_luastring = re.compile(
r'^@$|' # single @, OR
r'[^@]@$|' # trailing unescaped @, OR
r'(?<!@)@(?=[^@1-9n])' # an @ that is not escaped or part of a placeholder
)
# Attempt to read the mod's name from the mod.conf file or folder name. Returns None on failure
def get_modname(folder):
try:
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
for line in mod_conf:
match = pattern_name.match(line)
if match:
return match.group(1)
except FileNotFoundError:
folder_name = os.path.basename(folder)
# Special case when run in Minetest's builtin directory
return "__builtin" if folder_name == "builtin" else folder_name
# If there are already .tr files in /locale, returns a list of their names
def get_existing_tr_files(folder):
out = []
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
for name in files:
if pattern_tr_filename.search(name):
out.append(name)
return out
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
# Creates a directory if it doesn't exist, silently does
# nothing if it already exists
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else: raise
# Converts the template dictionary to a text to be written as a file
# dKeyStrings is a dictionary of localized string to source file sets
# dOld is a dictionary of existing translations and comments from
# the previous version of this text
def strings_to_text(dkeyStrings, dOld, mod_name, header_comments, textdomain, templ = None):
# if textdomain is specified, insert it at the top
if textdomain != None:
lOut = [textdomain] # argument is full textdomain line
# otherwise, use mod name as textdomain automatically
else:
lOut = [f"# textdomain: {mod_name}"]
if templ is not None and templ[2] and (header_comments is None or not header_comments.startswith(templ[2])):
# header comments in the template file
lOut.append(templ[2])
if header_comments is not None:
lOut.append(header_comments)
dGroupedBySource = {}
for key in dkeyStrings:
sourceList = list(dkeyStrings[key])
sourceString = "\n".join(sourceList)
listForSource = dGroupedBySource.get(sourceString, [])
listForSource.append(key)
dGroupedBySource[sourceString] = listForSource
lSourceKeys = list(dGroupedBySource.keys())
lSourceKeys.sort()
for source in lSourceKeys:
localizedStrings = dGroupedBySource[source]
if params["print-source"]:
if lOut[-1] != "":
lOut.append("")
lOut.append(source)
for localizedString in localizedStrings:
val = dOld.get(localizedString, {})
translation = val.get("translation", "")
comment = val.get("comment")
templ_comment = None
if templ:
templ_val = templ[0].get(localizedString, {})
templ_comment = templ_val.get("comment")
if params["break-long-lines"] and len(localizedString) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if templ_comment != None and templ_comment != "" and (comment is None or comment == "" or not comment.startswith(templ_comment)):
lOut.append(templ_comment)
if comment != None and comment != "" and not comment.startswith("# textdomain:"):
lOut.append(comment)
lOut.append(f"{localizedString}={translation}")
if params["break-long-lines"] and len(localizedString) > doublespace_threshold:
lOut.append("")
unusedExist = False
if not params["truncate-unused"]:
for key in dOld:
if key not in dkeyStrings:
val = dOld[key]
translation = val.get("translation")
comment = val.get("comment")
# only keep an unused translation if there was translated
# text or a comment associated with it
if translation != None and (translation != "" or comment):
if not unusedExist:
unusedExist = True
lOut.append("\n\n" + comment_unused + "\n")
if params["break-long-lines"] and len(key) > doublespace_threshold and not lOut[-1] == "":
lOut.append("")
if comment != None:
lOut.append(comment)
lOut.append(f"{key}={translation}")
if params["break-long-lines"] and len(key) > doublespace_threshold:
lOut.append("")
return "\n".join(lOut) + '\n'
# Writes a template.txt file
# dkeyStrings is the dictionary returned by generate_template
def write_template(templ_file, dkeyStrings, mod_name):
# read existing template file to preserve comments
existing_template = import_tr_file(templ_file)
text = strings_to_text(dkeyStrings, existing_template[0], mod_name, existing_template[2], existing_template[3])
mkdir_p(os.path.dirname(templ_file))
with open(templ_file, "wt", encoding='utf-8') as template_file:
template_file.write(text)
# Gets all translatable strings from a lua file
def read_lua_file_strings(lua_file):
lOut = []
with open(lua_file, encoding='utf-8') as text_file:
text = text_file.read()
strings = []
for s in pattern_lua_quoted_single.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed_single.findall(text):
strings.append(s)
# Only concatenate strings after matching
# single parameter call (without parantheses)
text = re.sub(pattern_concat, "", text)
for s in pattern_lua_quoted.findall(text):
strings.append(s[1])
for s in pattern_lua_bracketed.findall(text):
strings.append(s)
for s in strings:
found_bad = pattern_bad_luastring.search(s)
if found_bad:
print("SYNTAX ERROR: Unescaped '@' in Lua string: " + s)
continue
s = s.replace('\\"', '"')
s = s.replace("\\'", "'")
s = s.replace("\n", "@n")
s = s.replace("\\n", "@n")
s = s.replace("=", "@=")
lOut.append(s)
return lOut
# Gets strings from an existing translation file
# returns both a dictionary of translations
# and the full original source text so that the new text
# can be compared to it for changes.
# Returns also header comments in the third return value.
def import_tr_file(tr_file):
dOut = {}
text = None
in_header = True
header_comments = None
textdomain = None
if os.path.exists(tr_file):
with open(tr_file, "r", encoding='utf-8') as existing_file :
# save the full text to allow for comparison
# of the old version with the new output
text = existing_file.read()
existing_file.seek(0)
# a running record of the current comment block
# we're inside, to allow preceeding multi-line comments
# to be retained for a translation line
latest_comment_block = None
for line in existing_file.readlines():
line = line.rstrip('\n')
# "##### not used anymore #####" comment
if line == comment_unused:
# Always delete the 'not used anymore' comment.
# It will be re-added to the file if neccessary.
latest_comment_block = None
if header_comments != None:
in_header = False
continue
# Comment lines
elif line.startswith("#"):
# Source file comments: ##[ file.lua ]##
if line.startswith(symbol_source_prefix) and line.endswith(symbol_source_suffix):
# This line marks the end of header comments.
if params["print-source"]:
in_header = False
# Remove those comments; they may be added back automatically.
continue
# Store first occurance of textdomain
# discard all subsequent textdomain lines
if line.startswith("# textdomain:"):
if textdomain == None:
textdomain = line
continue
elif in_header:
# Save header comments (normal comments at top of file)
if not header_comments:
header_comments = line
else:
header_comments = header_comments + "\n" + line
else:
# Save normal comments
if line.startswith("# textdomain:") and textdomain == None:
textdomain = line
elif not latest_comment_block:
latest_comment_block = line
else:
latest_comment_block = latest_comment_block + "\n" + line
continue
match = pattern_tr.match(line)
if match:
# this line is a translated line
outval = {}
outval["translation"] = match.group(2)
if latest_comment_block:
# if there was a comment, record that.
outval["comment"] = latest_comment_block
latest_comment_block = None
in_header = False
dOut[match.group(1)] = outval
return (dOut, text, header_comments, textdomain)
# like os.walk but returns sorted filenames
def sorted_os_walk(folder):
tuples = []
t = 0
for root, dirs, files in os.walk(folder):
tuples.append( (root, dirs, files) )
t = t + 1
tuples = sorted(tuples)
paths_and_files = []
f = 0
for tu in tuples:
root = tu[0]
dirs = tu[1]
files = tu[2]
files = sorted(files, key=str.lower)
for filename in files:
paths_and_files.append( (os.path.join(root, filename), filename) )
f = f + 1
return paths_and_files
# Walks all lua files in the mod folder, collects translatable strings,
# and writes it to a template.txt file
# Returns a dictionary of localized strings to source file lists
# that can be used with the strings_to_text function.
def generate_template(folder, mod_name):
dOut = {}
paths_and_files = sorted_os_walk(folder)
for paf in paths_and_files:
fullpath_filename = paf[0]
filename = paf[1]
if fnmatch.fnmatch(filename, "*.lua"):
found = read_lua_file_strings(fullpath_filename)
if params["verbose"]:
print(f"{fullpath_filename}: {str(len(found))} translatable strings")
for s in found:
sources = dOut.get(s, set())
sources.add(os.path.relpath(fullpath_filename, start=folder))
dOut[s] = sources
if len(dOut) == 0:
return (None, None)
# Convert source file set to list, sort it and add comment symbols.
# Needed because a set is unsorted and might result in unpredictable.
# output orders if any source string appears in multiple files.
for d in dOut:
sources = dOut.get(d, set())
sources = sorted(list(sources), key=str.lower)
newSources = []
for i in sources:
i = i.replace("\\", "/")
newSources.append(f"{symbol_source_prefix} {i} {symbol_source_suffix}")
dOut[d] = newSources
templ_file = os.path.join(folder, "locale/template.txt")
write_template(templ_file, dOut, mod_name)
new_template = import_tr_file(templ_file) # re-import to get all new data
return (dOut, new_template)
# Updates an existing .tr file, copying the old one to a ".old" file
# if any changes have happened
# dNew is the data used to generate the template, it has all the
# currently-existing localized strings
def update_tr_file(dNew, templ, mod_name, tr_file):
if params["verbose"]:
print(f"updating {tr_file}")
tr_import = import_tr_file(tr_file)
dOld = tr_import[0]
textOld = tr_import[1]
textNew = strings_to_text(dNew, dOld, mod_name, tr_import[2], tr_import[3], templ)
if textOld and textOld != textNew:
print(f"{tr_file} has changed.")
if params["old-file"]:
shutil.copyfile(tr_file, f"{tr_file}.old")
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
new_tr_file.write(textNew)
# Updates translation files for the mod in the given folder
def update_mod(folder):
if not os.path.exists(os.path.join(folder, "init.lua")):
print(f"Mod folder {folder} is missing init.lua, aborting.")
exit(1)
assert not is_modpack(folder)
modname = get_modname(folder)
print(f"Updating translations for {modname}")
(data, templ) = generate_template(folder, modname)
if data == None:
print(f"No translatable strings found in {modname}")
else:
for tr_file in get_existing_tr_files(folder):
update_tr_file(data, templ, modname, os.path.join(folder, "locale/", tr_file))
def is_modpack(folder):
return os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
def is_game(folder):
return os.path.exists(os.path.join(folder, "game.conf")) and os.path.exists(os.path.join(folder, "mods"))
# Determines if the folder being pointed to is a game, mod or a mod pack
# and then runs update_mod accordingly
def update_folder(folder):
if is_game(folder):
run_all_subfolders(os.path.join(folder, "mods"))
elif is_modpack(folder):
run_all_subfolders(folder)
else:
update_mod(folder)
print("Done.")
def run_all_subfolders(folder):
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir() and not f.name.startswith('.')]:
update_folder(modfolder)
main()