forked from Mirrorlandia_minetest/minetest
Merge pull request 'master' (#1) from Mirrorlandia_minetest/minetest:master into master
Reviewed-on: #1
This commit is contained in:
commit
ff473180db
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -177,7 +177,6 @@ jobs:
|
||||
run: |
|
||||
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin32.sh winbuild
|
||||
env:
|
||||
NO_MINETEST_GAME: 1
|
||||
NO_PACKAGE: 1
|
||||
|
||||
win64:
|
||||
@ -195,15 +194,14 @@ jobs:
|
||||
run: |
|
||||
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin64.sh winbuild
|
||||
env:
|
||||
NO_MINETEST_GAME: 1
|
||||
NO_PACKAGE: 1
|
||||
|
||||
msvc:
|
||||
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
|
||||
runs-on: windows-2019
|
||||
env:
|
||||
VCPKG_VERSION: 5cf60186a241e84e8232641ee973395d4fde90e1
|
||||
# 2022.02
|
||||
VCPKG_VERSION: 8eb57355a4ffb410a2e94c07b4dca2dffbee8e50
|
||||
# 2023.10.19
|
||||
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
6
.github/workflows/macos.yml
vendored
6
.github/workflows/macos.yml
vendored
@ -21,11 +21,6 @@ on:
|
||||
- 'cmake/Modules/**'
|
||||
- '.github/workflows/macos.yml'
|
||||
|
||||
env:
|
||||
MINETEST_GAME_REPO: https://github.com/minetest/minetest_game.git
|
||||
MINETEST_GAME_BRANCH: master
|
||||
MINETEST_GAME_NAME: minetest_game
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
@ -38,7 +33,6 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
git clone -b $MINETEST_GAME_BRANCH $MINETEST_GAME_REPO games/$MINETEST_GAME_NAME
|
||||
git clone https://github.com/minetest/irrlicht lib/irrlichtmt --depth 1 -b $(cat misc/irrlichtmt_tag.txt)
|
||||
mkdir build
|
||||
cd build
|
||||
|
@ -9,7 +9,6 @@ stages:
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
|
||||
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
|
||||
|
||||
.build_template:
|
||||
@ -120,8 +119,6 @@ package:appimage-client:
|
||||
- mkdir AppDir
|
||||
- cp -a artifact/minetest/usr/ AppDir/usr/
|
||||
- cp -a clientmods AppDir/usr/share/minetest
|
||||
- git clone $MINETEST_GAME_REPO AppDir/usr/share/minetest/games/minetest_game
|
||||
- rm -rf AppDir/usr/share/minetest/games/minetest_game/.git
|
||||
# Remove PrefersNonDefaultGPU property due to validation errors
|
||||
- sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop
|
||||
script:
|
||||
|
@ -262,9 +262,6 @@ if(RUN_IN_PLACE)
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/texture_packs_here.txt" DESTINATION "${SHAREDIR}/textures")
|
||||
endif()
|
||||
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game" DESTINATION "${SHAREDIR}/games/"
|
||||
COMPONENT "SUBGAME_MINETEST_GAME" OPTIONAL PATTERN ".git*" EXCLUDE )
|
||||
|
||||
set(INSTALL_DEVTEST FALSE CACHE BOOL "Install Development Test")
|
||||
|
||||
if(INSTALL_DEVTEST)
|
||||
@ -286,7 +283,7 @@ install(FILES "doc/lua_api.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/client_lua_api.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/menu_lua_api.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/texture_packs.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/world_format.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/world_format.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
@ -336,16 +333,6 @@ cpack_add_component(Docs
|
||||
DESCRIPTION "Documentation about Minetest and Minetest modding"
|
||||
)
|
||||
|
||||
cpack_add_component(SUBGAME_MINETEST_GAME
|
||||
DISPLAY_NAME "Minetest Game"
|
||||
DESCRIPTION "The default game bundled in the Minetest engine. Mainly used as a modding base."
|
||||
GROUP "Games"
|
||||
)
|
||||
|
||||
cpack_add_component_group(Subgames
|
||||
DESCRIPTION "Games for the Minetest engine."
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
# Include all dynamically linked runtime libraries such as MSVCRxxx.dll
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
@ -1,7 +1,6 @@
|
||||
ARG DOCKER_IMAGE=alpine:3.16
|
||||
FROM $DOCKER_IMAGE AS dev
|
||||
|
||||
ENV MINETEST_GAME_VERSION master
|
||||
ENV IRRLICHT_VERSION master
|
||||
ENV SPATIALINDEX_VERSION 1.9.3
|
||||
ENV LUAJIT_VERSION v2.1
|
||||
@ -52,9 +51,7 @@ COPY src /usr/src/minetest/src
|
||||
COPY textures /usr/src/minetest/textures
|
||||
|
||||
WORKDIR /usr/src/minetest
|
||||
RUN git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \
|
||||
rm -fr ./games/minetest_game/.git && \
|
||||
cmake -B build \
|
||||
RUN cmake -B build \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SERVER=TRUE \
|
||||
|
@ -10,12 +10,6 @@ Minetest is a free open-source voxel game engine with easy modding and game crea
|
||||
Copyright (C) 2010-2022 Perttu Ahola <celeron55@gmail.com>
|
||||
and contributors (see source file comments and the version control log)
|
||||
|
||||
In case you downloaded the source code
|
||||
--------------------------------------
|
||||
If you downloaded the Minetest Engine source code in which this file is
|
||||
contained, you probably want to download the [Minetest Game](https://github.com/minetest/minetest_game/)
|
||||
project too. See its README.txt for more information.
|
||||
|
||||
Table of Contents
|
||||
------------------
|
||||
|
||||
|
@ -54,7 +54,6 @@ android {
|
||||
task prepareAssets() {
|
||||
def assetsFolder = "build/assets"
|
||||
def projRoot = rootDir.parent
|
||||
def gameToCopy = "minetest_game"
|
||||
|
||||
// See issue #4638
|
||||
def unsupportedLanguages = new File("${projRoot}/src/unsupported_language_list.txt").text.readLines()
|
||||
@ -81,9 +80,6 @@ task prepareAssets() {
|
||||
copy {
|
||||
from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts"
|
||||
}
|
||||
copy {
|
||||
from "${projRoot}/games/${gameToCopy}" into "${assetsFolder}/games/${gameToCopy}"
|
||||
}
|
||||
copy {
|
||||
from "${projRoot}/textures" into "${assetsFolder}/textures"
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ public class Utils {
|
||||
public static boolean isInstallValid(@NonNull Context context) {
|
||||
File userDataDirectory = getUserDataDirectory(context);
|
||||
return userDataDirectory.isDirectory() &&
|
||||
new File(userDataDirectory, "games").isDirectory() &&
|
||||
new File(userDataDirectory, "builtin").isDirectory() &&
|
||||
new File(userDataDirectory, "client").isDirectory() &&
|
||||
new File(userDataDirectory, "textures").isDirectory();
|
||||
|
@ -27,6 +27,8 @@ core.features = {
|
||||
get_light_data_buffer = true,
|
||||
mod_storage_on_disk = true,
|
||||
compress_zstd = true,
|
||||
sound_params_start_time = true,
|
||||
physics_overrides_v2 = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
@ -698,17 +698,14 @@ local function resolve_auto_install_spec()
|
||||
local resolved = nil
|
||||
|
||||
for _, pkg in ipairs(store.packages_full_unordered) do
|
||||
if pkg.author == auto_install_spec.author and
|
||||
(pkg.name == auto_install_spec.name or
|
||||
(pkg.type == "game" and pkg.name == auto_install_spec.name .. "_game")) then
|
||||
if pkg.id == auto_install_spec then
|
||||
resolved = pkg
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not resolved then
|
||||
gamedata.errormessage = fgettext("The package $1/$2 was not found.",
|
||||
auto_install_spec.author, auto_install_spec.name)
|
||||
gamedata.errormessage = fgettext("The package $1 was not found.", auto_install_spec)
|
||||
ui.update()
|
||||
|
||||
auto_install_spec = nil
|
||||
@ -777,26 +774,26 @@ function store.update_paths()
|
||||
local mod_hash = {}
|
||||
pkgmgr.refresh_globals()
|
||||
for _, mod in pairs(pkgmgr.global_mods:get_list()) do
|
||||
if mod.author and mod.release > 0 then
|
||||
local id = mod.author:lower() .. "/" .. mod.name
|
||||
mod_hash[store.aliases[id] or id] = mod
|
||||
local cdb_id = pkgmgr.get_contentdb_id(mod)
|
||||
if cdb_id then
|
||||
mod_hash[store.aliases[cdb_id] or cdb_id] = mod
|
||||
end
|
||||
end
|
||||
|
||||
local game_hash = {}
|
||||
pkgmgr.update_gamelist()
|
||||
for _, game in pairs(pkgmgr.games) do
|
||||
if game.author ~= "" and game.release > 0 then
|
||||
local id = game.author:lower() .. "/" .. game.id
|
||||
game_hash[store.aliases[id] or id] = game
|
||||
local cdb_id = pkgmgr.get_contentdb_id(game)
|
||||
if cdb_id then
|
||||
game_hash[store.aliases[cdb_id] or cdb_id] = game
|
||||
end
|
||||
end
|
||||
|
||||
local txp_hash = {}
|
||||
for _, txp in pairs(pkgmgr.get_texture_packs()) do
|
||||
if txp.author and txp.release > 0 then
|
||||
local id = txp.author:lower() .. "/" .. txp.name
|
||||
txp_hash[store.aliases[id] or id] = txp
|
||||
local cdb_id = pkgmgr.get_contentdb_id(txp)
|
||||
if cdb_id then
|
||||
txp_hash[store.aliases[cdb_id] or cdb_id] = txp
|
||||
end
|
||||
end
|
||||
|
||||
@ -815,6 +812,7 @@ function store.update_paths()
|
||||
package.installed_release = content.release or 0
|
||||
else
|
||||
package.path = nil
|
||||
package.installed_release = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1193,7 +1191,7 @@ end
|
||||
--- @param type string | nil
|
||||
--- Sets initial package filter. "game", "mod", "txp" or nil (no filter).
|
||||
--- @param install_spec table | nil
|
||||
--- Package specification of the form { author = string, name = string }.
|
||||
--- ContentDB ID of package as returned by pkgmgr.get_contentdb_id().
|
||||
--- Sets package to install or update automatically.
|
||||
function create_store_dlg(type, install_spec)
|
||||
search_string = ""
|
||||
|
@ -777,6 +777,30 @@ function pkgmgr.update_gamelist()
|
||||
end)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Returns the ContentDB ID for an installed piece of content.
|
||||
function pkgmgr.get_contentdb_id(content)
|
||||
-- core.get_games() will return "" instead of nil if there is no "author" field.
|
||||
if content.author and content.author ~= "" and content.release > 0 then
|
||||
if content.type == "game" then
|
||||
return content.author:lower() .. "/" .. content.id
|
||||
end
|
||||
return content.author:lower() .. "/" .. content.name
|
||||
end
|
||||
|
||||
-- Until Minetest 5.8.0, Minetest Game was bundled with Minetest.
|
||||
-- Unfortunately, the bundled MTG was not versioned (missing "release"
|
||||
-- field in game.conf).
|
||||
-- Therefore, we consider any installation of MTG that is not versioned,
|
||||
-- has not been cloned from Git, and is not system-wide to be updatable.
|
||||
if content.type == "game" and content.id == "minetest" and content.release == 0 and
|
||||
not core.is_dir(content.path .. "/.git") and core.may_modify_path(content.path) then
|
||||
return "minetest/minetest"
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- read initial data
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -59,7 +59,7 @@ local function has_packages_from_cdb()
|
||||
pkgmgr.update_gamelist()
|
||||
|
||||
for _, content in pairs(pkgmgr.get_all()) do
|
||||
if content.author and content.release > 0 then
|
||||
if pkgmgr.get_contentdb_id(content) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
@ -114,18 +114,13 @@ function update_detector.get_all()
|
||||
local ret = {}
|
||||
local all_content = pkgmgr.get_all()
|
||||
for _, content in ipairs(all_content) do
|
||||
if content.author and content.release > 0 then
|
||||
-- The backend will account for aliases in `latest_releases`
|
||||
local id = content.author:lower() .. "/"
|
||||
if content.type == "game" then
|
||||
id = id .. content.id
|
||||
else
|
||||
id = id .. content.name
|
||||
end
|
||||
local cdb_id = pkgmgr.get_contentdb_id(content)
|
||||
|
||||
local latest_release = latest_releases[id]
|
||||
if cdb_id then
|
||||
-- The backend will account for aliases in `latest_releases`
|
||||
local latest_release = latest_releases[cdb_id]
|
||||
if not latest_release and content.type == "game" then
|
||||
latest_release = latest_releases[id .. "_game"]
|
||||
latest_release = latest_releases[cdb_id .. "_game"]
|
||||
end
|
||||
|
||||
if latest_release and latest_release > content.release then
|
||||
|
@ -78,7 +78,7 @@ local function buttonhandler(this, fields)
|
||||
|
||||
local maintab = ui.find_by_name("maintab")
|
||||
|
||||
local dlg = create_store_dlg(nil, { author = "Minetest", name = "minetest_game" })
|
||||
local dlg = create_store_dlg(nil, "minetest/minetest")
|
||||
dlg:set_parent(maintab)
|
||||
maintab:hide()
|
||||
dlg:show()
|
||||
|
@ -27,7 +27,6 @@ local full_settings = settingtypes.parse_config_file(false, true)
|
||||
local info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png")
|
||||
local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png")
|
||||
|
||||
local gettext = fgettext_ne
|
||||
local all_pages = {}
|
||||
local page_by_id = {}
|
||||
local filtered_pages = all_pages
|
||||
@ -66,23 +65,23 @@ local change_keys = {
|
||||
|
||||
add_page({
|
||||
id = "accessibility",
|
||||
title = gettext("Accessibility"),
|
||||
title = fgettext_ne("Accessibility"),
|
||||
content = {
|
||||
"language",
|
||||
{ heading = gettext("General") },
|
||||
{ heading = fgettext_ne("General") },
|
||||
"font_size",
|
||||
"chat_font_size",
|
||||
"gui_scaling",
|
||||
"hud_scaling",
|
||||
"show_nametag_backgrounds",
|
||||
{ heading = gettext("Chat") },
|
||||
{ heading = fgettext_ne("Chat") },
|
||||
"console_height",
|
||||
"console_alpha",
|
||||
"console_color",
|
||||
{ heading = gettext("Controls") },
|
||||
{ heading = fgettext_ne("Controls") },
|
||||
"autojump",
|
||||
"safe_dig_and_place",
|
||||
{ heading = gettext("Movement") },
|
||||
{ heading = fgettext_ne("Movement") },
|
||||
"arm_inertia",
|
||||
"view_bobbing_amount",
|
||||
"fall_bobbing_amount",
|
||||
@ -97,7 +96,7 @@ local function load_settingtypes()
|
||||
if not page then
|
||||
page = add_page({
|
||||
id = (section or "general"):lower():gsub(" ", "_"),
|
||||
title = section or gettext("General"),
|
||||
title = section or fgettext_ne("General"),
|
||||
section = section,
|
||||
content = {},
|
||||
})
|
||||
@ -117,13 +116,11 @@ local function load_settingtypes()
|
||||
content = {},
|
||||
}
|
||||
|
||||
if page.title:sub(1, 5) ~= "Hide:" then
|
||||
page = add_page(page)
|
||||
end
|
||||
elseif entry.level == 2 then
|
||||
ensure_page_started()
|
||||
page.content[#page.content + 1] = {
|
||||
heading = gettext(entry.readable_name or entry.name),
|
||||
heading = fgettext_ne(entry.readable_name or entry.name),
|
||||
}
|
||||
end
|
||||
else
|
||||
|
@ -1,5 +1,3 @@
|
||||
local settings = ...
|
||||
|
||||
local concat = table.concat
|
||||
local insert = table.insert
|
||||
local sprintf = string.format
|
||||
@ -36,7 +34,7 @@ local group_format_template = [[
|
||||
|
||||
]]
|
||||
|
||||
local function create_minetest_conf_example()
|
||||
local function create_minetest_conf_example(settings)
|
||||
local result = { minetest_example_header }
|
||||
for _, entry in ipairs(settings) do
|
||||
if entry.type == "category" then
|
||||
@ -108,14 +106,11 @@ local translation_file_header = [[
|
||||
|
||||
fake_function() {]]
|
||||
|
||||
local function create_translation_file()
|
||||
local function create_translation_file(settings)
|
||||
local result = { translation_file_header }
|
||||
for _, entry in ipairs(settings) do
|
||||
if entry.type == "category" then
|
||||
insert(result, sprintf("\tgettext(%q);", entry.name))
|
||||
elseif entry.type == "key" then --luacheck: ignore
|
||||
-- Neither names nor descriptions of keys are used since we have a
|
||||
-- dedicated menu for them.
|
||||
else
|
||||
if entry.readable_name then
|
||||
insert(result, sprintf("\tgettext(%q);", entry.readable_name))
|
||||
@ -132,12 +127,13 @@ local function create_translation_file()
|
||||
end
|
||||
|
||||
local file = assert(io.open("minetest.conf.example", "w"))
|
||||
file:write(create_minetest_conf_example())
|
||||
file:write(create_minetest_conf_example(settingtypes.parse_config_file(true, false)))
|
||||
file:close()
|
||||
|
||||
file = assert(io.open("src/settings_translation_file.cpp", "w"))
|
||||
-- If 'minetest.conf.example' appears in the 'bin' folder, the line below may have to be
|
||||
-- used instead. The file will also appear in the 'bin' folder.
|
||||
--file = assert(io.open("settings_translation_file.cpp", "w"))
|
||||
file:write(create_translation_file())
|
||||
-- We don't want hidden settings to be translated, so we set read_all to false.
|
||||
file:write(create_translation_file(settingtypes.parse_config_file(false, false)))
|
||||
file:close()
|
||||
|
@ -25,4 +25,4 @@ dofile(path .. DIR_DELIM .. "dlg_settings.lua")
|
||||
-- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
|
||||
-- See comment and alternative line at the end of 'generate_from_settingtypes.lua'.
|
||||
|
||||
-- assert(loadfile(path .. DIR_DELIM .. "generate_from_settingtypes.lua"))(settingtypes.parse_config_file(true, false))
|
||||
-- dofile(path .. DIR_DELIM .. "generate_from_settingtypes.lua")
|
||||
|
@ -70,14 +70,37 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||
-- category
|
||||
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
|
||||
if category then
|
||||
local category_level = stars:len() + base_level
|
||||
|
||||
if settings.current_hide_level then
|
||||
if settings.current_hide_level < category_level then
|
||||
-- Skip this category, it's inside a hidden category.
|
||||
return
|
||||
else
|
||||
-- The start of this category marks the end of a hidden category.
|
||||
settings.current_hide_level = nil
|
||||
end
|
||||
end
|
||||
|
||||
if not read_all and category:sub(1, 5) == "Hide:" then
|
||||
-- This category is hidden.
|
||||
settings.current_hide_level = category_level
|
||||
return
|
||||
end
|
||||
|
||||
table.insert(settings, {
|
||||
name = category,
|
||||
level = stars:len() + base_level,
|
||||
level = category_level,
|
||||
type = "category",
|
||||
})
|
||||
return
|
||||
end
|
||||
|
||||
if settings.current_hide_level then
|
||||
-- Ignore this line, we're inside a hidden category.
|
||||
return
|
||||
end
|
||||
|
||||
-- settings
|
||||
local first_part, name, readable_name, setting_type = line:match("^"
|
||||
-- this first capture group matches the whole first part,
|
||||
@ -349,6 +372,7 @@ end
|
||||
local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
|
||||
-- store this helper variable in the table so it's easier to pass to parse_setting_line()
|
||||
result.current_comment = {}
|
||||
result.current_hide_level = nil
|
||||
|
||||
local line = file:read("*line")
|
||||
while line do
|
||||
@ -360,6 +384,7 @@ local function parse_single_file(file, filepath, read_all, result, base_level, a
|
||||
end
|
||||
|
||||
result.current_comment = nil
|
||||
result.current_hide_level = nil
|
||||
end
|
||||
|
||||
|
||||
|
@ -254,7 +254,7 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
|
||||
|
||||
if fields.btn_mod_mgr_update then
|
||||
local pkg = packages:get_list()[tabdata.selected_pkg]
|
||||
local dlg = create_store_dlg(nil, { author = pkg.author, name = pkg.id or pkg.name })
|
||||
local dlg = create_store_dlg(nil, pkgmgr.get_contentdb_id(pkg))
|
||||
dlg:set_parent(tabview)
|
||||
tabview:hide()
|
||||
dlg:show()
|
||||
|
@ -26,7 +26,7 @@ For Fedora users:
|
||||
|
||||
For openSUSE users:
|
||||
|
||||
sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel
|
||||
sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel
|
||||
|
||||
For Arch users:
|
||||
|
||||
@ -69,10 +69,6 @@ Download source (this is the URL to the latest of source repository, which might
|
||||
git clone --depth 1 https://github.com/minetest/minetest.git
|
||||
cd minetest
|
||||
|
||||
Download Minetest Game (otherwise only the "Development Test" game is available) using Git:
|
||||
|
||||
git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
|
||||
|
||||
Download IrrlichtMt to `lib/irrlichtmt`, it will be used to satisfy the IrrlichtMt dependency that way:
|
||||
|
||||
git clone --depth 1 https://github.com/minetest/irrlicht.git lib/irrlichtmt
|
||||
@ -83,14 +79,6 @@ Download source, without using Git:
|
||||
tar xf master.tar.gz
|
||||
cd minetest-master
|
||||
|
||||
Download Minetest Game, without using Git:
|
||||
|
||||
cd games/
|
||||
wget https://github.com/minetest/minetest_game/archive/master.tar.gz
|
||||
tar xf master.tar.gz
|
||||
mv minetest_game-master minetest_game
|
||||
cd ..
|
||||
|
||||
Download IrrlichtMt, without using Git:
|
||||
|
||||
cd lib/
|
||||
|
@ -20,12 +20,6 @@ git clone --depth 1 https://github.com/minetest/minetest.git
|
||||
cd minetest
|
||||
```
|
||||
|
||||
Download Minetest Game (otherwise only the "Development Test" game is available) using Git:
|
||||
|
||||
```
|
||||
git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
|
||||
```
|
||||
|
||||
Download Minetest's fork of Irrlicht:
|
||||
|
||||
```
|
||||
|
@ -1091,6 +1091,7 @@ Table used to specify how a sound is played:
|
||||
-- its end in `-start_time` seconds.
|
||||
-- It is unspecified what happens if `loop` is false and `start_time` is
|
||||
-- smaller than minus the sound's length.
|
||||
-- Available since feature `sound_params_start_time`.
|
||||
|
||||
loop = false,
|
||||
-- If true, sound is played in a loop.
|
||||
@ -1629,7 +1630,7 @@ HUD
|
||||
HUD element types
|
||||
-----------------
|
||||
|
||||
The position field is used for all element types.
|
||||
The `position` field is used for all element types.
|
||||
To account for differing resolutions, the position coordinates are the
|
||||
percentage of the screen, ranging in value from `0` to `1`.
|
||||
|
||||
@ -2148,11 +2149,13 @@ to games.
|
||||
* `fall_damage_add_percent`: modifies the fall damage suffered when hitting
|
||||
the top of this node. There's also an armor group with the same name.
|
||||
The final player damage is determined by the following formula:
|
||||
```lua
|
||||
damage =
|
||||
collision speed
|
||||
* ((node_fall_damage_add_percent + 100) / 100) -- node group
|
||||
* ((player_fall_damage_add_percent + 100) / 100) -- player armor group
|
||||
- (14) -- constant tolerance
|
||||
```
|
||||
Negative damage values are discarded as no damage.
|
||||
* `falling_node`: if there is no walkable block under the node it will fall
|
||||
* `float`: the node will not fall through liquids (`liquidtype ~= "none"`)
|
||||
@ -4006,9 +4009,9 @@ Translations
|
||||
Texts can be translated client-side with the help of `minetest.translate` and
|
||||
translation files.
|
||||
|
||||
Consider using the script `util/mtt_update.py` in the Minetest repository
|
||||
to generate and update translation files automatically from the Lua sources.
|
||||
See `util/README_mtt_update.md` for an explanation.
|
||||
Consider using the script `util/mod_translation_updater.py` in the Minetest
|
||||
repository to generate and update translation files automatically from the Lua
|
||||
sources. See `util/README_mod_translation_updater.md` for an explanation.
|
||||
|
||||
Translating a string
|
||||
--------------------
|
||||
@ -4111,9 +4114,10 @@ On some specific cases, server translation could be useful. For example, filter
|
||||
a list on labels and send results to client. A method is supplied to achieve
|
||||
that:
|
||||
|
||||
`minetest.get_translated_string(lang_code, string)`: Translates `string` using
|
||||
translations for `lang_code` language. It gives the same result as if the string
|
||||
was translated by the client.
|
||||
`minetest.get_translated_string(lang_code, string)`: resolves translations in
|
||||
the given string just like the client would, using the translation files for
|
||||
`lang_code`. For this to have any effect, the string needs to contain translation
|
||||
markup, e.g. `minetest.get_translated_string("fr", S("Hello"))`.
|
||||
|
||||
The `lang_code` to use for a given player can be retrieved from
|
||||
the table returned by `minetest.get_player_information(name)`.
|
||||
@ -5268,6 +5272,12 @@ Utilities
|
||||
mod_storage_on_disk = true,
|
||||
-- "zstd" method for compress/decompress (5.7.0)
|
||||
compress_zstd = true,
|
||||
-- Sound parameter tables support start_time (5.8.0)
|
||||
sound_params_start_time = true,
|
||||
-- New fields for set_physics_override: speed_climb, speed_crouch,
|
||||
-- liquid_fluidity, liquid_fluidity_smooth, liquid_sink,
|
||||
-- acceleration_default, acceleration_air (5.8.0)
|
||||
physics_overrides_v2 = true,
|
||||
}
|
||||
```
|
||||
|
||||
@ -7750,6 +7760,8 @@ child will follow movement and rotation of that bone.
|
||||
settings (e.g. via the game's `minetest.conf`) to set a global base value
|
||||
for all players and only use `set_physics_override` when you need to change
|
||||
from the base value on a per-player basis
|
||||
* Note: Some of the fields don't exist in old API versions, see feature
|
||||
`physics_overrides_v2`.
|
||||
|
||||
* `get_physics_override()`: returns the table given to `set_physics_override`
|
||||
* `hud_add(hud definition)`: add a HUD element described by HUD def, returns ID
|
||||
|
627
doc/world_format.md
Normal file
627
doc/world_format.md
Normal file
@ -0,0 +1,627 @@
|
||||
# Minetest World Format 22...29
|
||||
|
||||
This applies to a world format carrying the block serialization version
|
||||
22...27, used at least in
|
||||
* `0.4.dev-20120322` ... `0.4.dev-20120606` (22...23)
|
||||
* `0.4.0` (23)
|
||||
* 24 was never released as stable and existed for ~2 days
|
||||
* 27 was added in `0.4.15-dev`
|
||||
* 29 was added in `5.5.0-dev`
|
||||
|
||||
The block serialization version does not fully specify every aspect of this
|
||||
format; if compliance with this format is to be checked, it needs to be
|
||||
done by detecting if the files and data indeed follows it.
|
||||
|
||||
# Files
|
||||
|
||||
Everything is contained in a directory, the name of which is freeform, but
|
||||
often serves as the name of the world.
|
||||
|
||||
Currently, the authentication and ban data is stored on a per-world basis.
|
||||
It can be copied over from an old world to a newly created world.
|
||||
|
||||
World
|
||||
├── auth.txt ───── Authentication data
|
||||
├── auth.sqlite ── Authentication data (SQLite alternative)
|
||||
├── env_meta.txt ─ Environment metadata
|
||||
├── ipban.txt ──── Banned IPs/users
|
||||
├── map_meta.txt ─ Map metadata
|
||||
├── map.sqlite ─── Map data
|
||||
├── players ────── Player directory
|
||||
│ │── player1 ── Player file
|
||||
│ └── Foo ────── Player file
|
||||
└── world.mt ───── World metadata
|
||||
|
||||
## `auth.txt`
|
||||
|
||||
Contains authentication data, one player per line.
|
||||
|
||||
<name>:<password hash>:<privilege1,...>
|
||||
|
||||
Legacy format (until 0.4.12) of password hash is `<name><password>` SHA1'd,
|
||||
in base64.
|
||||
|
||||
Format (since 0.4.13) of password hash is `#1#<salt>#<verifier>`, with the
|
||||
parts inside `<>` encoded in base64.
|
||||
|
||||
`<verifier>` is an RFC 2945 compatible SRP verifier,
|
||||
of the given salt, password, and the player's name lowercased,
|
||||
using the 2048-bit group specified in RFC 5054 and the SHA-256 hash function.
|
||||
|
||||
Example lines:
|
||||
* Player "celeron55", no password, privileges "interact" and "shout":
|
||||
```
|
||||
celeron55::interact,shout
|
||||
```
|
||||
* Player "Foo", password "bar", privilege "shout", with a legacy password hash:
|
||||
```
|
||||
foo:iEPX+SQWIR3p67lj/0zigSWTKHg:shout
|
||||
```
|
||||
* Player "Foo", password "bar", privilege "shout", with a 0.4.13 password hash:
|
||||
```
|
||||
foo:#1#hPpy4O3IAn1hsNK00A6wNw#Kpu6rj7McsrPCt4euTb5RA5ltF7wdcWGoYMcRngwDi11cZhPuuR9i5Bo7o6A877TgcEwoc//HNrj9EjR/CGjdyTFmNhiermZOADvd8eu32FYK1kf7RMC0rXWxCenYuOQCG4WF9mMGiyTPxC63VAjAMuc1nCZzmy6D9zt0SIKxOmteI75pAEAIee2hx4OkSXRIiU4Zrxo1Xf7QFxkMY4x77vgaPcvfmuzom0y/fU1EdSnZeopGPvzMpFx80ODFx1P34R52nmVl0W8h4GNo0k8ZiWtRCdrJxs8xIg7z5P1h3Th/BJ0lwexpdK8sQZWng8xaO5ElthNuhO8UQx1l6FgEA:shout
|
||||
```
|
||||
* Player "bar", no password, no privileges:
|
||||
```
|
||||
bar::
|
||||
```
|
||||
|
||||
## `auth.sqlite`
|
||||
|
||||
Contains authentication data as an SQLite database. This replaces auth.txt
|
||||
above when `auth_backend` is set to `sqlite3` in world.mt.
|
||||
|
||||
This database contains two tables: `auth` and `user_privileges`:
|
||||
|
||||
```sql
|
||||
CREATE TABLE `auth` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` VARCHAR(32) UNIQUE,
|
||||
`password` VARCHAR(512),
|
||||
`last_login` INTEGER
|
||||
);
|
||||
CREATE TABLE `user_privileges` (
|
||||
`id` INTEGER,
|
||||
`privilege` VARCHAR(32),
|
||||
PRIMARY KEY (id, privilege),
|
||||
CONSTRAINT fk_id FOREIGN KEY (id) REFERENCES auth (id) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
The `name` and `password` fields of the auth table are the same as the auth.txt
|
||||
fields (with modern password hash). The `last_login` field is the last login
|
||||
time as a Unix time stamp.
|
||||
|
||||
The `user_privileges` table contains one entry per privilege and player.
|
||||
A player with "interact" and "shout" privileges will have two entries, one
|
||||
with `privilege="interact"` and the second with `privilege="shout"`.
|
||||
|
||||
## `env_meta.txt`
|
||||
|
||||
Simple global environment variables.
|
||||
|
||||
Example content:
|
||||
|
||||
game_time = 73471
|
||||
time_of_day = 19118
|
||||
EnvArgsEnd
|
||||
|
||||
## `ipban.txt`
|
||||
|
||||
Banned IP addresses and usernames.
|
||||
|
||||
Example content:
|
||||
|
||||
123.456.78.9|foo
|
||||
123.456.78.10|bar
|
||||
|
||||
## `map_meta.txt`
|
||||
|
||||
Simple global map variables.
|
||||
|
||||
Example content:
|
||||
|
||||
seed = 7980462765762429666
|
||||
[end_of_params]
|
||||
|
||||
## `map.sqlite`
|
||||
|
||||
Map data.
|
||||
|
||||
See [Map File Format](#map-file-format) below.
|
||||
|
||||
## `player1`, `Foo`
|
||||
|
||||
Player data.
|
||||
|
||||
Filename can be anything.
|
||||
|
||||
See [Player File Format](#player-file-format) below.
|
||||
|
||||
## `world.mt`
|
||||
|
||||
World metadata.
|
||||
|
||||
gameid = mesetint - name of the game
|
||||
enable_damage = true - whether damage is enabled or not
|
||||
creative_mode = false - whether creative mode is enabled or not
|
||||
backend = sqlite3 - which DB backend to use for blocks (sqlite3, dummy, leveldb, redis, postgresql)
|
||||
player_backend = sqlite3 - which DB backend to use for player data
|
||||
readonly_backend = sqlite3 - optionally read-only seed DB (DB file _must_ be located in "readonly" subfolder)
|
||||
auth_backend = files - which DB backend to use for authentication data
|
||||
mod_storage_backend = sqlite3 - which DB backend to use for mod storage
|
||||
server_announce = false - whether the server is publicly announced or not
|
||||
load_mod_<mod> = false - whether <mod> is to be loaded in this world
|
||||
|
||||
For `load_mod_<mod>`, the possible values are:
|
||||
|
||||
* `false` - Do not load the mod.
|
||||
* `true` - Load the mod from wherever it is found (may cause conflicts if the same mod appears also in some other place).
|
||||
* `mods/modpack/moddir` - Relative path to the mod
|
||||
* Must be one of the following:
|
||||
* `mods/`: mods in the user path's mods folder (ex. `/home/user/.minetest/mods`)
|
||||
* `share/`: mods in the share's mods folder (ex. `/usr/share/minetest/mods`)
|
||||
* `/path/to/env`: you can use absolute paths to mods inside folders specified with the `MINETEST_MOD_PATH` `env` variable.
|
||||
* Other locations and absolute paths are not supported.
|
||||
* Note that `moddir` is the directory name, not the mod name specified in mod.conf.
|
||||
|
||||
`PostgreSQL` backend specific settings:
|
||||
|
||||
pgsql_connection = host=127.0.0.1 port=5432 user=mt_user password=mt_password dbname=minetest
|
||||
pgsql_player_connection = (same parameters as above)
|
||||
pgsql_readonly_connection = (same parameters as above)
|
||||
pgsql_auth_connection = (same parameters as above)
|
||||
pgsql_mod_storage_connection = (same parameters as above)
|
||||
|
||||
`Redis` backend specific settings:
|
||||
|
||||
redis_address = 127.0.0.1 - Redis server address
|
||||
redis_hash = foo - Database hash
|
||||
redis_port = 6379 - (optional) Connection port
|
||||
redis_password = hunter2 - (optional) Server password
|
||||
|
||||
# Player File Format
|
||||
|
||||
Should be pretty self-explanatory.
|
||||
> **Note**: Position is in `nodes * 10`
|
||||
|
||||
Example content:
|
||||
|
||||
hp = 11
|
||||
name = celeron55
|
||||
pitch = 39.77
|
||||
position = (-5231.97,15,1961.41)
|
||||
version = 1
|
||||
yaw = 101.37
|
||||
PlayerArgsEnd
|
||||
List main 32
|
||||
Item default:torch 13
|
||||
Item default:pick_steel 1 50112
|
||||
Item experimental:tnt
|
||||
Item default:cobble 99
|
||||
Item default:pick_stone 1 13104
|
||||
Item default:shovel_steel 1 51838
|
||||
Item default:dirt 61
|
||||
Item default:rail 78
|
||||
Item default:coal_lump 3
|
||||
Item default:cobble 99
|
||||
Item default:leaves 22
|
||||
Item default:gravel 52
|
||||
Item default:axe_steel 1 2045
|
||||
Item default:cobble 98
|
||||
Item default:sand 61
|
||||
Item default:water_source 94
|
||||
Item default:glass 2
|
||||
Item default:mossycobble
|
||||
Item default:pick_steel 1 64428
|
||||
Item animalmaterials:bone
|
||||
Item default:sword_steel
|
||||
Item default:sapling
|
||||
Item default:sword_stone 1 10647
|
||||
Item default:dirt 99
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
EndInventoryList
|
||||
List craft 9
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
EndInventoryList
|
||||
List craftpreview 1
|
||||
Empty
|
||||
EndInventoryList
|
||||
List craftresult 1
|
||||
Empty
|
||||
EndInventoryList
|
||||
EndInventory
|
||||
|
||||
# Map File Format
|
||||
|
||||
Minetest maps consist of `MapBlock`s, chunks of 16x16x16 nodes.
|
||||
|
||||
In addition to the bulk node data, `MapBlock`s stored on disk also contain
|
||||
other things.
|
||||
|
||||
## History
|
||||
|
||||
Initially, Minetest stored maps in a format called the "sectors" format.
|
||||
It was a directory/file structure like this:
|
||||
|
||||
sectors2/XXX/ZZZ/YYYY
|
||||
|
||||
For example, the `MapBlock` at `(0, 1, -2)` was this file:
|
||||
|
||||
sectors2/000/ffd/0001
|
||||
|
||||
Eventually Minetest outgrew this directory structure, as filesystems were
|
||||
struggling under the number of files and directories.
|
||||
|
||||
Large servers seriously needed a new format, and thus the base of the
|
||||
current format was invented, suggested by celeron55 and implemented by
|
||||
JacobF.
|
||||
|
||||
`SQLite3` was implemented. Blocks files were directly inserted as blobs
|
||||
in a single table, indexed by integer primary keys, which were hashed
|
||||
coordinates.
|
||||
|
||||
Today, we know that `SQLite3` allows multiple primary keys (which would allow
|
||||
storing coordinates separately), but the format has been kept unchanged for
|
||||
that part.
|
||||
|
||||
## `map.sqlite`
|
||||
`map.sqlite` is a `SQLite3` database, containing a single table, called
|
||||
`blocks`. It looks like this:
|
||||
|
||||
```sql
|
||||
CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY, `data` BLOB);
|
||||
```
|
||||
|
||||
## Position Hashing
|
||||
|
||||
`pos` (a node position hash) is created from the three coordinates of a
|
||||
`MapBlock` using this algorithm, defined here in Python:
|
||||
|
||||
```python
|
||||
def getBlockAsInteger(p):
|
||||
return int64(p[2]*16777216 + p[1]*4096 + p[0])
|
||||
|
||||
def int64(u):
|
||||
while u >= 2**63:
|
||||
u -= 2**64
|
||||
while u <= -2**63:
|
||||
u += 2**64
|
||||
return u
|
||||
```
|
||||
|
||||
It can be converted the other way by using this code:
|
||||
|
||||
```python
|
||||
def getIntegerAsBlock(i):
|
||||
x = unsignedToSigned(i % 4096, 2048)
|
||||
i = int((i - x) / 4096)
|
||||
y = unsignedToSigned(i % 4096, 2048)
|
||||
i = int((i - y) / 4096)
|
||||
z = unsignedToSigned(i % 4096, 2048)
|
||||
return x,y,z
|
||||
|
||||
def unsignedToSigned(i, max_positive):
|
||||
if i < max_positive:
|
||||
return i
|
||||
else:
|
||||
return i - 2*max_positive
|
||||
```
|
||||
|
||||
## Blob
|
||||
|
||||
The blob is the data that would have otherwise gone into the file.
|
||||
|
||||
See below for description.
|
||||
|
||||
# MapBlock Serialization Format
|
||||
|
||||
> **Notes**:
|
||||
> * NOTE: Byte order is MSB first (big-endian).
|
||||
> * NOTE: Zlib data is in such a format that Python's `zlib` at least can
|
||||
> directly decompress.
|
||||
> * NOTE: Since version 29 zstd is used instead of zlib. In addition, the entire
|
||||
> block is first serialized and then compressed (except the version byte).
|
||||
|
||||
`u8` version
|
||||
* map format version number, see serialization.h for the latest number
|
||||
|
||||
`u8` flags
|
||||
* Flag bitmasks:
|
||||
* `0x01`: `is_underground`: Should be set to 0 if there will be no light
|
||||
obstructions above the block. If/when sunlight of a block is updated
|
||||
and there is no block above it, this value is checked for determining
|
||||
whether sunlight comes from the top.
|
||||
|
||||
* `0x02`: `day_night_differs`: Whether the lighting of the block is different
|
||||
on day and night. Only blocks that have this bit set are updated when
|
||||
day transforms to night.
|
||||
|
||||
* `0x04`: `lighting_expired`: Not used in version 27 and above. If true,
|
||||
lighting is invalid and should be updated. If you can't calculate
|
||||
lighting in your generator properly, you could try setting this 1 to
|
||||
everything and setting the uppermost block in every sector as
|
||||
`is_underground=0`. It most likely won't work properly.
|
||||
|
||||
* `0x08`: `generated`: True if the block has been generated. If false, block
|
||||
is mostly filled with `CONTENT_IGNORE` and is likely to contain e.g. parts
|
||||
of trees of neighboring blocks.
|
||||
|
||||
`u16` lighting_complete
|
||||
* Added in version 27.
|
||||
|
||||
* This contains 12 flags, each of them corresponds to a direction.
|
||||
|
||||
* Indicates if the light is correct at the sides of a map block.
|
||||
Lighting may not be correct if the light changed, but a neighbor
|
||||
block was not loaded at that time.
|
||||
If these flags are false, Minetest will automatically recompute light
|
||||
when both this block and its required neighbor are loaded.
|
||||
|
||||
* The bit order is:
|
||||
nothing, nothing, nothing, nothing,
|
||||
night X-, night Y-, night Z-, night Z+, night Y+, night X+,
|
||||
day X-, day Y-, day Z-, day Z+, day Y+, day X+.
|
||||
Where 'day' is for the day light bank, 'night' is for the night
|
||||
light bank.
|
||||
The 'nothing' bits should be always set, as they will be used
|
||||
to indicate if direct sunlight spreading is finished.
|
||||
|
||||
* Example: if the block at `(0, 0, 0)` has `lighting_complete = 0b1111111111111110`,
|
||||
Minetest will correct lighting in the day light bank when the block at
|
||||
`(1, 0, 0)` is also loaded.
|
||||
|
||||
Timestamp and node ID mappings were introduced in map format version 29.
|
||||
* `u32` timestamp
|
||||
* Timestamp when last saved, as seconds from starting the game.
|
||||
* `0xffffffff` = invalid/unknown timestamp, nothing should be done with the time
|
||||
difference when loaded
|
||||
|
||||
* `u8` `name_id_mapping_version`
|
||||
* Should be zero for map format version 29.
|
||||
|
||||
* `u16` `num_name_id_mappings`
|
||||
* foreach `num_name_id_mappings`:
|
||||
* `u16` `id`
|
||||
* `u16` `name_len`
|
||||
* `u8[name_len]` `name`
|
||||
|
||||
`u8` content_width
|
||||
* Number of bytes in the content (`param0`) fields of nodes
|
||||
* 1 byte before map format version 24, 2 bytes since
|
||||
|
||||
`u8` params_width
|
||||
* Number of bytes used for parameters per node
|
||||
* Always 2
|
||||
|
||||
## Node Data
|
||||
> **Note**: Zlib-compressed before map format version 29
|
||||
|
||||
* If `content_width` is 1:
|
||||
* `u8[4096]`: `param0` fields
|
||||
* `u8[4096]`: `param1` fields
|
||||
* `u8[4096]`: `param2` fields
|
||||
|
||||
* If `content_width` is 2:
|
||||
* `u16[4096]`: `param0` fields
|
||||
* `u8[4096]`: `param1` fields
|
||||
* `u8[4096]`: `param2` fields
|
||||
|
||||
* The location of a node in each of those arrays is `(z*16*16 + y*16 + x)`.
|
||||
|
||||
### Node Metadata List
|
||||
> **Note**: Zlib-compressed before map version format 29
|
||||
* Before map format version 23:
|
||||
* `u16` version (=1)
|
||||
* `u16` count of metadata
|
||||
* foreach count:
|
||||
* `u16` position (`(p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)`)
|
||||
* `u16` type_id
|
||||
* `u16` content_size
|
||||
* `u8[content_size]` content of metadata. Format depends on `type_id`, see below.
|
||||
|
||||
* Since map format version 23:
|
||||
* `u8` version
|
||||
> **Note**: Type was `u16` before map format version 23
|
||||
* = 1 before map format version 28
|
||||
* = 2 since map format version 28
|
||||
* `u16` count of metadata
|
||||
* foreach count:
|
||||
* `u16` `position` (`(p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)`)
|
||||
* `u32` `num_vars`
|
||||
* foreach `num_vars`:
|
||||
* `u16` `key_len`
|
||||
* `u8[key_len]` `key`
|
||||
* `u32 val_len`
|
||||
* `u8[val_len]` `value`
|
||||
* `u8` `is_private`
|
||||
* only since map format version 2. 0 = not private, 1 = private
|
||||
* serialized inventory
|
||||
|
||||
## Node Timers
|
||||
* Map format version 23:
|
||||
* `u8` unused version (always 0)
|
||||
|
||||
* Map format version 24:
|
||||
> **Note**: Not released as stable
|
||||
* `u8` `nodetimer_version`
|
||||
* if `nodetimer_version` == 1:
|
||||
* `u16` `num_of_timers`
|
||||
* foreach `num_of_timers`:
|
||||
* `u16` timer position (`(z*16*16 + y*16 + x)`)
|
||||
* `s32` timeout * 1000
|
||||
* `s32` elapsed * 1000
|
||||
|
||||
* Since map format version 25:
|
||||
* `u8` length of the data of a single timer (always 2+4+4=10)
|
||||
* `u16` `num_of_timers`
|
||||
* foreach `num_of_timers`:
|
||||
* `u16` timer position (`(z*16*16 + y*16 + x)`)
|
||||
* `s32` timeout * 1000
|
||||
* `s32` elapsed * 1000
|
||||
|
||||
`u8` static object version:
|
||||
* Always 0
|
||||
|
||||
`u16` `static_object_count`
|
||||
|
||||
foreach `static_object_count`:
|
||||
* `u8` type (object type-id)
|
||||
* `s32` `pos_x_nodes` * 10000
|
||||
* `s32` `pos_y_nodes` * 10000
|
||||
* `s32` `pos_z_nodes` * 10000
|
||||
* `u16` `data_size`
|
||||
* `u8[data_size]` `data`
|
||||
|
||||
Before map format version 29:
|
||||
* `u32` `timestamp`
|
||||
* Same meaning as the timestamp further up
|
||||
|
||||
* `u8` `name-id-mapping` version
|
||||
* Always 0
|
||||
|
||||
* `u16` `num_name_id_mappings`
|
||||
* foreach `num_name_id_mappings`:
|
||||
* `u16` `id`
|
||||
* `u16` `name_len`
|
||||
* `u8[name_len]` `name`
|
||||
|
||||
End of File (EOF).
|
||||
|
||||
# Format of Nodes
|
||||
|
||||
A node is composed of the `u8` fields `param0`, `param1` and `param2`.
|
||||
|
||||
Before map format version 24:
|
||||
* The content id of a node is determined as so:
|
||||
* If `param0` < `0x80`, `content_id = param0`
|
||||
* Otherwise, `content_id = (param0<<4) + (param2>>4)`
|
||||
|
||||
Since map format version 24:
|
||||
* The content id of a node is `param0`.
|
||||
|
||||
The purpose of `param1` and `param2` depend on the definition of the node.
|
||||
|
||||
# Name-ID-Mapping
|
||||
|
||||
The mapping maps node content IDs to node names.
|
||||
|
||||
# Node Metadata Format (Before Map Format Version 23)
|
||||
|
||||
The node metadata is serialized depending on the `type_id` field.
|
||||
|
||||
`1`: Generic metadata
|
||||
* serialized inventory
|
||||
* `u32` `len`
|
||||
* `u8[len]` `text`
|
||||
* `u16` `len`
|
||||
* `u8[len]` `owner`
|
||||
* `u16` `len`
|
||||
* `u8[len]` `infotext`
|
||||
* `u16` `len`
|
||||
* `u8[len]` inventory drawspec
|
||||
* `u8` `allow_text_input` (bool)
|
||||
* `u8` `removal_disabled` (bool)
|
||||
* `u8` `enforce_owner` (bool)
|
||||
* `u32` `num_vars`
|
||||
* foreach `num_vars`:
|
||||
* `u16` `len`
|
||||
* `u8[len]` `name`
|
||||
* `u32` `len`
|
||||
* `u8[len]` `value`
|
||||
|
||||
`14`: Sign metadata
|
||||
* `u16` `text_len`
|
||||
* `u8[text_len]` `text`
|
||||
|
||||
`15`: Chest metadata
|
||||
* serialized inventory
|
||||
|
||||
`16`: Furnace metadata
|
||||
* To be determined
|
||||
|
||||
`17`: Locked Chest metadata
|
||||
* `u16` `len`
|
||||
* `u8[len]` `owner`
|
||||
* serialized inventory
|
||||
|
||||
# Static Objects
|
||||
|
||||
Static objects are persistent freely moving objects in the world.
|
||||
|
||||
Object types:
|
||||
`1`: Test object
|
||||
`7`: LuaEntity:
|
||||
* `u8` `compatibility_byte` (always 1)
|
||||
* `u16` `len`
|
||||
* `u8[len]` entity name
|
||||
* `u32` `len`
|
||||
* `u8[len]` static data
|
||||
* `s16` `hp`
|
||||
* `s32` velocity.x * 10000
|
||||
* `s32` velocity.y * 10000
|
||||
* `s32` velocity.z * 10000
|
||||
* `s32` yaw * 1000
|
||||
|
||||
Since protocol version 37:
|
||||
* `u8` `version2` (=1)
|
||||
* `s32` pitch * 1000
|
||||
* `s32` roll * 1000
|
||||
|
||||
# Itemstring Format
|
||||
|
||||
Examples:
|
||||
* `'default:dirt 5'`
|
||||
* `'default:pick_wood 21323'`
|
||||
* `'"default:apple" 2'`
|
||||
* `'default:apple'`
|
||||
|
||||
Older formats:
|
||||
* `'node "default:dirt" 5'`
|
||||
* `'NodeItem default:dirt 5'`
|
||||
* `'ToolItem WPick 21323'`
|
||||
|
||||
The wear value in tools is 0...65535.
|
||||
|
||||
# Inventory Serialization Format
|
||||
|
||||
* The inventory serialization format is line-based.
|
||||
* The newline character used is `\n`
|
||||
* The end condition of a serialized inventory is always `EndInventory\n`
|
||||
* All the slots in a list must always be serialized.
|
||||
|
||||
## Example
|
||||
|
||||
List foo 4
|
||||
Item default:sapling
|
||||
Item default:sword_stone 1 10647
|
||||
Item default:dirt 99
|
||||
Empty
|
||||
EndInventoryList
|
||||
List bar 9
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
EndInventoryList
|
||||
EndInventory
|
@ -1,598 +0,0 @@
|
||||
=============================
|
||||
Minetest World Format 22...29
|
||||
=============================
|
||||
|
||||
This applies to a world format carrying the block serialization version
|
||||
22...27, used at least in
|
||||
- 0.4.dev-20120322 ... 0.4.dev-20120606 (22...23)
|
||||
- 0.4.0 (23)
|
||||
- 24 was never released as stable and existed for ~2 days
|
||||
- 27 was added in 0.4.15-dev
|
||||
- 29 was added in 5.5.0-dev
|
||||
|
||||
The block serialization version does not fully specify every aspect of this
|
||||
format; if compliance with this format is to be checked, it needs to be
|
||||
done by detecting if the files and data indeed follows it.
|
||||
|
||||
Files
|
||||
======
|
||||
Everything is contained in a directory, the name of which is freeform, but
|
||||
often serves as the name of the world.
|
||||
|
||||
Currently the authentication and ban data is stored on a per-world basis.
|
||||
It can be copied over from an old world to a newly created world.
|
||||
|
||||
World
|
||||
|-- auth.txt ----- Authentication data
|
||||
|-- auth.sqlite -- Authentication data (SQLite alternative)
|
||||
|-- env_meta.txt - Environment metadata
|
||||
|-- ipban.txt ---- Banned ips/users
|
||||
|-- map_meta.txt - Map metadata
|
||||
|-- map.sqlite --- Map data
|
||||
|-- players ------ Player directory
|
||||
| |-- player1 -- Player file
|
||||
| '-- Foo ------ Player file
|
||||
`-- world.mt ----- World metadata
|
||||
|
||||
auth.txt
|
||||
---------
|
||||
Contains authentication data, player per line.
|
||||
<name>:<password hash>:<privilege1,...>
|
||||
|
||||
Legacy format (until 0.4.12) of password hash is <name><password> SHA1'd,
|
||||
in the base64 encoding.
|
||||
|
||||
Format (since 0.4.13) of password hash is #1#<salt>#<verifier>, with the
|
||||
parts inside <> encoded in the base64 encoding.
|
||||
<verifier> is an RFC 2945 compatible SRP verifier,
|
||||
of the given salt, password, and the player's name lowercased,
|
||||
using the 2048-bit group specified in RFC 5054 and the SHA-256 hash function.
|
||||
|
||||
Example lines:
|
||||
- Player "celeron55", no password, privileges "interact" and "shout":
|
||||
celeron55::interact,shout
|
||||
- Player "Foo", password "bar", privilege "shout", with a legacy password hash:
|
||||
foo:iEPX+SQWIR3p67lj/0zigSWTKHg:shout
|
||||
- Player "Foo", password "bar", privilege "shout", with a 0.4.13 pw hash:
|
||||
foo:#1#hPpy4O3IAn1hsNK00A6wNw#Kpu6rj7McsrPCt4euTb5RA5ltF7wdcWGoYMcRngwDi11cZhPuuR9i5Bo7o6A877TgcEwoc//HNrj9EjR/CGjdyTFmNhiermZOADvd8eu32FYK1kf7RMC0rXWxCenYuOQCG4WF9mMGiyTPxC63VAjAMuc1nCZzmy6D9zt0SIKxOmteI75pAEAIee2hx4OkSXRIiU4Zrxo1Xf7QFxkMY4x77vgaPcvfmuzom0y/fU1EdSnZeopGPvzMpFx80ODFx1P34R52nmVl0W8h4GNo0k8ZiWtRCdrJxs8xIg7z5P1h3Th/BJ0lwexpdK8sQZWng8xaO5ElthNuhO8UQx1l6FgEA:shout
|
||||
- Player "bar", no password, no privileges:
|
||||
bar::
|
||||
|
||||
auth.sqlite
|
||||
------------
|
||||
Contains authentification data as an SQLite database. This replaces auth.txt
|
||||
above when auth_backend is set to "sqlite3" in world.mt .
|
||||
|
||||
This database contains two tables "auth" and "user_privileges":
|
||||
|
||||
CREATE TABLE `auth` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`name` VARCHAR(32) UNIQUE,
|
||||
`password` VARCHAR(512),
|
||||
`last_login` INTEGER
|
||||
);
|
||||
CREATE TABLE `user_privileges` (
|
||||
`id` INTEGER,
|
||||
`privilege` VARCHAR(32),
|
||||
PRIMARY KEY (id, privilege)
|
||||
CONSTRAINT fk_id FOREIGN KEY (id) REFERENCES auth (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
The "name" and "password" fields of the auth table are the same as the auth.txt
|
||||
fields (with modern password hash). The "last_login" field is the last login
|
||||
time as a unix time stamp.
|
||||
|
||||
The "user_privileges" table contains one entry per privilege and player.
|
||||
A player with "interact" and "shout" privileges will have two entries, one
|
||||
with privilege="interact" and the second with privilege="shout".
|
||||
|
||||
env_meta.txt
|
||||
-------------
|
||||
Simple global environment variables.
|
||||
Example content (added indentation):
|
||||
game_time = 73471
|
||||
time_of_day = 19118
|
||||
EnvArgsEnd
|
||||
|
||||
ipban.txt
|
||||
----------
|
||||
Banned IP addresses and usernames.
|
||||
Example content (added indentation):
|
||||
123.456.78.9|foo
|
||||
123.456.78.10|bar
|
||||
|
||||
map_meta.txt
|
||||
-------------
|
||||
Simple global map variables.
|
||||
Example content (added indentation):
|
||||
seed = 7980462765762429666
|
||||
[end_of_params]
|
||||
|
||||
map.sqlite
|
||||
-----------
|
||||
Map data.
|
||||
See Map File Format below.
|
||||
|
||||
player1, Foo
|
||||
-------------
|
||||
Player data.
|
||||
Filename can be anything.
|
||||
See Player File Format below.
|
||||
|
||||
world.mt
|
||||
---------
|
||||
World metadata.
|
||||
Example content (added indentation and - explanations):
|
||||
gameid = mesetint - name of the game
|
||||
enable_damage = true - whether damage is enabled or not
|
||||
creative_mode = false - whether creative mode is enabled or not
|
||||
backend = sqlite3 - which DB backend to use for blocks (sqlite3, dummy, leveldb, redis, postgresql)
|
||||
player_backend = sqlite3 - which DB backend to use for player data
|
||||
readonly_backend = sqlite3 - optionally readonly seed DB (DB file _must_ be located in "readonly" subfolder)
|
||||
auth_backend = files - which DB backend to use for authentication data
|
||||
mod_storage_backend = sqlite3 - which DB backend to use for mod storage
|
||||
server_announce = false - whether the server is publicly announced or not
|
||||
load_mod_<mod> = false - whether <mod> is to be loaded in this world
|
||||
|
||||
For load_mod_<mod>, the possible values are:
|
||||
|
||||
* `false` - Do not load the mod.
|
||||
* `true` - Load the mod from wherever it is found (may cause conflicts if the same mod appears also in some other place).
|
||||
* `mods/modpack/moddir` - Relative path to the mod
|
||||
* Must be one of the following:
|
||||
* `mods/`: mods in the user path's mods folder (ex `/home/user/.minetest/mods`)
|
||||
* `share/`: mods in the share's mods folder (ex: `/usr/share/minetest/mods`)
|
||||
* `/path/to/env`: you can use absolute paths to mods inside folders specified with the `MINETEST_MOD_PATH` env variable.
|
||||
* Other locations and absolute paths are not supported
|
||||
* Note that `moddir` is the directory name, not the mod name specified in mod.conf.
|
||||
|
||||
PostgreSQL backend specific settings:
|
||||
pgsql_connection = host=127.0.0.1 port=5432 user=mt_user password=mt_password dbname=minetest
|
||||
pgsql_player_connection = (same parameters as above)
|
||||
pgsql_readonly_connection = (same parameters as above)
|
||||
pgsql_auth_connection = (same parameters as above)
|
||||
pgsql_mod_storage_connection = (same parameters as above)
|
||||
|
||||
Redis backend specific settings:
|
||||
redis_address = 127.0.0.1 - Redis server address
|
||||
redis_hash = foo - Database hash
|
||||
redis_port = 6379 - (optional) connection port
|
||||
redis_password = hunter2 - (optional) server password
|
||||
|
||||
|
||||
Player File Format
|
||||
===================
|
||||
|
||||
- Should be pretty self-explanatory.
|
||||
- Note: position is in nodes * 10
|
||||
|
||||
Example content (added indentation):
|
||||
hp = 11
|
||||
name = celeron55
|
||||
pitch = 39.77
|
||||
position = (-5231.97,15,1961.41)
|
||||
version = 1
|
||||
yaw = 101.37
|
||||
PlayerArgsEnd
|
||||
List main 32
|
||||
Item default:torch 13
|
||||
Item default:pick_steel 1 50112
|
||||
Item experimental:tnt
|
||||
Item default:cobble 99
|
||||
Item default:pick_stone 1 13104
|
||||
Item default:shovel_steel 1 51838
|
||||
Item default:dirt 61
|
||||
Item default:rail 78
|
||||
Item default:coal_lump 3
|
||||
Item default:cobble 99
|
||||
Item default:leaves 22
|
||||
Item default:gravel 52
|
||||
Item default:axe_steel 1 2045
|
||||
Item default:cobble 98
|
||||
Item default:sand 61
|
||||
Item default:water_source 94
|
||||
Item default:glass 2
|
||||
Item default:mossycobble
|
||||
Item default:pick_steel 1 64428
|
||||
Item animalmaterials:bone
|
||||
Item default:sword_steel
|
||||
Item default:sapling
|
||||
Item default:sword_stone 1 10647
|
||||
Item default:dirt 99
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
EndInventoryList
|
||||
List craft 9
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
EndInventoryList
|
||||
List craftpreview 1
|
||||
Empty
|
||||
EndInventoryList
|
||||
List craftresult 1
|
||||
Empty
|
||||
EndInventoryList
|
||||
EndInventory
|
||||
|
||||
Map File Format
|
||||
================
|
||||
|
||||
Minetest maps consist of MapBlocks, chunks of 16x16x16 nodes.
|
||||
|
||||
In addition to the bulk node data, MapBlocks stored on disk also contain
|
||||
other things.
|
||||
|
||||
History
|
||||
--------
|
||||
We need a bit of history in here. Initially Minetest stored maps in a
|
||||
format called the "sectors" format. It was a directory/file structure like
|
||||
this:
|
||||
sectors2/XXX/ZZZ/YYYY
|
||||
For example, the MapBlock at (0,1,-2) was this file:
|
||||
sectors2/000/ffd/0001
|
||||
|
||||
Eventually Minetest outgrow this directory structure, as filesystems were
|
||||
struggling under the amount of files and directories.
|
||||
|
||||
Large servers seriously needed a new format, and thus the base of the
|
||||
current format was invented, suggested by celeron55 and implemented by
|
||||
JacobF.
|
||||
|
||||
SQLite3 was slammed in, and blocks files were directly inserted as blobs
|
||||
in a single table, indexed by integer primary keys, oddly mangled from
|
||||
coordinates.
|
||||
|
||||
Today we know that SQLite3 allows multiple primary keys (which would allow
|
||||
storing coordinates separately), but the format has been kept unchanged for
|
||||
that part. So, this is where it has come.
|
||||
</history>
|
||||
|
||||
So here goes
|
||||
-------------
|
||||
map.sqlite is an sqlite3 database, containing a single table, called
|
||||
"blocks". It looks like this:
|
||||
|
||||
CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY,`data` BLOB);
|
||||
|
||||
The key
|
||||
--------
|
||||
"pos" is created from the three coordinates of a MapBlock using this
|
||||
algorithm, defined here in Python:
|
||||
|
||||
def getBlockAsInteger(p):
|
||||
return int64(p[2]*16777216 + p[1]*4096 + p[0])
|
||||
|
||||
def int64(u):
|
||||
while u >= 2**63:
|
||||
u -= 2**64
|
||||
while u <= -2**63:
|
||||
u += 2**64
|
||||
return u
|
||||
|
||||
It can be converted the other way by using this code:
|
||||
|
||||
def getIntegerAsBlock(i):
|
||||
x = unsignedToSigned(i % 4096, 2048)
|
||||
i = int((i - x) / 4096)
|
||||
y = unsignedToSigned(i % 4096, 2048)
|
||||
i = int((i - y) / 4096)
|
||||
z = unsignedToSigned(i % 4096, 2048)
|
||||
return x,y,z
|
||||
|
||||
def unsignedToSigned(i, max_positive):
|
||||
if i < max_positive:
|
||||
return i
|
||||
else:
|
||||
return i - 2*max_positive
|
||||
|
||||
The blob
|
||||
---------
|
||||
The blob is the data that would have otherwise gone into the file.
|
||||
|
||||
See below for description.
|
||||
|
||||
MapBlock serialization format
|
||||
==============================
|
||||
NOTE: Byte order is MSB first (big-endian).
|
||||
NOTE: Zlib data is in such a format that Python's zlib at least can
|
||||
directly decompress.
|
||||
NOTE: Since version 29 zstd is used instead of zlib. In addition the entire
|
||||
block is first serialized and then compressed (except the version byte).
|
||||
|
||||
u8 version
|
||||
- map format version number, see serialization.h for the latest number
|
||||
|
||||
u8 flags
|
||||
- Flag bitmasks:
|
||||
- 0x01: is_underground: Should be set to 0 if there will be no light
|
||||
obstructions above the block. If/when sunlight of a block is updated
|
||||
and there is no block above it, this value is checked for determining
|
||||
whether sunlight comes from the top.
|
||||
- 0x02: day_night_differs: Whether the lighting of the block is different
|
||||
on day and night. Only blocks that have this bit set are updated when
|
||||
day transforms to night.
|
||||
- 0x04: lighting_expired: Not used in version 27 and above. If true,
|
||||
lighting is invalid and should be updated. If you can't calculate
|
||||
lighting in your generator properly, you could try setting this 1 to
|
||||
everything and setting the uppermost block in every sector as
|
||||
is_underground=0. I am quite sure it doesn't work properly, though.
|
||||
- 0x08: generated: True if the block has been generated. If false, block
|
||||
is mostly filled with CONTENT_IGNORE and is likely to contain eg. parts
|
||||
of trees of neighboring blocks.
|
||||
|
||||
u16 lighting_complete
|
||||
- Added in version 27.
|
||||
- This contains 12 flags, each of them corresponds to a direction.
|
||||
- Indicates if the light is correct at the sides of a map block.
|
||||
Lighting may not be correct if the light changed, but a neighbor
|
||||
block was not loaded at that time.
|
||||
If these flags are false, Minetest will automatically recompute light
|
||||
when both this block and its required neighbor are loaded.
|
||||
- The bit order is:
|
||||
nothing, nothing, nothing, nothing,
|
||||
night X-, night Y-, night Z-, night Z+, night Y+, night X+,
|
||||
day X-, day Y-, day Z-, day Z+, day Y+, day X+.
|
||||
Where 'day' is for the day light bank, 'night' is for the night
|
||||
light bank.
|
||||
The 'nothing' bits should be always set, as they will be used
|
||||
to indicate if direct sunlight spreading is finished.
|
||||
- Example: if the block at (0, 0, 0) has
|
||||
lighting_complete = 0b1111111111111110,
|
||||
then Minetest will correct lighting in the day light bank when
|
||||
the block at (1, 0, 0) is also loaded.
|
||||
|
||||
if map format version >= 29:
|
||||
u32 timestamp
|
||||
- Timestamp when last saved, as seconds from starting the game.
|
||||
- 0xffffffff = invalid/unknown timestamp, nothing should be done with the time
|
||||
difference when loaded
|
||||
|
||||
u8 name_id_mapping_version
|
||||
- Should be zero for map format version 29.
|
||||
|
||||
u16 num_name_id_mappings
|
||||
foreach num_name_id_mappings
|
||||
u16 id
|
||||
u16 name_len
|
||||
u8[name_len] name
|
||||
if map format version < 29:
|
||||
-- Nothing right here, timestamp and node id mappings are serialized later
|
||||
|
||||
u8 content_width
|
||||
- Number of bytes in the content (param0) fields of nodes
|
||||
if map format version <= 23:
|
||||
- Always 1
|
||||
if map format version >= 24:
|
||||
- Always 2
|
||||
|
||||
u8 params_width
|
||||
- Number of bytes used for parameters per node
|
||||
- Always 2
|
||||
|
||||
node data (zlib-compressed if version < 29):
|
||||
if content_width == 1:
|
||||
- content:
|
||||
u8[4096]: param0 fields
|
||||
u8[4096]: param1 fields
|
||||
u8[4096]: param2 fields
|
||||
if content_width == 2:
|
||||
- content:
|
||||
u16[4096]: param0 fields
|
||||
u8[4096]: param1 fields
|
||||
u8[4096]: param2 fields
|
||||
- The location of a node in each of those arrays is (z*16*16 + y*16 + x).
|
||||
|
||||
node metadata list (zlib-compressed if version < 29):
|
||||
- content:
|
||||
if map format version <= 22:
|
||||
u16 version (=1)
|
||||
u16 count of metadata
|
||||
foreach count:
|
||||
u16 position (p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)
|
||||
u16 type_id
|
||||
u16 content_size
|
||||
u8[content_size] content of metadata. Format depends on type_id, see below.
|
||||
if map format version >= 23:
|
||||
u8 version -- Note: type was u16 for map format version <= 22
|
||||
-- = 1 for map format version < 28
|
||||
-- = 2 since map format version 28
|
||||
u16 count of metadata
|
||||
foreach count:
|
||||
u16 position (p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X)
|
||||
u32 num_vars
|
||||
foreach num_vars:
|
||||
u16 key_len
|
||||
u8[key_len] key
|
||||
u32 val_len
|
||||
u8[val_len] value
|
||||
u8 is_private -- only for version >= 2. 0 = not private, 1 = private
|
||||
serialized inventory
|
||||
|
||||
- Node timers
|
||||
if map format version == 23:
|
||||
u8 unused version (always 0)
|
||||
if map format version == 24: (NOTE: Not released as stable)
|
||||
u8 nodetimer_version
|
||||
if nodetimer_version == 0:
|
||||
(nothing else)
|
||||
if nodetimer_version == 1:
|
||||
u16 num_of_timers
|
||||
foreach num_of_timers:
|
||||
u16 timer position (z*16*16 + y*16 + x)
|
||||
s32 timeout*1000
|
||||
s32 elapsed*1000
|
||||
if map format version >= 25:
|
||||
-- Nothing right here, node timers are serialized later
|
||||
|
||||
u8 static object version:
|
||||
- Always 0
|
||||
|
||||
u16 static_object_count
|
||||
|
||||
foreach static_object_count:
|
||||
u8 type (object type-id)
|
||||
s32 pos_x_nodes * 10000
|
||||
s32 pos_y_nodes * 10000
|
||||
s32 pos_z_nodes * 10000
|
||||
u16 data_size
|
||||
u8[data_size] data
|
||||
|
||||
if map format version < 29:
|
||||
u32 timestamp
|
||||
- Same meaning as the timestamp further up
|
||||
|
||||
u8 name-id-mapping version
|
||||
- Always 0
|
||||
|
||||
u16 num_name_id_mappings
|
||||
foreach num_name_id_mappings
|
||||
u16 id
|
||||
u16 name_len
|
||||
u8[name_len] name
|
||||
|
||||
- Node timers
|
||||
if map format version >= 25:
|
||||
u8 length of the data of a single timer (always 2+4+4=10)
|
||||
u16 num_of_timers
|
||||
foreach num_of_timers:
|
||||
u16 timer position (z*16*16 + y*16 + x)
|
||||
s32 timeout*1000
|
||||
s32 elapsed*1000
|
||||
|
||||
EOF.
|
||||
|
||||
Format of nodes
|
||||
----------------
|
||||
A node is composed of the u8 fields param0, param1 and param2.
|
||||
|
||||
if map format version <= 23:
|
||||
The content id of a node is determined as so:
|
||||
- If param0 < 0x80,
|
||||
content_id = param0
|
||||
- Otherwise
|
||||
content_id = (param0<<4) + (param2>>4)
|
||||
if map format version >= 24:
|
||||
The content id of a node is param0.
|
||||
|
||||
The purpose of param1 and param2 depend on the definition of the node.
|
||||
|
||||
The name-id-mapping
|
||||
--------------------
|
||||
The mapping maps node content ids to node names.
|
||||
|
||||
Node metadata format for map format versions <= 22
|
||||
---------------------------------------------------
|
||||
The node metadata are serialized depending on the type_id field.
|
||||
|
||||
1: Generic metadata
|
||||
serialized inventory
|
||||
u32 len
|
||||
u8[len] text
|
||||
u16 len
|
||||
u8[len] owner
|
||||
u16 len
|
||||
u8[len] infotext
|
||||
u16 len
|
||||
u8[len] inventory drawspec
|
||||
u8 allow_text_input (bool)
|
||||
u8 removal_disabled (bool)
|
||||
u8 enforce_owner (bool)
|
||||
u32 num_vars
|
||||
foreach num_vars
|
||||
u16 len
|
||||
u8[len] name
|
||||
u32 len
|
||||
u8[len] value
|
||||
|
||||
14: Sign metadata
|
||||
u16 text_len
|
||||
u8[text_len] text
|
||||
|
||||
15: Chest metadata
|
||||
serialized inventory
|
||||
|
||||
16: Furnace metadata
|
||||
TBD
|
||||
|
||||
17: Locked Chest metadata
|
||||
u16 len
|
||||
u8[len] owner
|
||||
serialized inventory
|
||||
|
||||
Static objects
|
||||
---------------
|
||||
Static objects are persistent freely moving objects in the world.
|
||||
|
||||
Object types:
|
||||
1: Test object
|
||||
7: LuaEntity
|
||||
|
||||
7: LuaEntity:
|
||||
u8 compatibility_byte (always 1)
|
||||
u16 len
|
||||
u8[len] entity name
|
||||
u32 len
|
||||
u8[len] static data
|
||||
s16 hp
|
||||
s32 velocity.x * 10000
|
||||
s32 velocity.y * 10000
|
||||
s32 velocity.z * 10000
|
||||
s32 yaw * 1000
|
||||
if PROTOCOL_VERSION >= 37:
|
||||
u8 version2 (=1)
|
||||
s32 pitch * 1000
|
||||
s32 roll * 1000
|
||||
|
||||
Itemstring format
|
||||
------------------
|
||||
eg. 'default:dirt 5'
|
||||
eg. 'default:pick_wood 21323'
|
||||
eg. '"default:apple" 2'
|
||||
eg. 'default:apple'
|
||||
- The wear value in tools is 0...65535
|
||||
- There are also a number of older formats that you might stumble upon:
|
||||
eg. 'node "default:dirt" 5'
|
||||
eg. 'NodeItem default:dirt 5'
|
||||
eg. 'ToolItem WPick 21323'
|
||||
|
||||
Inventory serialization format
|
||||
-------------------------------
|
||||
- The inventory serialization format is line-based
|
||||
- The newline character used is "\n"
|
||||
- The end condition of a serialized inventory is always "EndInventory\n"
|
||||
- All the slots in a list must always be serialized.
|
||||
|
||||
Example (format does not include "---"):
|
||||
---
|
||||
List foo 4
|
||||
Item default:sapling
|
||||
Item default:sword_stone 1 10647
|
||||
Item default:dirt 99
|
||||
Empty
|
||||
EndInventoryList
|
||||
List bar 9
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
EndInventoryList
|
||||
EndInventory
|
||||
---
|
@ -3,7 +3,7 @@ minetest.register_on_joinplayer(function(player)
|
||||
if not player or not player:is_player() then
|
||||
return
|
||||
end
|
||||
minetest.chat_send_player(player:get_player_name(), "This is the \"Development Test\" [devtest], meant only for testing and development. Use Minetest Game for the real thing.")
|
||||
minetest.chat_send_player(player:get_player_name(), "This is the \"Development Test\" [devtest], meant only for testing and development.")
|
||||
end
|
||||
minetest.after(2.0, cb, player)
|
||||
end)
|
||||
|
@ -428,17 +428,17 @@ local MAX_BOUNCE_NONJUMPY = 140
|
||||
for i=-MAX_BOUNCE_NONJUMPY, MAX_BOUNCE_JUMPY, 20 do
|
||||
if i ~= 0 then
|
||||
local desc
|
||||
local val = math.floor(((i-20)/200)*255)
|
||||
local val2 = math.max(0, 200 - val)
|
||||
local val = math.floor((math.abs(i) - 20) / 200 * 255)
|
||||
local val2 = math.max(0, 255 - val)
|
||||
local num = string.format("%03d", math.abs(i))
|
||||
if i > 0 then
|
||||
desc = S("Bouncy Node (@1%), jumpy", i).."\n"..
|
||||
S("Sneaking/jumping affects bounce")
|
||||
color = { r=255-val, g=255-val, b=255, a=255 }
|
||||
color = { r=val2, g=val2, b=255, a=255 }
|
||||
else
|
||||
desc = S("Bouncy Node (@1%), non-jumpy", math.abs(i)).."\n"..
|
||||
S("Sneaking/jumping does not affect bounce")
|
||||
color = { r=val, g=255, b=val, a=255 }
|
||||
color = { r=val2, g=255, b=val2, a=255 }
|
||||
num = "NEG"..num
|
||||
end
|
||||
minetest.register_node("testnodes:bouncy"..num, {
|
||||
|
@ -201,13 +201,13 @@ full_brightness (Full brightness) bool false
|
||||
# type: bool
|
||||
# enable_particles = true
|
||||
|
||||
### 3d
|
||||
### 3D
|
||||
|
||||
# 3D support.
|
||||
# Currently supported:
|
||||
# - none: no 3d output.
|
||||
# - anaglyph: cyan/magenta color 3d.
|
||||
# - interlaced: odd/even line based polarisation screen support.
|
||||
# - interlaced: odd/even line based polarization screen support.
|
||||
# - topbottom: split screen top/bottom.
|
||||
# - sidebyside: split screen side by side.
|
||||
# - crossview: Cross-eyed 3d
|
||||
@ -319,7 +319,7 @@ full_brightness (Full brightness) bool false
|
||||
|
||||
### Clouds
|
||||
|
||||
# Clouds are a client side effect.
|
||||
# Clouds are a client-side effect.
|
||||
# type: bool
|
||||
# enable_clouds = true
|
||||
|
||||
@ -330,7 +330,7 @@ full_brightness (Full brightness) bool false
|
||||
### Filtering and Antialiasing
|
||||
|
||||
# Use mipmaps when scaling textures down. May slightly increase performance,
|
||||
# especially when using a high resolution texture pack.
|
||||
# especially when using a high-resolution texture pack.
|
||||
# Gamma-correct downscaling is not supported.
|
||||
# type: bool
|
||||
# mip_map = false
|
||||
@ -368,7 +368,7 @@ full_brightness (Full brightness) bool false
|
||||
# type: enum values: none, fsaa, fxaa, ssaa
|
||||
# antialiasing = none
|
||||
|
||||
# Defines size of the sampling grid for FSAA and SSAA antializasing methods.
|
||||
# Defines the size of the sampling grid for FSAA and SSAA antialiasing methods.
|
||||
# Value of 2 means taking 2x2 = 4 samples.
|
||||
# type: enum values: 2, 4, 8, 16
|
||||
# fsaa = 2
|
||||
@ -472,7 +472,7 @@ full_brightness (Full brightness) bool false
|
||||
# type: bool
|
||||
# shadow_map_color = false
|
||||
|
||||
# Spread a complete update of shadow map over given amount of frames.
|
||||
# Spread a complete update of shadow map over given number of frames.
|
||||
# Higher values might make shadows laggy, lower values
|
||||
# will consume more resources.
|
||||
# Minimum value: 1; maximum value: 16
|
||||
@ -565,7 +565,7 @@ full_brightness (Full brightness) bool false
|
||||
# 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 =
|
||||
|
||||
### GUIs
|
||||
### GUI
|
||||
|
||||
# Scale GUI by a user specified value.
|
||||
# Use a nearest-neighbor-anti-alias filter to scale the GUI.
|
||||
@ -837,7 +837,7 @@ full_brightness (Full brightness) bool false
|
||||
# type: int min: 10 max: 65535
|
||||
# chat_message_max_size = 500
|
||||
|
||||
# Amount of messages a player may send per 10 seconds.
|
||||
# Number of messages a player may send per 10 seconds.
|
||||
# type: float min: 1
|
||||
# chat_message_limit_per_10sec = 8.0
|
||||
|
||||
@ -959,7 +959,7 @@ full_brightness (Full brightness) bool false
|
||||
# type: flags possible values: caves, dungeons, light, decorations, biomes, ores, nocaves, nodungeons, nolight, nodecorations, nobiomes, noores
|
||||
# mg_flags = caves,dungeons,light,decorations,biomes,ores
|
||||
|
||||
## Biome API noise parameters
|
||||
## Biome API
|
||||
|
||||
# Temperature variation for biomes.
|
||||
# type: noise_params_2d
|
||||
@ -1397,7 +1397,7 @@ full_brightness (Full brightness) bool false
|
||||
# to above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the
|
||||
# upper tapering).
|
||||
# ***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***:
|
||||
# When enabling water placement the floatlands must be configured and tested
|
||||
# When enabling water placement, floatlands must be configured and tested
|
||||
# to be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other
|
||||
# required value depending on 'mgv7_np_floatland'), to avoid
|
||||
# server-intensive extreme water flow and to avoid vast flooding of the
|
||||
@ -2312,7 +2312,7 @@ full_brightness (Full brightness) bool false
|
||||
# mgvalleys_spflags = altitude_chill,humid_rivers,vary_river_depth,altitude_dry
|
||||
|
||||
# The vertical distance over which heat drops by 20 if 'altitude_chill' is
|
||||
# enabled. Also the vertical distance over which humidity drops by 10 if
|
||||
# enabled. Also, the vertical distance over which humidity drops by 10 if
|
||||
# 'altitude_dry' is enabled.
|
||||
# type: int min: 0 max: 65535
|
||||
# mgvalleys_altitude_chill = 90
|
||||
@ -2403,7 +2403,7 @@ full_brightness (Full brightness) bool false
|
||||
# flags =
|
||||
# }
|
||||
|
||||
# The depth of dirt or other biome filler node.
|
||||
# Variation of biome filler depth.
|
||||
# type: noise_params_2d
|
||||
# mgvalleys_np_filler_depth = {
|
||||
# offset = 0,
|
||||
@ -2641,7 +2641,7 @@ full_brightness (Full brightness) bool false
|
||||
# type: bool
|
||||
# instrument.profiler = false
|
||||
|
||||
### Engine profiler
|
||||
### Engine Profiler
|
||||
|
||||
# Print the engine's profiling data in regular intervals (in seconds).
|
||||
# 0 = disable. Useful for developers.
|
||||
@ -2857,7 +2857,7 @@ full_brightness (Full brightness) bool false
|
||||
# type: string
|
||||
# prometheus_listener_address = 127.0.0.1:30000
|
||||
|
||||
# Maximum size of the out chat queue.
|
||||
# Maximum size of the outgoing chat queue.
|
||||
# 0 to disable queueing and -1 to make the queue size unlimited.
|
||||
# type: int min: -1 max: 32767
|
||||
# max_out_chat_queue_size = 20
|
||||
@ -3024,17 +3024,17 @@ full_brightness (Full brightness) bool false
|
||||
# type: int min: 2 max: 32767
|
||||
# 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
|
||||
# on the eye position of the player. This can reduce the number of blocks
|
||||
# sent to the client 50-80%. The client will not longer receive most invisible
|
||||
# so that the utility of noclip mode is reduced.
|
||||
# sent to the client by 50-80%. Clients will no longer receive most
|
||||
# invisible blocks, so that the utility of noclip mode is reduced.
|
||||
# type: bool
|
||||
# server_side_occlusion_culling = true
|
||||
|
||||
### Mapgen
|
||||
|
||||
# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).
|
||||
# WARNING!: There is no benefit, and there are several dangers, in
|
||||
# WARNING: There is no benefit, and there are several dangers, in
|
||||
# increasing this value above 5.
|
||||
# Reducing this value increases cave and dungeon density.
|
||||
# Altering this value is for special usage, leaving it unchanged is
|
||||
@ -3091,7 +3091,7 @@ full_brightness (Full brightness) bool false
|
||||
# type: int min: 5000 max: 2147483647
|
||||
# curl_file_download_timeout = 300000
|
||||
|
||||
### Misc
|
||||
### Miscellaneous
|
||||
|
||||
# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
|
||||
# type: int min: 1
|
||||
|
File diff suppressed because it is too large
Load Diff
1046
po/be/minetest.po
1046
po/be/minetest.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1032
po/ca/minetest.po
1032
po/ca/minetest.po
File diff suppressed because it is too large
Load Diff
1094
po/cs/minetest.po
1094
po/cs/minetest.po
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
1397
po/de/minetest.po
1397
po/de/minetest.po
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
1028
po/eo/minetest.po
1028
po/eo/minetest.po
File diff suppressed because it is too large
Load Diff
1366
po/es/minetest.po
1366
po/es/minetest.po
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
1492
po/fr/minetest.po
1492
po/fr/minetest.po
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
1061
po/gl/minetest.po
1061
po/gl/minetest.po
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
1063
po/hu/minetest.po
1063
po/hu/minetest.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1460
po/id/minetest.po
1460
po/id/minetest.po
File diff suppressed because it is too large
Load Diff
1117
po/it/minetest.po
1117
po/it/minetest.po
File diff suppressed because it is too large
Load Diff
1411
po/ja/minetest.po
1411
po/ja/minetest.po
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
747
po/minetest.pot
747
po/minetest.pot
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
1451
po/ms/minetest.po
1451
po/ms/minetest.po
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
1061
po/nl/minetest.po
1061
po/nl/minetest.po
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
1078
po/pl/minetest.po
1078
po/pl/minetest.po
File diff suppressed because it is too large
Load Diff
1104
po/pt/minetest.po
1104
po/pt/minetest.po
File diff suppressed because it is too large
Load Diff
1109
po/pt_BR/minetest.po
1109
po/pt_BR/minetest.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2631
po/ru/minetest.po
2631
po/ru/minetest.po
File diff suppressed because it is too large
Load Diff
1095
po/sk/minetest.po
1095
po/sk/minetest.po
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
1063
po/sv/minetest.po
1063
po/sv/minetest.po
File diff suppressed because it is too large
Load Diff
1015
po/sw/minetest.po
1015
po/sw/minetest.po
File diff suppressed because it is too large
Load Diff
1030
po/th/minetest.po
1030
po/th/minetest.po
File diff suppressed because it is too large
Load Diff
1042
po/tr/minetest.po
1042
po/tr/minetest.po
File diff suppressed because it is too large
Load Diff
1017
po/tt/minetest.po
1017
po/tt/minetest.po
File diff suppressed because it is too large
Load Diff
1759
po/uk/minetest.po
1759
po/uk/minetest.po
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
1034
po/zh_CN/minetest.po
1034
po/zh_CN/minetest.po
File diff suppressed because it is too large
Load Diff
1007
po/zh_TW/minetest.po
1007
po/zh_TW/minetest.po
File diff suppressed because it is too large
Load Diff
@ -1034,9 +1034,9 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *
|
||||
s32 yaw = myplayer->getYaw() * 100;
|
||||
u32 keyPressed = myplayer->control.getKeysPressed();
|
||||
// scaled by 80, so that pi can fit into a u8
|
||||
u8 fov = clientMap->getCameraFov() * 80;
|
||||
u8 wanted_range = MYMIN(255,
|
||||
std::ceil(clientMap->getControl().wanted_range / MAP_BLOCKSIZE));
|
||||
u8 fov = std::fmin(255.0f, clientMap->getCameraFov() * 80.0f);
|
||||
u8 wanted_range = std::fmin(255.0f,
|
||||
std::ceil(clientMap->getWantedRange() * (1.0f / MAP_BLOCKSIZE)));
|
||||
|
||||
v3s32 position(pf.X, pf.Y, pf.Z);
|
||||
v3s32 speed(sf.X, sf.Y, sf.Z);
|
||||
@ -1385,8 +1385,9 @@ void Client::sendPlayerPos()
|
||||
return;
|
||||
|
||||
ClientMap &map = m_env.getClientMap();
|
||||
u8 camera_fov = map.getCameraFov();
|
||||
u8 wanted_range = map.getControl().wanted_range;
|
||||
u8 camera_fov = std::fmin(255.0f, map.getCameraFov() * 80.0f);
|
||||
u8 wanted_range = std::fmin(255.0f,
|
||||
std::ceil(map.getWantedRange() * (1.0f / MAP_BLOCKSIZE)));
|
||||
|
||||
u32 keyPressed = player->control.getKeysPressed();
|
||||
bool camera_inverted = m_camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT;
|
||||
|
@ -819,6 +819,7 @@ protected:
|
||||
const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
|
||||
void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
||||
const CameraOrientation &cam);
|
||||
void updateClouds(float dtime);
|
||||
void updateShadows();
|
||||
|
||||
// Misc
|
||||
@ -4012,33 +4013,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
||||
/*
|
||||
Update clouds
|
||||
*/
|
||||
if (clouds) {
|
||||
if (sky->getCloudsVisible()) {
|
||||
clouds->setVisible(true);
|
||||
clouds->step(dtime);
|
||||
// camera->getPosition is not enough for 3rd person views
|
||||
v3f camera_node_position = camera->getCameraNode()->getPosition();
|
||||
v3s16 camera_offset = camera->getOffset();
|
||||
camera_node_position.X = camera_node_position.X + camera_offset.X * BS;
|
||||
camera_node_position.Y = camera_node_position.Y + camera_offset.Y * BS;
|
||||
camera_node_position.Z = camera_node_position.Z + camera_offset.Z * BS;
|
||||
clouds->update(camera_node_position,
|
||||
sky->getCloudColor());
|
||||
if (clouds->isCameraInsideCloud() && m_cache_enable_fog) {
|
||||
// if inside clouds, and fog enabled, use that as sky
|
||||
// color(s)
|
||||
video::SColor clouds_dark = clouds->getColor()
|
||||
.getInterpolated(video::SColor(255, 0, 0, 0), 0.9);
|
||||
sky->overrideColors(clouds_dark, clouds->getColor());
|
||||
sky->setInClouds(true);
|
||||
runData.fog_range = std::fmin(runData.fog_range * 0.5f, 32.0f * BS);
|
||||
// do not draw clouds after all
|
||||
clouds->setVisible(false);
|
||||
}
|
||||
} else {
|
||||
clouds->setVisible(false);
|
||||
}
|
||||
}
|
||||
if (clouds)
|
||||
updateClouds(dtime);
|
||||
|
||||
/*
|
||||
Update particles
|
||||
@ -4217,6 +4193,33 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
||||
g_profiler->avg("Game::updateFrame(): update frame [ms]", tt_update.stop(true));
|
||||
}
|
||||
|
||||
void Game::updateClouds(float dtime)
|
||||
{
|
||||
if (this->sky->getCloudsVisible()) {
|
||||
this->clouds->setVisible(true);
|
||||
this->clouds->step(dtime);
|
||||
// this->camera->getPosition is not enough for third-person camera.
|
||||
v3f camera_node_position = this->camera->getCameraNode()->getPosition();
|
||||
v3s16 camera_offset = this->camera->getOffset();
|
||||
camera_node_position.X = camera_node_position.X + camera_offset.X * BS;
|
||||
camera_node_position.Y = camera_node_position.Y + camera_offset.Y * BS;
|
||||
camera_node_position.Z = camera_node_position.Z + camera_offset.Z * BS;
|
||||
this->clouds->update(camera_node_position, this->sky->getCloudColor());
|
||||
if (this->clouds->isCameraInsideCloud() && this->m_cache_enable_fog) {
|
||||
// If camera is inside cloud and fog is enabled, use cloud's colors as sky colors.
|
||||
video::SColor clouds_dark = this->clouds->getColor().getInterpolated(
|
||||
video::SColor(255, 0, 0, 0), 0.9);
|
||||
this->sky->overrideColors(clouds_dark, this->clouds->getColor());
|
||||
this->sky->setInClouds(true);
|
||||
this->runData.fog_range = std::fmin(this->runData.fog_range * 0.5f, 32.0f * BS);
|
||||
// Clouds are not drawn in this case.
|
||||
this->clouds->setVisible(false);
|
||||
}
|
||||
} else {
|
||||
this->clouds->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Log times and stuff for visualization */
|
||||
inline void Game::updateProfilerGraphs(ProfilerGraph *graph)
|
||||
{
|
||||
|
@ -169,7 +169,6 @@ private:
|
||||
LocalPlayer *m_player;
|
||||
ParticleSpawnerParameters p;
|
||||
std::vector<ClientParticleTexture> m_texpool;
|
||||
size_t m_texcount;
|
||||
std::vector<float> m_spawntimes;
|
||||
u16 m_attached_id;
|
||||
};
|
||||
|
@ -266,8 +266,8 @@ void GUIScrollBar::setPos(const s32 &pos)
|
||||
}
|
||||
|
||||
if (is_auto_scaling)
|
||||
thumb_size = s32(thumb_area /
|
||||
(f32(page_size) / f32(thumb_area + border_size * 2)));
|
||||
thumb_size = (s32)std::fmin(S32_MAX,
|
||||
thumb_area / (f32(page_size) / f32(thumb_area + border_size * 2)));
|
||||
|
||||
thumb_size = core::s32_clamp(thumb_size, thumb_min, thumb_area);
|
||||
scroll_pos = core::s32_clamp(pos, min_pos, max_pos);
|
||||
|
@ -70,15 +70,15 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
||||
Add stuff
|
||||
*/
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 70 * s);
|
||||
core::rect<s32> rect(0, 0, 300 * s, 20 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 150 * s, size.Y / 2 - 70 * s);
|
||||
|
||||
StaticText::add(Environment, fwgettext("Sound Volume: %d%%", volume),
|
||||
rect, false, true, this, ID_soundText);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 80 * s, 30 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s);
|
||||
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 100 * s / 2, size.Y / 2 + 55 * s);
|
||||
GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton,
|
||||
wstrgettext("Exit").c_str());
|
||||
}
|
||||
@ -91,8 +91,8 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
||||
e->setPos(volume);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 35 * s);
|
||||
core::rect<s32> rect(0, 0, 300 * s, 20 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 150 * s, size.Y / 2 - 35 * s);
|
||||
Environment->addCheckBox(g_settings->getBool("mute_sound"), rect, this,
|
||||
ID_soundMuteButton, wstrgettext("Muted").c_str());
|
||||
}
|
||||
|
20
src/main.cpp
20
src/main.cpp
@ -78,6 +78,7 @@ extern "C" {
|
||||
#define DEBUGFILE "debug.txt"
|
||||
#define DEFAULT_SERVER_PORT 30000
|
||||
|
||||
#define ENV_MT_LOGCOLOR "MT_LOGCOLOR"
|
||||
#define ENV_NO_COLOR "NO_COLOR"
|
||||
#define ENV_CLICOLOR "CLICOLOR"
|
||||
#define ENV_CLICOLOR_FORCE "CLICOLOR_FORCE"
|
||||
@ -287,6 +288,13 @@ int main(int argc, char *argv[])
|
||||
|
||||
static void get_env_opts(Settings &args)
|
||||
{
|
||||
#if !defined(_WIN32)
|
||||
const char *mt_logcolor = std::getenv(ENV_MT_LOGCOLOR);
|
||||
if (mt_logcolor) {
|
||||
args.set("color", mt_logcolor);
|
||||
}
|
||||
#endif
|
||||
|
||||
// CLICOLOR is a de-facto standard option for colors <https://bixense.com/clicolors/>
|
||||
// CLICOLOR != 0: ANSI colors are supported (auto-detection, this is the default)
|
||||
// CLICOLOR == 0: ANSI colors are NOT supported
|
||||
@ -493,12 +501,6 @@ static bool setup_log_params(const Settings &cmd_args)
|
||||
std::string color_mode;
|
||||
if (cmd_args.exists("color")) {
|
||||
color_mode = cmd_args.get("color");
|
||||
#if !defined(_WIN32)
|
||||
} else {
|
||||
char *color_mode_env = getenv("MT_LOGCOLOR");
|
||||
if (color_mode_env)
|
||||
color_mode = color_mode_env;
|
||||
#endif
|
||||
}
|
||||
if (!color_mode.empty()) {
|
||||
if (color_mode == "auto") {
|
||||
@ -550,8 +552,7 @@ static bool create_userdata_path()
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string findProgram(const char *name)
|
||||
{
|
||||
[[maybe_unused]] std::string findProgram(const char *name) {
|
||||
char *path_c = getenv("PATH");
|
||||
if (!path_c)
|
||||
return "";
|
||||
@ -571,8 +572,9 @@ namespace {
|
||||
#ifdef _WIN32
|
||||
const char *debuggerNames[] = {"gdb.exe", "lldb.exe"};
|
||||
#else
|
||||
const char *debuggerNames[] = {"gdb", "lldb"};
|
||||
[[maybe_unused]] const char *debuggerNames[] = {"gdb", "lldb"};
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
void getDebuggerArgs(T &out, int i) {
|
||||
if (i == 0) {
|
||||
|
@ -294,19 +294,23 @@ bool read_color(lua_State *L, int index, video::SColor *color)
|
||||
|
||||
video::SColor read_ARGB8(lua_State *L, int index)
|
||||
{
|
||||
auto clamp_col = [](double c) -> u32 {
|
||||
return std::fmax(0.0, std::fmin(255.0, c));
|
||||
};
|
||||
|
||||
video::SColor color(0);
|
||||
CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
|
||||
lua_getfield(L, index, "a");
|
||||
color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
|
||||
color.setAlpha(lua_isnumber(L, -1) ? clamp_col(lua_tonumber(L, -1)) : 0xFF);
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, index, "r");
|
||||
color.setRed(lua_tonumber(L, -1));
|
||||
color.setRed(clamp_col(lua_tonumber(L, -1)));
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, index, "g");
|
||||
color.setGreen(lua_tonumber(L, -1));
|
||||
color.setGreen(clamp_col(lua_tonumber(L, -1)));
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, index, "b");
|
||||
color.setBlue(lua_tonumber(L, -1));
|
||||
color.setBlue(clamp_col(lua_tonumber(L, -1)));
|
||||
lua_pop(L, 1);
|
||||
return color;
|
||||
}
|
||||
|
@ -82,9 +82,9 @@ fake_function() {
|
||||
gettext("Enables tradeoffs that reduce CPU load or increase rendering performance\nat the expense of minor visual glitches that do not impact game playability.");
|
||||
gettext("Digging particles");
|
||||
gettext("Adds particles when digging a node.");
|
||||
gettext("3d");
|
||||
gettext("3D");
|
||||
gettext("3D mode");
|
||||
gettext("3D support.\nCurrently supported:\n- none: no 3d output.\n- anaglyph: cyan/magenta color 3d.\n- interlaced: odd/even line based polarisation screen support.\n- topbottom: split screen top/bottom.\n- sidebyside: split screen side by side.\n- crossview: Cross-eyed 3d\nNote that the interlaced mode requires shaders to be enabled.");
|
||||
gettext("3D support.\nCurrently supported:\n- none: no 3d output.\n- anaglyph: cyan/magenta color 3d.\n- interlaced: odd/even line based polarization screen support.\n- topbottom: split screen top/bottom.\n- sidebyside: split screen side by side.\n- crossview: Cross-eyed 3d\nNote that the interlaced mode requires shaders to be enabled.");
|
||||
gettext("3D mode parallax strength");
|
||||
gettext("Strength of 3D mode parallax.");
|
||||
gettext("Bobbing");
|
||||
@ -130,12 +130,12 @@ fake_function() {
|
||||
gettext("Fraction of the visible distance at which fog starts to be rendered");
|
||||
gettext("Clouds");
|
||||
gettext("Clouds");
|
||||
gettext("Clouds are a client side effect.");
|
||||
gettext("Clouds are a client-side effect.");
|
||||
gettext("3D clouds");
|
||||
gettext("Use 3D cloud look instead of flat.");
|
||||
gettext("Filtering and Antialiasing");
|
||||
gettext("Mipmapping");
|
||||
gettext("Use mipmaps when scaling textures down. May slightly increase performance,\nespecially when using a high resolution texture pack.\nGamma-correct downscaling is not supported.");
|
||||
gettext("Use mipmaps when scaling textures down. May slightly increase performance,\nespecially when using a high-resolution texture pack.\nGamma-correct downscaling is not supported.");
|
||||
gettext("Bilinear filtering");
|
||||
gettext("Use bilinear filtering when scaling textures down.");
|
||||
gettext("Trilinear filtering");
|
||||
@ -145,7 +145,7 @@ fake_function() {
|
||||
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("Anti-aliasing scale");
|
||||
gettext("Defines size of the sampling grid for FSAA and SSAA antializasing 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 Culler");
|
||||
gettext("Type of occlusion_culler\n\n\"loops\" is the legacy algorithm with nested loops and O(n³) complexity\n\"bfs\" is the new algorithm based on breadth-first-search and side culling\n\nThis setting should only be changed if you have performance problems.");
|
||||
@ -185,7 +185,7 @@ fake_function() {
|
||||
gettext("Colored shadows");
|
||||
gettext("Enable colored shadows.\nOn true translucent nodes cast colored shadows. This is expensive.");
|
||||
gettext("Map shadows update frames");
|
||||
gettext("Spread a complete update of shadow map over given amount of frames.\nHigher values might make shadows laggy, lower values\nwill consume more resources.\nMinimum value: 1; maximum value: 16");
|
||||
gettext("Spread a complete update of shadow map over given number of frames.\nHigher values might make shadows laggy, lower values\nwill consume more resources.\nMinimum value: 1; maximum value: 16");
|
||||
gettext("Soft shadow radius");
|
||||
gettext("Set the soft shadow radius size.\nLower values mean sharper shadows, bigger values mean softer shadows.\nMinimum value: 1.0; maximum value: 15.0");
|
||||
gettext("Sky Body Orbit Tilt");
|
||||
@ -216,7 +216,7 @@ fake_function() {
|
||||
gettext("User Interfaces");
|
||||
gettext("Language");
|
||||
gettext("Set the language. Leave empty to use the system language.\nA restart is required after changing this.");
|
||||
gettext("GUIs");
|
||||
gettext("GUI");
|
||||
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("Inventory items animations");
|
||||
@ -323,7 +323,7 @@ fake_function() {
|
||||
gettext("Client-side Modding");
|
||||
gettext("Client side modding restrictions");
|
||||
gettext("Restricts the access of certain client-side functions on servers.\nCombine the byteflags below to restrict client-side features, or set to 0\nfor no restrictions:\nLOAD_CLIENT_MODS: 1 (disable loading client-provided mods)\nCHAT_MESSAGES: 2 (disable send_chat_message call client-side)\nREAD_ITEMDEFS: 4 (disable get_item_def call client-side)\nREAD_NODEDEFS: 8 (disable get_node_def call client-side)\nLOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to\ncsm_restriction_noderange)\nREAD_PLAYERINFO: 32 (disable get_player_names call client-side)");
|
||||
gettext("Client side node lookup range restriction");
|
||||
gettext("Client-side node lookup range restriction");
|
||||
gettext("If the CSM restriction for node range is enabled, get_node calls are limited\nto this distance from the player to the node.");
|
||||
gettext("Chat");
|
||||
gettext("Strip color codes");
|
||||
@ -331,7 +331,7 @@ fake_function() {
|
||||
gettext("Chat message max length");
|
||||
gettext("Set the maximum length of a chat message (in characters) sent by clients.");
|
||||
gettext("Chat message count limit");
|
||||
gettext("Amount of messages a player may send per 10 seconds.");
|
||||
gettext("Number of messages a player may send per 10 seconds.");
|
||||
gettext("Chat message kick threshold");
|
||||
gettext("Kick players who sent more than X messages per 10 seconds.");
|
||||
gettext("Server Gameplay");
|
||||
@ -381,7 +381,7 @@ fake_function() {
|
||||
gettext("Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).\nOnly mapchunks completely within the mapgen limit are generated.\nValue is stored per-world.");
|
||||
gettext("Mapgen flags");
|
||||
gettext("Global map generation attributes.\nIn Mapgen v6 the 'decorations' flag controls all decorations except trees\nand jungle grass, in all other mapgens this flag controls all decorations.");
|
||||
gettext("Biome API noise parameters");
|
||||
gettext("Biome API");
|
||||
gettext("Heat noise");
|
||||
gettext("Temperature variation for biomes.");
|
||||
gettext("Heat blend noise");
|
||||
@ -484,7 +484,7 @@ fake_function() {
|
||||
gettext("Floatland density");
|
||||
gettext("Adjusts the density of the floatland layer.\nIncrease value to increase density. Can be positive or negative.\nValue = 0.0: 50% of volume is floatland.\nValue = 2.0 (can be higher depending on 'mgv7_np_floatland', always test\nto be sure) creates a solid floatland layer.");
|
||||
gettext("Floatland water level");
|
||||
gettext("Surface level of optional water placed on a solid floatland layer.\nWater is disabled by default and will only be placed if this value is set\nto above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the\nupper tapering).\n***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***:\nWhen enabling water placement the floatlands must be configured and tested\nto be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other\nrequired value depending on 'mgv7_np_floatland'), to avoid\nserver-intensive extreme water flow and to avoid vast flooding of the\nworld surface below.");
|
||||
gettext("Surface level of optional water placed on a solid floatland layer.\nWater is disabled by default and will only be placed if this value is set\nto above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the\nupper tapering).\n***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***:\nWhen enabling water placement, floatlands must be configured and tested\nto be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other\nrequired value depending on 'mgv7_np_floatland'), to avoid\nserver-intensive extreme water flow and to avoid vast flooding of the\nworld surface below.");
|
||||
gettext("Cave width");
|
||||
gettext("Controls width of tunnels, a smaller value creates wider tunnels.\nValue >= 10.0 completely disables generation of tunnels and avoids the\nintensive noise calculations.");
|
||||
gettext("Large cave depth");
|
||||
@ -712,7 +712,7 @@ fake_function() {
|
||||
gettext("Mapgen Valleys specific flags");
|
||||
gettext("Map generation attributes specific to Mapgen Valleys.\n'altitude_chill': Reduces heat with altitude.\n'humid_rivers': Increases humidity around rivers.\n'vary_river_depth': If enabled, low humidity and high heat causes rivers\nto become shallower and occasionally dry.\n'altitude_dry': Reduces humidity with altitude.");
|
||||
gettext("Altitude chill");
|
||||
gettext("The vertical distance over which heat drops by 20 if 'altitude_chill' is\nenabled. Also the vertical distance over which humidity drops by 10 if\n'altitude_dry' is enabled.");
|
||||
gettext("The vertical distance over which heat drops by 20 if 'altitude_chill' is\nenabled. Also, the vertical distance over which humidity drops by 10 if\n'altitude_dry' is enabled.");
|
||||
gettext("Large cave depth");
|
||||
gettext("Depth below which you'll find large caves.");
|
||||
gettext("Small cave minimum number");
|
||||
@ -747,7 +747,7 @@ fake_function() {
|
||||
gettext("Cave noise #2");
|
||||
gettext("Second of two 3D noises that together define tunnels.");
|
||||
gettext("Filler depth");
|
||||
gettext("The depth of dirt or other biome filler node.");
|
||||
gettext("Variation of biome filler depth.");
|
||||
gettext("Cavern noise");
|
||||
gettext("3D noise defining giant caverns.");
|
||||
gettext("River noise");
|
||||
@ -811,7 +811,7 @@ fake_function() {
|
||||
gettext("Instrument builtin.\nThis is usually only needed by core/builtin contributors");
|
||||
gettext("Profiler");
|
||||
gettext("Have the profiler instrument itself:\n* Instrument an empty function.\nThis estimates the overhead, that instrumentation is adding (+1 function call).\n* Instrument the sampler being used to update the statistics.");
|
||||
gettext("Engine profiler");
|
||||
gettext("Engine Profiler");
|
||||
gettext("Engine profiling data print interval");
|
||||
gettext("Print the engine's profiling data in regular intervals (in seconds).\n0 = disable. Useful for developers.");
|
||||
gettext("Advanced");
|
||||
@ -891,8 +891,8 @@ fake_function() {
|
||||
gettext("Networking");
|
||||
gettext("Prometheus listener address");
|
||||
gettext("Prometheus listener address.\nIf Minetest is compiled with ENABLE_PROMETHEUS option enabled,\nenable metrics listener for Prometheus on that address.\nMetrics can be fetched on http://127.0.0.1:30000/metrics");
|
||||
gettext("Maximum size of the out chat queue");
|
||||
gettext("Maximum size of the out chat queue.\n0 to disable queueing and -1 to make the queue size unlimited.");
|
||||
gettext("Maximum size of the outgoing chat queue");
|
||||
gettext("Maximum size of the outgoing chat queue.\n0 to disable queueing and -1 to make the queue size unlimited.");
|
||||
gettext("Mapblock unload timeout");
|
||||
gettext("Timeout for client to remove unused map data from memory, in seconds.");
|
||||
gettext("Mapblock limit");
|
||||
@ -957,11 +957,11 @@ fake_function() {
|
||||
gettext("Liquid update interval in seconds.");
|
||||
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("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 50-80%. The client will not longer receive most invisible\nso that the utility of noclip mode is reduced.");
|
||||
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("Mapgen");
|
||||
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.");
|
||||
gettext("Mapgen debug");
|
||||
gettext("Dump the mapgen debug information.");
|
||||
gettext("Absolute limit of queued blocks to emerge");
|
||||
@ -979,7 +979,7 @@ fake_function() {
|
||||
gettext("Limits number of parallel HTTP requests. Affects:\n- Media fetch if server uses remote_media setting.\n- Serverlist download and server announcement.\n- Downloads performed by main menu (e.g. mod manager).\nOnly has an effect if compiled with cURL.");
|
||||
gettext("cURL file download timeout");
|
||||
gettext("Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.");
|
||||
gettext("Misc");
|
||||
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");
|
||||
@ -1011,45 +1011,4 @@ fake_function() {
|
||||
gettext("The dead zone of the joystick");
|
||||
gettext("Joystick frustum sensitivity");
|
||||
gettext("The sensitivity of the joystick axes for moving the\nin-game view frustum around.");
|
||||
gettext("Hide: Temporary Settings");
|
||||
gettext("Texture path");
|
||||
gettext("Path to texture directory. All textures are first searched from here.");
|
||||
gettext("Minimap");
|
||||
gettext("Enables minimap.");
|
||||
gettext("Round minimap");
|
||||
gettext("Shape of the minimap. Enabled = round, disabled = square.");
|
||||
gettext("Server address");
|
||||
gettext("Address to connect to.\nLeave this blank to start a local server.\nNote that the address field in the main menu overrides this setting.");
|
||||
gettext("Remote port");
|
||||
gettext("Port to connect to (UDP).\nNote that the port field in the main menu overrides this setting.");
|
||||
gettext("Damage");
|
||||
gettext("Enable players getting damage and dying.");
|
||||
gettext("Creative");
|
||||
gettext("Enable creative mode for all players");
|
||||
gettext("Player versus player");
|
||||
gettext("Whether to allow players to damage and kill each other.");
|
||||
gettext("Flying");
|
||||
gettext("Player is able to fly without being affected by gravity.\nThis requires the \"fly\" privilege on the server.");
|
||||
gettext("Pitch move mode");
|
||||
gettext("If enabled, makes move directions relative to the player's pitch when flying or swimming.");
|
||||
gettext("Fast movement");
|
||||
gettext("Fast movement (via the \"Aux1\" key).\nThis requires the \"fast\" privilege on the server.");
|
||||
gettext("Noclip");
|
||||
gettext("If enabled together with fly mode, player is able to fly through solid nodes.\nThis requires the \"noclip\" privilege on the server.");
|
||||
gettext("Continuous forward");
|
||||
gettext("Continuous forward movement, toggled by autoforward key.\nPress the autoforward key again or the backwards movement to disable.");
|
||||
gettext("Cinematic mode");
|
||||
gettext("This can be bound to a key to toggle camera smoothing when looking around.\nUseful for recording videos");
|
||||
gettext("Show technical names");
|
||||
gettext("Affects mods and texture packs in the Content and Select Mods menus, as well as\nsetting names.\nControlled by a checkbox in the settings menu.");
|
||||
gettext("Show advanced settings");
|
||||
gettext("Controlled by a checkbox in the settings menu.");
|
||||
gettext("Sound");
|
||||
gettext("Enables the sound system.\nIf disabled, this completely disables all sounds everywhere and the in-game\nsound controls will be non-functional.\nChanging this setting requires a restart.");
|
||||
gettext("Last update check");
|
||||
gettext("Unix timestamp (integer) of when the client last checked for an update\nSet this value to \"disabled\" to never check for updates.");
|
||||
gettext("Last known version update");
|
||||
gettext("Version number which was last seen during an update check.\n\nRepresentation: MMMIIIPPP, where M=Major, I=Minor, P=Patch\nEx: 5.5.0 is 005005000");
|
||||
gettext("Don't show \"reinstall Minetest Game\" notification");
|
||||
gettext("If this is set to true, the user will never (again) be shown the\n\"reinstall Minetest Game\" notification.");
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user