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: |
|
run: |
|
||||||
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin32.sh winbuild
|
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin32.sh winbuild
|
||||||
env:
|
env:
|
||||||
NO_MINETEST_GAME: 1
|
|
||||||
NO_PACKAGE: 1
|
NO_PACKAGE: 1
|
||||||
|
|
||||||
win64:
|
win64:
|
||||||
@ -195,15 +194,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin64.sh winbuild
|
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin64.sh winbuild
|
||||||
env:
|
env:
|
||||||
NO_MINETEST_GAME: 1
|
|
||||||
NO_PACKAGE: 1
|
NO_PACKAGE: 1
|
||||||
|
|
||||||
msvc:
|
msvc:
|
||||||
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
|
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
env:
|
env:
|
||||||
VCPKG_VERSION: 5cf60186a241e84e8232641ee973395d4fde90e1
|
VCPKG_VERSION: 8eb57355a4ffb410a2e94c07b4dca2dffbee8e50
|
||||||
# 2022.02
|
# 2023.10.19
|
||||||
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry
|
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
6
.github/workflows/macos.yml
vendored
6
.github/workflows/macos.yml
vendored
@ -21,11 +21,6 @@ on:
|
|||||||
- 'cmake/Modules/**'
|
- 'cmake/Modules/**'
|
||||||
- '.github/workflows/macos.yml'
|
- '.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:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
@ -38,7 +33,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
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)
|
git clone https://github.com/minetest/irrlicht lib/irrlichtmt --depth 1 -b $(cat misc/irrlichtmt_tag.txt)
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
|
@ -9,7 +9,6 @@ stages:
|
|||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
|
|
||||||
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
|
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
|
||||||
|
|
||||||
.build_template:
|
.build_template:
|
||||||
@ -120,8 +119,6 @@ package:appimage-client:
|
|||||||
- mkdir AppDir
|
- mkdir AppDir
|
||||||
- cp -a artifact/minetest/usr/ AppDir/usr/
|
- cp -a artifact/minetest/usr/ AppDir/usr/
|
||||||
- cp -a clientmods AppDir/usr/share/minetest
|
- 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
|
# Remove PrefersNonDefaultGPU property due to validation errors
|
||||||
- sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop
|
- sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop
|
||||||
script:
|
script:
|
||||||
|
@ -262,9 +262,6 @@ if(RUN_IN_PLACE)
|
|||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/texture_packs_here.txt" DESTINATION "${SHAREDIR}/textures")
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/texture_packs_here.txt" DESTINATION "${SHAREDIR}/textures")
|
||||||
endif()
|
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")
|
set(INSTALL_DEVTEST FALSE CACHE BOOL "Install Development Test")
|
||||||
|
|
||||||
if(INSTALL_DEVTEST)
|
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/client_lua_api.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||||
install(FILES "doc/menu_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/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}")
|
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
@ -336,16 +333,6 @@ cpack_add_component(Docs
|
|||||||
DESCRIPTION "Documentation about Minetest and Minetest modding"
|
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)
|
if(WIN32)
|
||||||
# Include all dynamically linked runtime libraries such as MSVCRxxx.dll
|
# Include all dynamically linked runtime libraries such as MSVCRxxx.dll
|
||||||
include(InstallRequiredSystemLibraries)
|
include(InstallRequiredSystemLibraries)
|
||||||
|
23
Dockerfile
23
Dockerfile
@ -1,7 +1,6 @@
|
|||||||
ARG DOCKER_IMAGE=alpine:3.16
|
ARG DOCKER_IMAGE=alpine:3.16
|
||||||
FROM $DOCKER_IMAGE AS dev
|
FROM $DOCKER_IMAGE AS dev
|
||||||
|
|
||||||
ENV MINETEST_GAME_VERSION master
|
|
||||||
ENV IRRLICHT_VERSION master
|
ENV IRRLICHT_VERSION master
|
||||||
ENV SPATIALINDEX_VERSION 1.9.3
|
ENV SPATIALINDEX_VERSION 1.9.3
|
||||||
ENV LUAJIT_VERSION v2.1
|
ENV LUAJIT_VERSION v2.1
|
||||||
@ -52,18 +51,16 @@ COPY src /usr/src/minetest/src
|
|||||||
COPY textures /usr/src/minetest/textures
|
COPY textures /usr/src/minetest/textures
|
||||||
|
|
||||||
WORKDIR /usr/src/minetest
|
WORKDIR /usr/src/minetest
|
||||||
RUN git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \
|
RUN cmake -B build \
|
||||||
rm -fr ./games/minetest_game/.git && \
|
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||||
cmake -B build \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
-DBUILD_SERVER=TRUE \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DENABLE_PROMETHEUS=TRUE \
|
||||||
-DBUILD_SERVER=TRUE \
|
-DBUILD_UNITTESTS=FALSE \
|
||||||
-DENABLE_PROMETHEUS=TRUE \
|
-DBUILD_CLIENT=FALSE \
|
||||||
-DBUILD_UNITTESTS=FALSE \
|
-GNinja && \
|
||||||
-DBUILD_CLIENT=FALSE \
|
cmake --build build && \
|
||||||
-GNinja && \
|
cmake --install build
|
||||||
cmake --build build && \
|
|
||||||
cmake --install build
|
|
||||||
|
|
||||||
ARG DOCKER_IMAGE=alpine:3.16
|
ARG DOCKER_IMAGE=alpine:3.16
|
||||||
FROM $DOCKER_IMAGE AS runtime
|
FROM $DOCKER_IMAGE AS runtime
|
||||||
|
@ -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>
|
Copyright (C) 2010-2022 Perttu Ahola <celeron55@gmail.com>
|
||||||
and contributors (see source file comments and the version control log)
|
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
|
Table of Contents
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@ android {
|
|||||||
task prepareAssets() {
|
task prepareAssets() {
|
||||||
def assetsFolder = "build/assets"
|
def assetsFolder = "build/assets"
|
||||||
def projRoot = rootDir.parent
|
def projRoot = rootDir.parent
|
||||||
def gameToCopy = "minetest_game"
|
|
||||||
|
|
||||||
// See issue #4638
|
// See issue #4638
|
||||||
def unsupportedLanguages = new File("${projRoot}/src/unsupported_language_list.txt").text.readLines()
|
def unsupportedLanguages = new File("${projRoot}/src/unsupported_language_list.txt").text.readLines()
|
||||||
@ -81,9 +80,6 @@ task prepareAssets() {
|
|||||||
copy {
|
copy {
|
||||||
from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts"
|
from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts"
|
||||||
}
|
}
|
||||||
copy {
|
|
||||||
from "${projRoot}/games/${gameToCopy}" into "${assetsFolder}/games/${gameToCopy}"
|
|
||||||
}
|
|
||||||
copy {
|
copy {
|
||||||
from "${projRoot}/textures" into "${assetsFolder}/textures"
|
from "${projRoot}/textures" into "${assetsFolder}/textures"
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ public class Utils {
|
|||||||
public static boolean isInstallValid(@NonNull Context context) {
|
public static boolean isInstallValid(@NonNull Context context) {
|
||||||
File userDataDirectory = getUserDataDirectory(context);
|
File userDataDirectory = getUserDataDirectory(context);
|
||||||
return userDataDirectory.isDirectory() &&
|
return userDataDirectory.isDirectory() &&
|
||||||
new File(userDataDirectory, "games").isDirectory() &&
|
|
||||||
new File(userDataDirectory, "builtin").isDirectory() &&
|
new File(userDataDirectory, "builtin").isDirectory() &&
|
||||||
new File(userDataDirectory, "client").isDirectory() &&
|
new File(userDataDirectory, "client").isDirectory() &&
|
||||||
new File(userDataDirectory, "textures").isDirectory();
|
new File(userDataDirectory, "textures").isDirectory();
|
||||||
|
@ -27,6 +27,8 @@ core.features = {
|
|||||||
get_light_data_buffer = true,
|
get_light_data_buffer = true,
|
||||||
mod_storage_on_disk = true,
|
mod_storage_on_disk = true,
|
||||||
compress_zstd = true,
|
compress_zstd = true,
|
||||||
|
sound_params_start_time = true,
|
||||||
|
physics_overrides_v2 = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
function core.has_feature(arg)
|
function core.has_feature(arg)
|
||||||
|
@ -698,17 +698,14 @@ local function resolve_auto_install_spec()
|
|||||||
local resolved = nil
|
local resolved = nil
|
||||||
|
|
||||||
for _, pkg in ipairs(store.packages_full_unordered) do
|
for _, pkg in ipairs(store.packages_full_unordered) do
|
||||||
if pkg.author == auto_install_spec.author and
|
if pkg.id == auto_install_spec then
|
||||||
(pkg.name == auto_install_spec.name or
|
|
||||||
(pkg.type == "game" and pkg.name == auto_install_spec.name .. "_game")) then
|
|
||||||
resolved = pkg
|
resolved = pkg
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not resolved then
|
if not resolved then
|
||||||
gamedata.errormessage = fgettext("The package $1/$2 was not found.",
|
gamedata.errormessage = fgettext("The package $1 was not found.", auto_install_spec)
|
||||||
auto_install_spec.author, auto_install_spec.name)
|
|
||||||
ui.update()
|
ui.update()
|
||||||
|
|
||||||
auto_install_spec = nil
|
auto_install_spec = nil
|
||||||
@ -777,26 +774,26 @@ function store.update_paths()
|
|||||||
local mod_hash = {}
|
local mod_hash = {}
|
||||||
pkgmgr.refresh_globals()
|
pkgmgr.refresh_globals()
|
||||||
for _, mod in pairs(pkgmgr.global_mods:get_list()) do
|
for _, mod in pairs(pkgmgr.global_mods:get_list()) do
|
||||||
if mod.author and mod.release > 0 then
|
local cdb_id = pkgmgr.get_contentdb_id(mod)
|
||||||
local id = mod.author:lower() .. "/" .. mod.name
|
if cdb_id then
|
||||||
mod_hash[store.aliases[id] or id] = mod
|
mod_hash[store.aliases[cdb_id] or cdb_id] = mod
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local game_hash = {}
|
local game_hash = {}
|
||||||
pkgmgr.update_gamelist()
|
pkgmgr.update_gamelist()
|
||||||
for _, game in pairs(pkgmgr.games) do
|
for _, game in pairs(pkgmgr.games) do
|
||||||
if game.author ~= "" and game.release > 0 then
|
local cdb_id = pkgmgr.get_contentdb_id(game)
|
||||||
local id = game.author:lower() .. "/" .. game.id
|
if cdb_id then
|
||||||
game_hash[store.aliases[id] or id] = game
|
game_hash[store.aliases[cdb_id] or cdb_id] = game
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local txp_hash = {}
|
local txp_hash = {}
|
||||||
for _, txp in pairs(pkgmgr.get_texture_packs()) do
|
for _, txp in pairs(pkgmgr.get_texture_packs()) do
|
||||||
if txp.author and txp.release > 0 then
|
local cdb_id = pkgmgr.get_contentdb_id(txp)
|
||||||
local id = txp.author:lower() .. "/" .. txp.name
|
if cdb_id then
|
||||||
txp_hash[store.aliases[id] or id] = txp
|
txp_hash[store.aliases[cdb_id] or cdb_id] = txp
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -815,6 +812,7 @@ function store.update_paths()
|
|||||||
package.installed_release = content.release or 0
|
package.installed_release = content.release or 0
|
||||||
else
|
else
|
||||||
package.path = nil
|
package.path = nil
|
||||||
|
package.installed_release = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1193,7 +1191,7 @@ end
|
|||||||
--- @param type string | nil
|
--- @param type string | nil
|
||||||
--- Sets initial package filter. "game", "mod", "txp" or nil (no filter).
|
--- Sets initial package filter. "game", "mod", "txp" or nil (no filter).
|
||||||
--- @param install_spec table | nil
|
--- @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.
|
--- Sets package to install or update automatically.
|
||||||
function create_store_dlg(type, install_spec)
|
function create_store_dlg(type, install_spec)
|
||||||
search_string = ""
|
search_string = ""
|
||||||
|
@ -777,6 +777,30 @@ function pkgmgr.update_gamelist()
|
|||||||
end)
|
end)
|
||||||
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
|
-- read initial data
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
@ -59,7 +59,7 @@ local function has_packages_from_cdb()
|
|||||||
pkgmgr.update_gamelist()
|
pkgmgr.update_gamelist()
|
||||||
|
|
||||||
for _, content in pairs(pkgmgr.get_all()) do
|
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
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -114,18 +114,13 @@ function update_detector.get_all()
|
|||||||
local ret = {}
|
local ret = {}
|
||||||
local all_content = pkgmgr.get_all()
|
local all_content = pkgmgr.get_all()
|
||||||
for _, content in ipairs(all_content) do
|
for _, content in ipairs(all_content) do
|
||||||
if content.author and content.release > 0 then
|
local cdb_id = pkgmgr.get_contentdb_id(content)
|
||||||
-- 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 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
|
if not latest_release and content.type == "game" then
|
||||||
latest_release = latest_releases[id .. "_game"]
|
latest_release = latest_releases[cdb_id .. "_game"]
|
||||||
end
|
end
|
||||||
|
|
||||||
if latest_release and latest_release > content.release then
|
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 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)
|
dlg:set_parent(maintab)
|
||||||
maintab:hide()
|
maintab:hide()
|
||||||
dlg:show()
|
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 info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png")
|
||||||
local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png")
|
local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png")
|
||||||
|
|
||||||
local gettext = fgettext_ne
|
|
||||||
local all_pages = {}
|
local all_pages = {}
|
||||||
local page_by_id = {}
|
local page_by_id = {}
|
||||||
local filtered_pages = all_pages
|
local filtered_pages = all_pages
|
||||||
@ -66,23 +65,23 @@ local change_keys = {
|
|||||||
|
|
||||||
add_page({
|
add_page({
|
||||||
id = "accessibility",
|
id = "accessibility",
|
||||||
title = gettext("Accessibility"),
|
title = fgettext_ne("Accessibility"),
|
||||||
content = {
|
content = {
|
||||||
"language",
|
"language",
|
||||||
{ heading = gettext("General") },
|
{ heading = fgettext_ne("General") },
|
||||||
"font_size",
|
"font_size",
|
||||||
"chat_font_size",
|
"chat_font_size",
|
||||||
"gui_scaling",
|
"gui_scaling",
|
||||||
"hud_scaling",
|
"hud_scaling",
|
||||||
"show_nametag_backgrounds",
|
"show_nametag_backgrounds",
|
||||||
{ heading = gettext("Chat") },
|
{ heading = fgettext_ne("Chat") },
|
||||||
"console_height",
|
"console_height",
|
||||||
"console_alpha",
|
"console_alpha",
|
||||||
"console_color",
|
"console_color",
|
||||||
{ heading = gettext("Controls") },
|
{ heading = fgettext_ne("Controls") },
|
||||||
"autojump",
|
"autojump",
|
||||||
"safe_dig_and_place",
|
"safe_dig_and_place",
|
||||||
{ heading = gettext("Movement") },
|
{ heading = fgettext_ne("Movement") },
|
||||||
"arm_inertia",
|
"arm_inertia",
|
||||||
"view_bobbing_amount",
|
"view_bobbing_amount",
|
||||||
"fall_bobbing_amount",
|
"fall_bobbing_amount",
|
||||||
@ -97,7 +96,7 @@ local function load_settingtypes()
|
|||||||
if not page then
|
if not page then
|
||||||
page = add_page({
|
page = add_page({
|
||||||
id = (section or "general"):lower():gsub(" ", "_"),
|
id = (section or "general"):lower():gsub(" ", "_"),
|
||||||
title = section or gettext("General"),
|
title = section or fgettext_ne("General"),
|
||||||
section = section,
|
section = section,
|
||||||
content = {},
|
content = {},
|
||||||
})
|
})
|
||||||
@ -117,13 +116,11 @@ local function load_settingtypes()
|
|||||||
content = {},
|
content = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if page.title:sub(1, 5) ~= "Hide:" then
|
page = add_page(page)
|
||||||
page = add_page(page)
|
|
||||||
end
|
|
||||||
elseif entry.level == 2 then
|
elseif entry.level == 2 then
|
||||||
ensure_page_started()
|
ensure_page_started()
|
||||||
page.content[#page.content + 1] = {
|
page.content[#page.content + 1] = {
|
||||||
heading = gettext(entry.readable_name or entry.name),
|
heading = fgettext_ne(entry.readable_name or entry.name),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
local settings = ...
|
|
||||||
|
|
||||||
local concat = table.concat
|
local concat = table.concat
|
||||||
local insert = table.insert
|
local insert = table.insert
|
||||||
local sprintf = string.format
|
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 }
|
local result = { minetest_example_header }
|
||||||
for _, entry in ipairs(settings) do
|
for _, entry in ipairs(settings) do
|
||||||
if entry.type == "category" then
|
if entry.type == "category" then
|
||||||
@ -108,14 +106,11 @@ local translation_file_header = [[
|
|||||||
|
|
||||||
fake_function() {]]
|
fake_function() {]]
|
||||||
|
|
||||||
local function create_translation_file()
|
local function create_translation_file(settings)
|
||||||
local result = { translation_file_header }
|
local result = { translation_file_header }
|
||||||
for _, entry in ipairs(settings) do
|
for _, entry in ipairs(settings) do
|
||||||
if entry.type == "category" then
|
if entry.type == "category" then
|
||||||
insert(result, sprintf("\tgettext(%q);", entry.name))
|
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
|
else
|
||||||
if entry.readable_name then
|
if entry.readable_name then
|
||||||
insert(result, sprintf("\tgettext(%q);", entry.readable_name))
|
insert(result, sprintf("\tgettext(%q);", entry.readable_name))
|
||||||
@ -132,12 +127,13 @@ local function create_translation_file()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local file = assert(io.open("minetest.conf.example", "w"))
|
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:close()
|
||||||
|
|
||||||
file = assert(io.open("src/settings_translation_file.cpp", "w"))
|
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
|
-- 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.
|
-- used instead. The file will also appear in the 'bin' folder.
|
||||||
--file = assert(io.open("settings_translation_file.cpp", "w"))
|
--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()
|
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.
|
-- 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'.
|
-- 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
|
-- category
|
||||||
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
|
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
|
||||||
if category then
|
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, {
|
table.insert(settings, {
|
||||||
name = category,
|
name = category,
|
||||||
level = stars:len() + base_level,
|
level = category_level,
|
||||||
type = "category",
|
type = "category",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if settings.current_hide_level then
|
||||||
|
-- Ignore this line, we're inside a hidden category.
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- settings
|
-- settings
|
||||||
local first_part, name, readable_name, setting_type = line:match("^"
|
local first_part, name, readable_name, setting_type = line:match("^"
|
||||||
-- this first capture group matches the whole first part,
|
-- 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)
|
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()
|
-- store this helper variable in the table so it's easier to pass to parse_setting_line()
|
||||||
result.current_comment = {}
|
result.current_comment = {}
|
||||||
|
result.current_hide_level = nil
|
||||||
|
|
||||||
local line = file:read("*line")
|
local line = file:read("*line")
|
||||||
while line do
|
while line do
|
||||||
@ -360,6 +384,7 @@ local function parse_single_file(file, filepath, read_all, result, base_level, a
|
|||||||
end
|
end
|
||||||
|
|
||||||
result.current_comment = nil
|
result.current_comment = nil
|
||||||
|
result.current_hide_level = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
|
|||||||
|
|
||||||
if fields.btn_mod_mgr_update then
|
if fields.btn_mod_mgr_update then
|
||||||
local pkg = packages:get_list()[tabdata.selected_pkg]
|
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)
|
dlg:set_parent(tabview)
|
||||||
tabview:hide()
|
tabview:hide()
|
||||||
dlg:show()
|
dlg:show()
|
||||||
|
@ -26,7 +26,7 @@ For Fedora users:
|
|||||||
|
|
||||||
For openSUSE 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:
|
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
|
git clone --depth 1 https://github.com/minetest/minetest.git
|
||||||
cd minetest
|
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:
|
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
|
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
|
tar xf master.tar.gz
|
||||||
cd minetest-master
|
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:
|
Download IrrlichtMt, without using Git:
|
||||||
|
|
||||||
cd lib/
|
cd lib/
|
||||||
|
@ -20,12 +20,6 @@ git clone --depth 1 https://github.com/minetest/minetest.git
|
|||||||
cd minetest
|
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:
|
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.
|
-- its end in `-start_time` seconds.
|
||||||
-- It is unspecified what happens if `loop` is false and `start_time` is
|
-- It is unspecified what happens if `loop` is false and `start_time` is
|
||||||
-- smaller than minus the sound's length.
|
-- smaller than minus the sound's length.
|
||||||
|
-- Available since feature `sound_params_start_time`.
|
||||||
|
|
||||||
loop = false,
|
loop = false,
|
||||||
-- If true, sound is played in a loop.
|
-- If true, sound is played in a loop.
|
||||||
@ -1629,7 +1630,7 @@ HUD
|
|||||||
HUD element types
|
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
|
To account for differing resolutions, the position coordinates are the
|
||||||
percentage of the screen, ranging in value from `0` to `1`.
|
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
|
* `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 top of this node. There's also an armor group with the same name.
|
||||||
The final player damage is determined by the following formula:
|
The final player damage is determined by the following formula:
|
||||||
|
```lua
|
||||||
damage =
|
damage =
|
||||||
collision speed
|
collision speed
|
||||||
* ((node_fall_damage_add_percent + 100) / 100) -- node group
|
* ((node_fall_damage_add_percent + 100) / 100) -- node group
|
||||||
* ((player_fall_damage_add_percent + 100) / 100) -- player armor group
|
* ((player_fall_damage_add_percent + 100) / 100) -- player armor group
|
||||||
- (14) -- constant tolerance
|
- (14) -- constant tolerance
|
||||||
|
```
|
||||||
Negative damage values are discarded as no damage.
|
Negative damage values are discarded as no damage.
|
||||||
* `falling_node`: if there is no walkable block under the node it will fall
|
* `falling_node`: if there is no walkable block under the node it will fall
|
||||||
* `float`: the node will not fall through liquids (`liquidtype ~= "none"`)
|
* `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
|
Texts can be translated client-side with the help of `minetest.translate` and
|
||||||
translation files.
|
translation files.
|
||||||
|
|
||||||
Consider using the script `util/mtt_update.py` in the Minetest repository
|
Consider using the script `util/mod_translation_updater.py` in the Minetest
|
||||||
to generate and update translation files automatically from the Lua sources.
|
repository to generate and update translation files automatically from the Lua
|
||||||
See `util/README_mtt_update.md` for an explanation.
|
sources. See `util/README_mod_translation_updater.md` for an explanation.
|
||||||
|
|
||||||
Translating a string
|
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
|
a list on labels and send results to client. A method is supplied to achieve
|
||||||
that:
|
that:
|
||||||
|
|
||||||
`minetest.get_translated_string(lang_code, string)`: Translates `string` using
|
`minetest.get_translated_string(lang_code, string)`: resolves translations in
|
||||||
translations for `lang_code` language. It gives the same result as if the string
|
the given string just like the client would, using the translation files for
|
||||||
was translated by the client.
|
`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 `lang_code` to use for a given player can be retrieved from
|
||||||
the table returned by `minetest.get_player_information(name)`.
|
the table returned by `minetest.get_player_information(name)`.
|
||||||
@ -5268,6 +5272,12 @@ Utilities
|
|||||||
mod_storage_on_disk = true,
|
mod_storage_on_disk = true,
|
||||||
-- "zstd" method for compress/decompress (5.7.0)
|
-- "zstd" method for compress/decompress (5.7.0)
|
||||||
compress_zstd = true,
|
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
|
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
|
for all players and only use `set_physics_override` when you need to change
|
||||||
from the base value on a per-player basis
|
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`
|
* `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
|
* `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
|
if not player or not player:is_player() then
|
||||||
return
|
return
|
||||||
end
|
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
|
end
|
||||||
minetest.after(2.0, cb, player)
|
minetest.after(2.0, cb, player)
|
||||||
end)
|
end)
|
||||||
|
@ -428,17 +428,17 @@ local MAX_BOUNCE_NONJUMPY = 140
|
|||||||
for i=-MAX_BOUNCE_NONJUMPY, MAX_BOUNCE_JUMPY, 20 do
|
for i=-MAX_BOUNCE_NONJUMPY, MAX_BOUNCE_JUMPY, 20 do
|
||||||
if i ~= 0 then
|
if i ~= 0 then
|
||||||
local desc
|
local desc
|
||||||
local val = math.floor(((i-20)/200)*255)
|
local val = math.floor((math.abs(i) - 20) / 200 * 255)
|
||||||
local val2 = math.max(0, 200 - val)
|
local val2 = math.max(0, 255 - val)
|
||||||
local num = string.format("%03d", math.abs(i))
|
local num = string.format("%03d", math.abs(i))
|
||||||
if i > 0 then
|
if i > 0 then
|
||||||
desc = S("Bouncy Node (@1%), jumpy", i).."\n"..
|
desc = S("Bouncy Node (@1%), jumpy", i).."\n"..
|
||||||
S("Sneaking/jumping affects bounce")
|
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
|
else
|
||||||
desc = S("Bouncy Node (@1%), non-jumpy", math.abs(i)).."\n"..
|
desc = S("Bouncy Node (@1%), non-jumpy", math.abs(i)).."\n"..
|
||||||
S("Sneaking/jumping does not affect bounce")
|
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
|
num = "NEG"..num
|
||||||
end
|
end
|
||||||
minetest.register_node("testnodes:bouncy"..num, {
|
minetest.register_node("testnodes:bouncy"..num, {
|
||||||
|
@ -201,13 +201,13 @@ full_brightness (Full brightness) bool false
|
|||||||
# type: bool
|
# type: bool
|
||||||
# enable_particles = true
|
# enable_particles = true
|
||||||
|
|
||||||
### 3d
|
### 3D
|
||||||
|
|
||||||
# 3D support.
|
# 3D support.
|
||||||
# Currently supported:
|
# Currently supported:
|
||||||
# - none: no 3d output.
|
# - none: no 3d output.
|
||||||
# - anaglyph: cyan/magenta color 3d.
|
# - 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.
|
# - topbottom: split screen top/bottom.
|
||||||
# - sidebyside: split screen side by side.
|
# - sidebyside: split screen side by side.
|
||||||
# - crossview: Cross-eyed 3d
|
# - crossview: Cross-eyed 3d
|
||||||
@ -319,7 +319,7 @@ full_brightness (Full brightness) bool false
|
|||||||
|
|
||||||
### Clouds
|
### Clouds
|
||||||
|
|
||||||
# Clouds are a client side effect.
|
# Clouds are a client-side effect.
|
||||||
# type: bool
|
# type: bool
|
||||||
# enable_clouds = true
|
# enable_clouds = true
|
||||||
|
|
||||||
@ -330,7 +330,7 @@ full_brightness (Full brightness) bool false
|
|||||||
### Filtering and Antialiasing
|
### Filtering and Antialiasing
|
||||||
|
|
||||||
# Use mipmaps when scaling textures down. May slightly increase performance,
|
# 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.
|
# Gamma-correct downscaling is not supported.
|
||||||
# type: bool
|
# type: bool
|
||||||
# mip_map = false
|
# mip_map = false
|
||||||
@ -368,7 +368,7 @@ full_brightness (Full brightness) bool false
|
|||||||
# type: enum values: none, fsaa, fxaa, ssaa
|
# type: enum values: none, fsaa, fxaa, ssaa
|
||||||
# antialiasing = none
|
# 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.
|
# Value of 2 means taking 2x2 = 4 samples.
|
||||||
# type: enum values: 2, 4, 8, 16
|
# type: enum values: 2, 4, 8, 16
|
||||||
# fsaa = 2
|
# fsaa = 2
|
||||||
@ -472,7 +472,7 @@ full_brightness (Full brightness) bool false
|
|||||||
# type: bool
|
# type: bool
|
||||||
# shadow_map_color = false
|
# 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
|
# Higher values might make shadows laggy, lower values
|
||||||
# will consume more resources.
|
# will consume more resources.
|
||||||
# Minimum value: 1; maximum value: 16
|
# 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
|
# type: enum values: , be, bg, ca, cs, da, de, el, en, eo, es, et, eu, fi, fr, gd, gl, hu, id, it, ja, jbo, kk, ko, lt, lv, ms, nb, nl, nn, pl, pt, pt_BR, ro, ru, sk, sl, sr_Cyrl, sr_Latn, sv, sw, tr, uk, vi, zh_CN, zh_TW
|
||||||
# language =
|
# language =
|
||||||
|
|
||||||
### GUIs
|
### GUI
|
||||||
|
|
||||||
# Scale GUI by a user specified value.
|
# Scale GUI by a user specified value.
|
||||||
# Use a nearest-neighbor-anti-alias filter to scale the GUI.
|
# 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
|
# type: int min: 10 max: 65535
|
||||||
# chat_message_max_size = 500
|
# 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
|
# type: float min: 1
|
||||||
# chat_message_limit_per_10sec = 8.0
|
# 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
|
# type: flags possible values: caves, dungeons, light, decorations, biomes, ores, nocaves, nodungeons, nolight, nodecorations, nobiomes, noores
|
||||||
# mg_flags = caves,dungeons,light,decorations,biomes,ores
|
# mg_flags = caves,dungeons,light,decorations,biomes,ores
|
||||||
|
|
||||||
## Biome API noise parameters
|
## Biome API
|
||||||
|
|
||||||
# Temperature variation for biomes.
|
# Temperature variation for biomes.
|
||||||
# type: noise_params_2d
|
# 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
|
# to above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the
|
||||||
# upper tapering).
|
# upper tapering).
|
||||||
# ***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***:
|
# ***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
|
# to be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other
|
||||||
# required value depending on 'mgv7_np_floatland'), to avoid
|
# required value depending on 'mgv7_np_floatland'), to avoid
|
||||||
# server-intensive extreme water flow and to avoid vast flooding of the
|
# 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
|
# mgvalleys_spflags = altitude_chill,humid_rivers,vary_river_depth,altitude_dry
|
||||||
|
|
||||||
# The vertical distance over which heat drops by 20 if 'altitude_chill' is
|
# 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.
|
# 'altitude_dry' is enabled.
|
||||||
# type: int min: 0 max: 65535
|
# type: int min: 0 max: 65535
|
||||||
# mgvalleys_altitude_chill = 90
|
# mgvalleys_altitude_chill = 90
|
||||||
@ -2403,7 +2403,7 @@ full_brightness (Full brightness) bool false
|
|||||||
# flags =
|
# flags =
|
||||||
# }
|
# }
|
||||||
|
|
||||||
# The depth of dirt or other biome filler node.
|
# Variation of biome filler depth.
|
||||||
# type: noise_params_2d
|
# type: noise_params_2d
|
||||||
# mgvalleys_np_filler_depth = {
|
# mgvalleys_np_filler_depth = {
|
||||||
# offset = 0,
|
# offset = 0,
|
||||||
@ -2604,7 +2604,7 @@ full_brightness (Full brightness) bool false
|
|||||||
# type: enum values: txt, csv, lua, json, json_pretty
|
# type: enum values: txt, csv, lua, json, json_pretty
|
||||||
# profiler.default_report_format = txt
|
# profiler.default_report_format = txt
|
||||||
|
|
||||||
# The file path relative to your worldpath in which profiles will be saved to.
|
# The file path relative to your world path in which profiles will be saved to.
|
||||||
# type: string
|
# type: string
|
||||||
# profiler.report_path =
|
# profiler.report_path =
|
||||||
|
|
||||||
@ -2641,7 +2641,7 @@ full_brightness (Full brightness) bool false
|
|||||||
# type: bool
|
# type: bool
|
||||||
# instrument.profiler = false
|
# instrument.profiler = false
|
||||||
|
|
||||||
### Engine profiler
|
### Engine Profiler
|
||||||
|
|
||||||
# Print the engine's profiling data in regular intervals (in seconds).
|
# Print the engine's profiling data in regular intervals (in seconds).
|
||||||
# 0 = disable. Useful for developers.
|
# 0 = disable. Useful for developers.
|
||||||
@ -2857,7 +2857,7 @@ full_brightness (Full brightness) bool false
|
|||||||
# type: string
|
# type: string
|
||||||
# prometheus_listener_address = 127.0.0.1:30000
|
# 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.
|
# 0 to disable queueing and -1 to make the queue size unlimited.
|
||||||
# type: int min: -1 max: 32767
|
# type: int min: -1 max: 32767
|
||||||
# max_out_chat_queue_size = 20
|
# max_out_chat_queue_size = 20
|
||||||
@ -3024,17 +3024,17 @@ full_brightness (Full brightness) bool false
|
|||||||
# type: int min: 2 max: 32767
|
# type: int min: 2 max: 32767
|
||||||
# block_send_optimize_distance = 4
|
# block_send_optimize_distance = 4
|
||||||
|
|
||||||
# If enabled the server will perform map block occlusion culling based on
|
# If enabled, the server will perform map block occlusion culling based on
|
||||||
# on the eye position of the player. This can reduce the number of blocks
|
# 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
|
# sent to the client by 50-80%. Clients will no longer receive most
|
||||||
# so that the utility of noclip mode is reduced.
|
# invisible blocks, so that the utility of noclip mode is reduced.
|
||||||
# type: bool
|
# type: bool
|
||||||
# server_side_occlusion_culling = true
|
# server_side_occlusion_culling = true
|
||||||
|
|
||||||
### Mapgen
|
### Mapgen
|
||||||
|
|
||||||
# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).
|
# 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.
|
# increasing this value above 5.
|
||||||
# Reducing this value increases cave and dungeon density.
|
# Reducing this value increases cave and dungeon density.
|
||||||
# Altering this value is for special usage, leaving it unchanged is
|
# 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
|
# type: int min: 5000 max: 2147483647
|
||||||
# curl_file_download_timeout = 300000
|
# curl_file_download_timeout = 300000
|
||||||
|
|
||||||
### Misc
|
### Miscellaneous
|
||||||
|
|
||||||
# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
|
# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
|
||||||
# type: int min: 1
|
# type: int min: 1
|
||||||
|
File diff suppressed because it is too large
Load Diff
1050
po/be/minetest.po
1050
po/be/minetest.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1036
po/ca/minetest.po
1036
po/ca/minetest.po
File diff suppressed because it is too large
Load Diff
1098
po/cs/minetest.po
1098
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
1403
po/de/minetest.po
1403
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
1032
po/eo/minetest.po
1032
po/eo/minetest.po
File diff suppressed because it is too large
Load Diff
1372
po/es/minetest.po
1372
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
1498
po/fr/minetest.po
1498
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
1065
po/gl/minetest.po
1065
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
1067
po/hu/minetest.po
1067
po/hu/minetest.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1466
po/id/minetest.po
1466
po/id/minetest.po
File diff suppressed because it is too large
Load Diff
1121
po/it/minetest.po
1121
po/it/minetest.po
File diff suppressed because it is too large
Load Diff
1423
po/ja/minetest.po
1423
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
751
po/minetest.pot
751
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
1459
po/ms/minetest.po
1459
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
1065
po/nl/minetest.po
1065
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
1082
po/pl/minetest.po
1082
po/pl/minetest.po
File diff suppressed because it is too large
Load Diff
1108
po/pt/minetest.po
1108
po/pt/minetest.po
File diff suppressed because it is too large
Load Diff
1113
po/pt_BR/minetest.po
1113
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
2641
po/ru/minetest.po
2641
po/ru/minetest.po
File diff suppressed because it is too large
Load Diff
1099
po/sk/minetest.po
1099
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
1067
po/sv/minetest.po
1067
po/sv/minetest.po
File diff suppressed because it is too large
Load Diff
1019
po/sw/minetest.po
1019
po/sw/minetest.po
File diff suppressed because it is too large
Load Diff
1034
po/th/minetest.po
1034
po/th/minetest.po
File diff suppressed because it is too large
Load Diff
1046
po/tr/minetest.po
1046
po/tr/minetest.po
File diff suppressed because it is too large
Load Diff
1021
po/tt/minetest.po
1021
po/tt/minetest.po
File diff suppressed because it is too large
Load Diff
1765
po/uk/minetest.po
1765
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
1038
po/zh_CN/minetest.po
1038
po/zh_CN/minetest.po
File diff suppressed because it is too large
Load Diff
1011
po/zh_TW/minetest.po
1011
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;
|
s32 yaw = myplayer->getYaw() * 100;
|
||||||
u32 keyPressed = myplayer->control.getKeysPressed();
|
u32 keyPressed = myplayer->control.getKeysPressed();
|
||||||
// scaled by 80, so that pi can fit into a u8
|
// scaled by 80, so that pi can fit into a u8
|
||||||
u8 fov = clientMap->getCameraFov() * 80;
|
u8 fov = std::fmin(255.0f, clientMap->getCameraFov() * 80.0f);
|
||||||
u8 wanted_range = MYMIN(255,
|
u8 wanted_range = std::fmin(255.0f,
|
||||||
std::ceil(clientMap->getControl().wanted_range / MAP_BLOCKSIZE));
|
std::ceil(clientMap->getWantedRange() * (1.0f / MAP_BLOCKSIZE)));
|
||||||
|
|
||||||
v3s32 position(pf.X, pf.Y, pf.Z);
|
v3s32 position(pf.X, pf.Y, pf.Z);
|
||||||
v3s32 speed(sf.X, sf.Y, sf.Z);
|
v3s32 speed(sf.X, sf.Y, sf.Z);
|
||||||
@ -1385,8 +1385,9 @@ void Client::sendPlayerPos()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ClientMap &map = m_env.getClientMap();
|
ClientMap &map = m_env.getClientMap();
|
||||||
u8 camera_fov = map.getCameraFov();
|
u8 camera_fov = std::fmin(255.0f, map.getCameraFov() * 80.0f);
|
||||||
u8 wanted_range = map.getControl().wanted_range;
|
u8 wanted_range = std::fmin(255.0f,
|
||||||
|
std::ceil(map.getWantedRange() * (1.0f / MAP_BLOCKSIZE)));
|
||||||
|
|
||||||
u32 keyPressed = player->control.getKeysPressed();
|
u32 keyPressed = player->control.getKeysPressed();
|
||||||
bool camera_inverted = m_camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT;
|
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);
|
const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
|
||||||
void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
||||||
const CameraOrientation &cam);
|
const CameraOrientation &cam);
|
||||||
|
void updateClouds(float dtime);
|
||||||
void updateShadows();
|
void updateShadows();
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
@ -4012,33 +4013,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||||||
/*
|
/*
|
||||||
Update clouds
|
Update clouds
|
||||||
*/
|
*/
|
||||||
if (clouds) {
|
if (clouds)
|
||||||
if (sky->getCloudsVisible()) {
|
updateClouds(dtime);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update particles
|
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));
|
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 */
|
/* Log times and stuff for visualization */
|
||||||
inline void Game::updateProfilerGraphs(ProfilerGraph *graph)
|
inline void Game::updateProfilerGraphs(ProfilerGraph *graph)
|
||||||
{
|
{
|
||||||
|
@ -169,7 +169,6 @@ private:
|
|||||||
LocalPlayer *m_player;
|
LocalPlayer *m_player;
|
||||||
ParticleSpawnerParameters p;
|
ParticleSpawnerParameters p;
|
||||||
std::vector<ClientParticleTexture> m_texpool;
|
std::vector<ClientParticleTexture> m_texpool;
|
||||||
size_t m_texcount;
|
|
||||||
std::vector<float> m_spawntimes;
|
std::vector<float> m_spawntimes;
|
||||||
u16 m_attached_id;
|
u16 m_attached_id;
|
||||||
};
|
};
|
||||||
|
@ -266,8 +266,8 @@ void GUIScrollBar::setPos(const s32 &pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_auto_scaling)
|
if (is_auto_scaling)
|
||||||
thumb_size = s32(thumb_area /
|
thumb_size = (s32)std::fmin(S32_MAX,
|
||||||
(f32(page_size) / f32(thumb_area + border_size * 2)));
|
thumb_area / (f32(page_size) / f32(thumb_area + border_size * 2)));
|
||||||
|
|
||||||
thumb_size = core::s32_clamp(thumb_size, thumb_min, thumb_area);
|
thumb_size = core::s32_clamp(thumb_size, thumb_min, thumb_area);
|
||||||
scroll_pos = core::s32_clamp(pos, min_pos, max_pos);
|
scroll_pos = core::s32_clamp(pos, min_pos, max_pos);
|
||||||
|
@ -70,15 +70,15 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
|||||||
Add stuff
|
Add stuff
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
|
core::rect<s32> rect(0, 0, 300 * s, 20 * s);
|
||||||
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 70 * s);
|
rect = rect + v2s32(size.X / 2 - 150 * s, size.Y / 2 - 70 * s);
|
||||||
|
|
||||||
StaticText::add(Environment, fwgettext("Sound Volume: %d%%", volume),
|
StaticText::add(Environment, fwgettext("Sound Volume: %d%%", volume),
|
||||||
rect, false, true, this, ID_soundText);
|
rect, false, true, this, ID_soundText);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 80 * s, 30 * s);
|
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
|
||||||
rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s);
|
rect = rect + v2s32(size.X / 2 - 100 * s / 2, size.Y / 2 + 55 * s);
|
||||||
GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton,
|
GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton,
|
||||||
wstrgettext("Exit").c_str());
|
wstrgettext("Exit").c_str());
|
||||||
}
|
}
|
||||||
@ -91,8 +91,8 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
|||||||
e->setPos(volume);
|
e->setPos(volume);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
|
core::rect<s32> rect(0, 0, 300 * s, 20 * s);
|
||||||
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 35 * s);
|
rect = rect + v2s32(size.X / 2 - 150 * s, size.Y / 2 - 35 * s);
|
||||||
Environment->addCheckBox(g_settings->getBool("mute_sound"), rect, this,
|
Environment->addCheckBox(g_settings->getBool("mute_sound"), rect, this,
|
||||||
ID_soundMuteButton, wstrgettext("Muted").c_str());
|
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 DEBUGFILE "debug.txt"
|
||||||
#define DEFAULT_SERVER_PORT 30000
|
#define DEFAULT_SERVER_PORT 30000
|
||||||
|
|
||||||
|
#define ENV_MT_LOGCOLOR "MT_LOGCOLOR"
|
||||||
#define ENV_NO_COLOR "NO_COLOR"
|
#define ENV_NO_COLOR "NO_COLOR"
|
||||||
#define ENV_CLICOLOR "CLICOLOR"
|
#define ENV_CLICOLOR "CLICOLOR"
|
||||||
#define ENV_CLICOLOR_FORCE "CLICOLOR_FORCE"
|
#define ENV_CLICOLOR_FORCE "CLICOLOR_FORCE"
|
||||||
@ -287,6 +288,13 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
static void get_env_opts(Settings &args)
|
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 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 supported (auto-detection, this is the default)
|
||||||
// CLICOLOR == 0: ANSI colors are NOT supported
|
// CLICOLOR == 0: ANSI colors are NOT supported
|
||||||
@ -493,12 +501,6 @@ static bool setup_log_params(const Settings &cmd_args)
|
|||||||
std::string color_mode;
|
std::string color_mode;
|
||||||
if (cmd_args.exists("color")) {
|
if (cmd_args.exists("color")) {
|
||||||
color_mode = cmd_args.get("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.empty()) {
|
||||||
if (color_mode == "auto") {
|
if (color_mode == "auto") {
|
||||||
@ -550,8 +552,7 @@ static bool create_userdata_path()
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::string findProgram(const char *name)
|
[[maybe_unused]] std::string findProgram(const char *name) {
|
||||||
{
|
|
||||||
char *path_c = getenv("PATH");
|
char *path_c = getenv("PATH");
|
||||||
if (!path_c)
|
if (!path_c)
|
||||||
return "";
|
return "";
|
||||||
@ -571,8 +572,9 @@ namespace {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const char *debuggerNames[] = {"gdb.exe", "lldb.exe"};
|
const char *debuggerNames[] = {"gdb.exe", "lldb.exe"};
|
||||||
#else
|
#else
|
||||||
const char *debuggerNames[] = {"gdb", "lldb"};
|
[[maybe_unused]] const char *debuggerNames[] = {"gdb", "lldb"};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void getDebuggerArgs(T &out, int i) {
|
void getDebuggerArgs(T &out, int i) {
|
||||||
if (i == 0) {
|
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)
|
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);
|
video::SColor color(0);
|
||||||
CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
|
CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
|
||||||
lua_getfield(L, index, "a");
|
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_pop(L, 1);
|
||||||
lua_getfield(L, index, "r");
|
lua_getfield(L, index, "r");
|
||||||
color.setRed(lua_tonumber(L, -1));
|
color.setRed(clamp_col(lua_tonumber(L, -1)));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
lua_getfield(L, index, "g");
|
lua_getfield(L, index, "g");
|
||||||
color.setGreen(lua_tonumber(L, -1));
|
color.setGreen(clamp_col(lua_tonumber(L, -1)));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
lua_getfield(L, index, "b");
|
lua_getfield(L, index, "b");
|
||||||
color.setBlue(lua_tonumber(L, -1));
|
color.setBlue(clamp_col(lua_tonumber(L, -1)));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return color;
|
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("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("Digging particles");
|
||||||
gettext("Adds particles when digging a node.");
|
gettext("Adds particles when digging a node.");
|
||||||
gettext("3d");
|
gettext("3D");
|
||||||
gettext("3D mode");
|
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("3D mode parallax strength");
|
||||||
gettext("Strength of 3D mode parallax.");
|
gettext("Strength of 3D mode parallax.");
|
||||||
gettext("Bobbing");
|
gettext("Bobbing");
|
||||||
@ -130,12 +130,12 @@ fake_function() {
|
|||||||
gettext("Fraction of the visible distance at which fog starts to be rendered");
|
gettext("Fraction of the visible distance at which fog starts to be rendered");
|
||||||
gettext("Clouds");
|
gettext("Clouds");
|
||||||
gettext("Clouds");
|
gettext("Clouds");
|
||||||
gettext("Clouds are a client side effect.");
|
gettext("Clouds are a client-side effect.");
|
||||||
gettext("3D clouds");
|
gettext("3D clouds");
|
||||||
gettext("Use 3D cloud look instead of flat.");
|
gettext("Use 3D cloud look instead of flat.");
|
||||||
gettext("Filtering and Antialiasing");
|
gettext("Filtering and Antialiasing");
|
||||||
gettext("Mipmapping");
|
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("Bilinear filtering");
|
||||||
gettext("Use bilinear filtering when scaling textures down.");
|
gettext("Use bilinear filtering when scaling textures down.");
|
||||||
gettext("Trilinear filtering");
|
gettext("Trilinear filtering");
|
||||||
@ -145,7 +145,7 @@ fake_function() {
|
|||||||
gettext("Antialiasing method");
|
gettext("Antialiasing method");
|
||||||
gettext("Select the antialiasing method to apply.\n\n* None - No antialiasing (default)\n\n* FSAA - Hardware-provided full-screen antialiasing (incompatible with shaders)\nA.K.A multi-sample antialiasing (MSAA)\nSmoothens out block edges but does not affect the insides of textures.\nA restart is required to change this option.\n\n* FXAA - Fast approximate antialiasing (requires shaders)\nApplies a post-processing filter to detect and smoothen high-contrast edges.\nProvides balance between speed and image quality.\n\n* SSAA - Super-sampling antialiasing (requires shaders)\nRenders higher-resolution image of the scene, then scales down to reduce\nthe aliasing effects. This is the slowest and the most accurate method.");
|
gettext("Select the antialiasing method to apply.\n\n* None - No antialiasing (default)\n\n* FSAA - Hardware-provided full-screen antialiasing (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("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 Culling");
|
||||||
gettext("Occlusion Culler");
|
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.");
|
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("Colored shadows");
|
||||||
gettext("Enable colored shadows.\nOn true translucent nodes cast colored shadows. This is expensive.");
|
gettext("Enable colored shadows.\nOn true translucent nodes cast colored shadows. This is expensive.");
|
||||||
gettext("Map shadows update frames");
|
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("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("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");
|
gettext("Sky Body Orbit Tilt");
|
||||||
@ -216,7 +216,7 @@ fake_function() {
|
|||||||
gettext("User Interfaces");
|
gettext("User Interfaces");
|
||||||
gettext("Language");
|
gettext("Language");
|
||||||
gettext("Set the language. Leave empty to use the system language.\nA restart is required after changing this.");
|
gettext("Set the language. Leave empty to use the system language.\nA restart is required after changing this.");
|
||||||
gettext("GUIs");
|
gettext("GUI");
|
||||||
gettext("GUI scaling");
|
gettext("GUI scaling");
|
||||||
gettext("Scale GUI by a user specified value.\nUse a nearest-neighbor-anti-alias filter to scale the GUI.\nThis will smooth over some of the rough edges, and blend\npixels when scaling down, at the cost of blurring some\nedge pixels when images are scaled by non-integer sizes.");
|
gettext("Scale GUI by a user specified value.\nUse a nearest-neighbor-anti-alias filter to scale the GUI.\nThis will smooth over some of the rough edges, and blend\npixels when scaling down, at the cost of blurring some\nedge pixels when images are scaled by non-integer sizes.");
|
||||||
gettext("Inventory items animations");
|
gettext("Inventory items animations");
|
||||||
@ -294,7 +294,7 @@ fake_function() {
|
|||||||
gettext("Message of the day displayed to players connecting.");
|
gettext("Message of the day displayed to players connecting.");
|
||||||
gettext("Maximum users");
|
gettext("Maximum users");
|
||||||
gettext("Maximum number of players that can be connected simultaneously.");
|
gettext("Maximum number of players that can be connected simultaneously.");
|
||||||
gettext("Static spawnpoint");
|
gettext("Static spawn point");
|
||||||
gettext("If this is set, players will always (re)spawn at the given position.");
|
gettext("If this is set, players will always (re)spawn at the given position.");
|
||||||
gettext("Networking");
|
gettext("Networking");
|
||||||
gettext("Server port");
|
gettext("Server port");
|
||||||
@ -323,7 +323,7 @@ fake_function() {
|
|||||||
gettext("Client-side Modding");
|
gettext("Client-side Modding");
|
||||||
gettext("Client side modding restrictions");
|
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("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("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("Chat");
|
||||||
gettext("Strip color codes");
|
gettext("Strip color codes");
|
||||||
@ -331,7 +331,7 @@ fake_function() {
|
|||||||
gettext("Chat message max length");
|
gettext("Chat message max length");
|
||||||
gettext("Set the maximum length of a chat message (in characters) sent by clients.");
|
gettext("Set the maximum length of a chat message (in characters) sent by clients.");
|
||||||
gettext("Chat message count limit");
|
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("Chat message kick threshold");
|
||||||
gettext("Kick players who sent more than X messages per 10 seconds.");
|
gettext("Kick players who sent more than X messages per 10 seconds.");
|
||||||
gettext("Server Gameplay");
|
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("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("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("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("Heat noise");
|
||||||
gettext("Temperature variation for biomes.");
|
gettext("Temperature variation for biomes.");
|
||||||
gettext("Heat blend noise");
|
gettext("Heat blend noise");
|
||||||
@ -484,7 +484,7 @@ fake_function() {
|
|||||||
gettext("Floatland density");
|
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("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("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("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("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");
|
gettext("Large cave depth");
|
||||||
@ -712,7 +712,7 @@ fake_function() {
|
|||||||
gettext("Mapgen Valleys specific flags");
|
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("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("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("Large cave depth");
|
||||||
gettext("Depth below which you'll find large caves.");
|
gettext("Depth below which you'll find large caves.");
|
||||||
gettext("Small cave minimum number");
|
gettext("Small cave minimum number");
|
||||||
@ -747,7 +747,7 @@ fake_function() {
|
|||||||
gettext("Cave noise #2");
|
gettext("Cave noise #2");
|
||||||
gettext("Second of two 3D noises that together define tunnels.");
|
gettext("Second of two 3D noises that together define tunnels.");
|
||||||
gettext("Filler depth");
|
gettext("Filler depth");
|
||||||
gettext("The depth of dirt or other biome filler node.");
|
gettext("Variation of biome filler depth.");
|
||||||
gettext("Cavern noise");
|
gettext("Cavern noise");
|
||||||
gettext("3D noise defining giant caverns.");
|
gettext("3D noise defining giant caverns.");
|
||||||
gettext("River noise");
|
gettext("River noise");
|
||||||
@ -796,7 +796,7 @@ fake_function() {
|
|||||||
gettext("Default report format");
|
gettext("Default report format");
|
||||||
gettext("The default format in which profiles are being saved,\nwhen calling `/profiler save [format]` without format.");
|
gettext("The default format in which profiles are being saved,\nwhen calling `/profiler save [format]` without format.");
|
||||||
gettext("Report path");
|
gettext("Report path");
|
||||||
gettext("The file path relative to your worldpath in which profiles will be saved to.");
|
gettext("The file path relative to your world path in which profiles will be saved to.");
|
||||||
gettext("Entity methods");
|
gettext("Entity methods");
|
||||||
gettext("Instrument the methods of entities on registration.");
|
gettext("Instrument the methods of entities on registration.");
|
||||||
gettext("Active Block Modifiers");
|
gettext("Active Block Modifiers");
|
||||||
@ -811,7 +811,7 @@ fake_function() {
|
|||||||
gettext("Instrument builtin.\nThis is usually only needed by core/builtin contributors");
|
gettext("Instrument builtin.\nThis is usually only needed by core/builtin contributors");
|
||||||
gettext("Profiler");
|
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("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("Engine profiling data print interval");
|
||||||
gettext("Print the engine's profiling data in regular intervals (in seconds).\n0 = disable. Useful for developers.");
|
gettext("Print the engine's profiling data in regular intervals (in seconds).\n0 = disable. Useful for developers.");
|
||||||
gettext("Advanced");
|
gettext("Advanced");
|
||||||
@ -891,8 +891,8 @@ fake_function() {
|
|||||||
gettext("Networking");
|
gettext("Networking");
|
||||||
gettext("Prometheus listener address");
|
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("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 outgoing 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.\n0 to disable queueing and -1 to make the queue size unlimited.");
|
||||||
gettext("Mapblock unload timeout");
|
gettext("Mapblock unload timeout");
|
||||||
gettext("Timeout for client to remove unused map data from memory, in seconds.");
|
gettext("Timeout for client to remove unused map data from memory, in seconds.");
|
||||||
gettext("Mapblock limit");
|
gettext("Mapblock limit");
|
||||||
@ -957,11 +957,11 @@ fake_function() {
|
|||||||
gettext("Liquid update interval in seconds.");
|
gettext("Liquid update interval in seconds.");
|
||||||
gettext("Block send optimize distance");
|
gettext("Block send optimize distance");
|
||||||
gettext("At this distance the server will aggressively optimize which blocks are sent to\nclients.\nSmall values potentially improve performance a lot, at the expense of visible\nrendering glitches (some blocks will not be rendered under water and in caves,\nas well as sometimes on land).\nSetting this to a value greater than max_block_send_distance disables this\noptimization.\nStated in mapblocks (16 nodes).");
|
gettext("At this distance the server will aggressively optimize which blocks are sent to\nclients.\nSmall values potentially improve performance a lot, at the expense of visible\nrendering glitches (some blocks 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("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("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("Mapgen");
|
||||||
gettext("Chunk size");
|
gettext("Chunk size");
|
||||||
gettext("Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).\nWARNING!: There is no benefit, and there are several dangers, in\nincreasing this value above 5.\nReducing this value increases cave and dungeon density.\nAltering this value is for special usage, leaving it unchanged is\nrecommended.");
|
gettext("Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).\nWARNING: There is no benefit, and there are several dangers, in\nincreasing this value above 5.\nReducing this value increases cave and dungeon density.\nAltering this value is for special usage, leaving it unchanged is\nrecommended.");
|
||||||
gettext("Mapgen debug");
|
gettext("Mapgen debug");
|
||||||
gettext("Dump the mapgen debug information.");
|
gettext("Dump the mapgen debug information.");
|
||||||
gettext("Absolute limit of queued blocks to emerge");
|
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("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("cURL file download timeout");
|
||||||
gettext("Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.");
|
gettext("Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.");
|
||||||
gettext("Misc");
|
gettext("Miscellaneous");
|
||||||
gettext("DPI");
|
gettext("DPI");
|
||||||
gettext("Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.");
|
gettext("Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.");
|
||||||
gettext("Display Density Scaling Factor");
|
gettext("Display Density Scaling Factor");
|
||||||
@ -1011,45 +1011,4 @@ fake_function() {
|
|||||||
gettext("The dead zone of the joystick");
|
gettext("The dead zone of the joystick");
|
||||||
gettext("Joystick frustum sensitivity");
|
gettext("Joystick frustum sensitivity");
|
||||||
gettext("The sensitivity of the joystick axes for moving the\nin-game view frustum around.");
|
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