Merge branch 'dragonfire/master' into waspsaliva

This merge removes some redundant-looking code that was apparently
included in DFC upstream already.

This merge also reverts some whitespace & reformatting changes in the
`src/` directory so that a `git diff dragonfire/master` contains only
the essential differences.
This commit is contained in:
Schmappie Eldress 2021-08-17 01:48:45 -05:00
commit 7871b44824
466 changed files with 40002 additions and 44846 deletions

View File

@ -29,3 +29,4 @@ AlignAfterOpenBracket: DontAlign
ContinuationIndentWidth: 16 ContinuationIndentWidth: 16
ConstructorInitializerIndentWidth: 16 ConstructorInitializerIndentWidth: 16
BreakConstructorInitializers: AfterColon BreakConstructorInitializers: AfterColon
AlwaysBreakTemplateDeclarations: Yes

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
./cmake-build-*
./build/*
./cache/*
Dockerfile

View File

@ -70,7 +70,9 @@ Feature requests are welcome but take a moment to see if your idea follows the r
## Translations ## Translations
Translations of Minetest are performed using Weblate. You can access the project page with a list of current languages [here](https://hosted.weblate.org/projects/minetest/minetest/). The core translations of Minetest are performed using Weblate. You can access the project page with a list of current languages [here](https://hosted.weblate.org/projects/minetest/minetest/).
Builtin (the component which contains things like server messages, chat command descriptions, privilege descriptions) is translated separately; it needs to be translated by editing a `.tr` text file. See [Translation](https://dev.minetest.net/Translation) for more information.
## Donations ## Donations

View File

@ -13,6 +13,8 @@ on:
- 'util/buildbot/**' - 'util/buildbot/**'
- 'util/ci/**' - 'util/ci/**'
- '.github/workflows/**.yml' - '.github/workflows/**.yml'
- 'Dockerfile'
- '.dockerignore'
pull_request: pull_request:
paths: paths:
- 'lib/**.[ch]' - 'lib/**.[ch]'
@ -24,6 +26,8 @@ on:
- 'util/buildbot/**' - 'util/buildbot/**'
- 'util/ci/**' - 'util/ci/**'
- '.github/workflows/**.yml' - '.github/workflows/**.yml'
- 'Dockerfile'
- '.dockerignore'
jobs: jobs:
# This is our minor gcc compiler # This is our minor gcc compiler
@ -33,9 +37,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install g++-6 gcc-6 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps g++-6
- name: Build - name: Build
run: | run: |
@ -55,9 +58,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install g++-8 gcc-8 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps g++-8
- name: Build - name: Build
run: | run: |
@ -77,9 +79,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-3.9 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps clang-3.9 gdb
- name: Build - name: Build
run: | run: |
@ -88,10 +89,14 @@ jobs:
CC: clang-3.9 CC: clang-3.9
CXX: clang++-3.9 CXX: clang++-3.9
- name: Test - name: Unittest
run: | run: |
./bin/minetest --run-unittests ./bin/minetest --run-unittests
- name: Integration test
run: |
./util/test_multiplayer.sh
# This is the current clang version # This is the current clang version
clang_9: clang_9:
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04
@ -99,11 +104,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-9 valgrind -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps clang-9 valgrind libluajit-5.1-dev
env:
WITH_LUAJIT: 1
- name: Build - name: Build
run: | run: |
@ -111,6 +113,7 @@ jobs:
env: env:
CC: clang-9 CC: clang-9
CXX: clang++-9 CXX: clang++-9
CMAKE_FLAGS: "-DREQUIRE_LUAJIT=1"
- name: Test - name: Test
run: | run: |
@ -128,9 +131,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps --old-irr clang-9
- name: Build prometheus-cpp - name: Build prometheus-cpp
run: | run: |
@ -156,9 +158,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps clang-9
- name: Build - name: Build
run: | run: |
@ -188,7 +189,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install compiler - name: Install compiler
run: | run: |
sudo apt-get install gettext -qyy sudo apt-get update -q && sudo apt-get install gettext -qyy
wget http://minetest.kitsunemimi.pw/mingw-w64-i686_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz wget http://minetest.kitsunemimi.pw/mingw-w64-i686_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz
sudo tar -xaf mingw.tar.xz -C /usr sudo tar -xaf mingw.tar.xz -C /usr
@ -206,7 +207,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install compiler - name: Install compiler
run: | run: |
sudo apt-get install gettext -qyy sudo apt-get update -q && sudo apt-get install gettext -qyy
wget http://minetest.kitsunemimi.pw/mingw-w64-x86_64_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz wget http://minetest.kitsunemimi.pw/mingw-w64-x86_64_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz
sudo tar -xaf mingw.tar.xz -C /usr sudo tar -xaf mingw.tar.xz -C /usr
@ -219,7 +220,10 @@ jobs:
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
#### Disabled due to Irrlicht switch
if: false
#### Disabled due to Irrlicht switch
env: env:
VCPKG_VERSION: 0bf3923f9fab4001c00f0f429682a0853b5749e0 VCPKG_VERSION: 0bf3923f9fab4001c00f0f429682a0853b5749e0
# 2020.11 # 2020.11

View File

@ -24,20 +24,21 @@ on:
- '.github/workflows/**.yml' - '.github/workflows/**.yml'
jobs: jobs:
clang_format:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Install clang-format
run: |
sudo apt-get install clang-format-9 -qyy
- name: Run clang-format # clang_format:
run: | # runs-on: ubuntu-18.04
source ./util/ci/lint.sh # steps:
perform_lint # - uses: actions/checkout@v2
env: # - name: Install clang-format
CLANG_FORMAT: clang-format-9 # run: |
# sudo apt-get install clang-format-9 -qyy
#
# - name: Run clang-format
# run: |
# source ./util/ci/clang-format.sh
# check_format
# env:
# CLANG_FORMAT: clang-format-9
clang_tidy: clang_tidy:
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04

3
.gitignore vendored
View File

@ -85,8 +85,7 @@ src/test_config.h
src/cmake_config.h src/cmake_config.h
src/cmake_config_githash.h src/cmake_config_githash.h
src/unittest/test_world/world.mt src/unittest/test_world/world.mt
src/lua/build/ /locale/
locale/
.directory .directory
*.cbp *.cbp
*.layout *.layout

View File

@ -9,40 +9,48 @@ stages:
- deploy - deploy
variables: variables:
IRRLICHT_TAG: "1.9.0mt1"
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git" 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:
stage: build stage: build
before_script:
- apt-get update
- apt-get -y install build-essential git cmake libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libleveldb-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
script: script:
- git clone https://github.com/minetest/irrlicht -b $IRRLICHT_TAG
- cd irrlicht
- cmake . -DBUILD_SHARED_LIBS=OFF
- make -j2
- cd ..
- mkdir cmakebuild - mkdir cmakebuild
- mkdir -p artifact/minetest/usr/
- cd cmakebuild - cd cmakebuild
- cmake -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE .. - cmake -DIRRLICHT_LIBRARY=$PWD/../irrlicht/lib/Linux/libIrrlichtMt.a -DIRRLICHT_INCLUDE_DIR=$PWD/../irrlicht/include -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE ..
- make -j2 - make -j2
- make install - make install
artifacts: artifacts:
when: on_success when: on_success
expire_in: 2h expire_in: 1h
paths: paths:
- artifact/* - artifact/*
.debpkg_template: .debpkg_template:
stage: package stage: package
before_script: before_script:
- apt-get update -y - apt-get update
- apt-get install -y git - apt-get install -y git
- mkdir -p build/deb/minetest/DEBIAN/ - mkdir -p build/deb/minetest/DEBIAN/
- cp misc/debpkg-control build/deb/minetest/DEBIAN/control - cp misc/debpkg-control build/deb/minetest/DEBIAN/control
- cp -Rp artifact/minetest/usr build/deb/minetest/ - cp -a artifact/minetest/usr build/deb/minetest/
script: script:
- git clone $MINETEST_GAME_REPO build/deb/minetest/usr/share/minetest/games/minetest_game - git clone $MINETEST_GAME_REPO build/deb/minetest/usr/share/minetest/games/minetest_game
- rm -Rf build/deb/minetest/usr/share/minetest/games/minetest/.git - rm -rf build/deb/minetest/usr/share/minetest/games/minetest/.git
- sed -i 's/DATEPLACEHOLDER/'$(date +%y.%m.%d)'/g' build/deb/minetest/DEBIAN/control - sed -i 's/DATEPLACEHOLDER/'$(date +%y.%m.%d)'/g' build/deb/minetest/DEBIAN/control
- sed -i 's/JPEG_PLACEHOLDER/'$JPEG_PKG'/g' build/deb/minetest/DEBIAN/control
- sed -i 's/LEVELDB_PLACEHOLDER/'$LEVELDB_PKG'/g' build/deb/minetest/DEBIAN/control - sed -i 's/LEVELDB_PLACEHOLDER/'$LEVELDB_PKG'/g' build/deb/minetest/DEBIAN/control
- cd build/deb/ && dpkg-deb -b minetest/ && mv minetest.deb ../../ - cd build/deb/ && dpkg-deb -b minetest/ && mv minetest.deb ../../
artifacts: artifacts:
when: on_success
expire_in: 90 day expire_in: 90 day
paths: paths:
- ./*.deb - ./*.deb
@ -50,94 +58,57 @@ variables:
.debpkg_install: .debpkg_install:
stage: deploy stage: deploy
before_script: before_script:
- apt-get update -y - apt-get update
- apt-get install -y libc6 libcurl3-gnutls libfreetype6 libirrlicht1.8 $LEVELDB_PKG liblua5.1-0 libluajit-5.1-2 libopenal1 libstdc++6 libvorbisfile3 libx11-6 zlib1g
script: script:
- dpkg -i ./*.deb - apt-get install -y ./*.deb
- minetest --version
## ##
## Debian ## Debian
## ##
# Jessie
build:debian-8:
extends: .build_template
image: debian:8
before_script:
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu trusty main" > /etc/apt/sources.list.d/uptodate-toolchain.list
- apt-key adv --keyserver keyserver.ubuntu.com --recv BA9EF27F
- apt-get update -y
- apt-get -y install build-essential gcc-6 g++-6 libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
variables:
CC: gcc-6
CXX: g++-6
package:debian-8:
extends: .debpkg_template
image: debian:8
dependencies:
- build:debian-8
variables:
LEVELDB_PKG: libleveldb1
deploy:debian-8:
extends: .debpkg_install
image: debian:8
dependencies:
- package:debian-8
variables:
LEVELDB_PKG: libleveldb1
# Stretch # Stretch
build:debian-9: build:debian-9:
extends: .build_template extends: .build_template
image: debian:9 image: debian:9
before_script:
- apt-get update -y
- apt-get -y install build-essential libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
package:debian-9: package:debian-9:
extends: .debpkg_template extends: .debpkg_template
image: debian:9 image: debian:9
dependencies: needs:
- build:debian-9 - build:debian-9
variables: variables:
LEVELDB_PKG: libleveldb1v5 LEVELDB_PKG: libleveldb1v5
JPEG_PKG: libjpeg62-turbo
deploy:debian-9: deploy:debian-9:
extends: .debpkg_install extends: .debpkg_install
image: debian:9 image: debian:9
dependencies: needs:
- package:debian-9 - package:debian-9
variables:
LEVELDB_PKG: libleveldb1v5
# Stretch # Buster
build:debian-10: build:debian-10:
extends: .build_template extends: .build_template
image: debian:10 image: debian:10
before_script:
- apt-get update -y
- apt-get -y install build-essential libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
package:debian-10: package:debian-10:
extends: .debpkg_template extends: .debpkg_template
image: debian:10 image: debian:10
dependencies: needs:
- build:debian-10 - build:debian-10
variables: variables:
LEVELDB_PKG: libleveldb1d LEVELDB_PKG: libleveldb1d
JPEG_PKG: libjpeg62-turbo
deploy:debian-10: deploy:debian-10:
extends: .debpkg_install extends: .debpkg_install
image: debian:10 image: debian:10
dependencies: needs:
- package:debian-10 - package:debian-10
variables:
LEVELDB_PKG: libleveldb1d
## ##
## Ubuntu ## Ubuntu
## ##
@ -147,134 +118,120 @@ deploy:debian-10:
build:ubuntu-16.04: build:ubuntu-16.04:
extends: .build_template extends: .build_template
image: ubuntu:xenial image: ubuntu:xenial
before_script:
- apt-get update -y
- apt-get -y install build-essential libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
package:ubuntu-16.04: package:ubuntu-16.04:
extends: .debpkg_template extends: .debpkg_template
image: ubuntu:xenial image: ubuntu:xenial
dependencies: needs:
- build:ubuntu-16.04 - build:ubuntu-16.04
variables: variables:
LEVELDB_PKG: libleveldb1v5 LEVELDB_PKG: libleveldb1v5
JPEG_PKG: libjpeg-turbo8
deploy:ubuntu-16.04: deploy:ubuntu-16.04:
extends: .debpkg_install extends: .debpkg_install
image: ubuntu:xenial image: ubuntu:xenial
dependencies: needs:
- package:ubuntu-16.04 - package:ubuntu-16.04
variables:
LEVELDB_PKG: libleveldb1v5
# Bionic # Bionic
build:ubuntu-18.04: build:ubuntu-18.04:
extends: .build_template extends: .build_template
image: ubuntu:bionic image: ubuntu:bionic
before_script:
- apt-get update -y
- apt-get -y install build-essential libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
package:ubuntu-18.04: package:ubuntu-18.04:
extends: .debpkg_template extends: .debpkg_template
image: ubuntu:bionic image: ubuntu:bionic
dependencies: needs:
- build:ubuntu-18.04 - build:ubuntu-18.04
variables: variables:
LEVELDB_PKG: libleveldb1v5 LEVELDB_PKG: libleveldb1v5
JPEG_PKG: libjpeg-turbo8
deploy:ubuntu-18.04: deploy:ubuntu-18.04:
extends: .debpkg_install extends: .debpkg_install
image: ubuntu:bionic image: ubuntu:bionic
dependencies: needs:
- package:ubuntu-18.04 - package:ubuntu-18.04
variables:
LEVELDB_PKG: libleveldb1v5
## ##
## Fedora ## Fedora
## ##
# Do we need to support this old version ? # Fedora 28 <-> RHEL 8
build:fedora-24: build:fedora-28:
extends: .build_template extends: .build_template
image: fedora:24 image: fedora:28
before_script: before_script:
- dnf -y install make automake gcc gcc-c++ kernel-devel cmake libcurl* openal* libvorbis* libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel irrlicht-devel bzip2-libs gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel doxygen spatialindex-devel bzip2-devel - dnf -y install make git gcc gcc-c++ kernel-devel cmake libjpeg-devel libpng-devel libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel
## ##
## Mingw for Windows ## MinGW for Windows
## ##
.generic_win_template: .generic_win_template:
image: ubuntu:bionic image: ubuntu:focal
before_script: before_script:
- apt-get update -y - apt-get update
- apt-get install -y wget xz-utils unzip git cmake gettext - DEBIAN_FRONTEND=noninteractive apt-get install -y wget xz-utils unzip git cmake gettext
- wget -q http://minetest.kitsunemimi.pw/mingw-w64-${WIN_ARCH}_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz - wget -nv http://minetest.kitsunemimi.pw/mingw-w64-${WIN_ARCH}_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz
- tar -xaf mingw.tar.xz -C /usr - tar -xaf mingw.tar.xz -C /usr
.build_win_template: .build_win_template:
extends: .generic_win_template extends: .generic_win_template
stage: build stage: build
artifacts: artifacts:
when: on_success expire_in: 1h
expire_in: 2h
paths: paths:
- build/* - build/build/*.zip
.package_win_template: .package_win_template:
extends: .generic_win_template extends: .generic_win_template
stage: package stage: package
script: script:
- cd build/minetest/_build - unzip build/build/*.zip
- make package - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libgcc*.dll minetest-*-win*/bin/
- cd ../../../ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libstdc++*.dll minetest-*-win*/bin/
- mkdir minetest-win-${WIN_ARCH} - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libwinpthread*.dll minetest-*-win*/bin/
- unzip build/minetest/_build/minetest-*-win*.zip -d minetest-win-${WIN_ARCH}
- cp /usr/${WIN_ARCH}-w64-mingw32/bin/libgcc*.dll minetest-win-${WIN_ARCH}/minetest-*-win*/bin
- cp /usr/${WIN_ARCH}-w64-mingw32/bin/libstdc++*.dll minetest-win-${WIN_ARCH}/minetest-*-win*/bin
- cp /usr/${WIN_ARCH}-w64-mingw32/bin/libwinpthread*.dll minetest-win-${WIN_ARCH}/minetest-*-win*/bin
artifacts: artifacts:
when: on_success
expire_in: 90 day expire_in: 90 day
paths: paths:
- minetest-win-*/* - minetest-*-win*/*
build:win32: build:win32:
extends: .build_win_template extends: .build_win_template
script: script:
- ./util/buildbot/buildwin32.sh build - EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin32.sh build
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "i686" WIN_ARCH: "i686"
package:win32: package:win32:
extends: .package_win_template extends: .package_win_template
dependencies: needs:
- build:win32 - build:win32
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "i686" WIN_ARCH: "i686"
build:win64: build:win64:
extends: .build_win_template extends: .build_win_template
script: script:
- ./util/buildbot/buildwin64.sh build - EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin64.sh build
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "x86_64" WIN_ARCH: "x86_64"
package:win64: package:win64:
extends: .package_win_template extends: .package_win_template
dependencies: needs:
- build:win64 - build:win64
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "x86_64" WIN_ARCH: "x86_64"
##
## Docker
##
package:docker: package:docker:
stage: package stage: package
image: docker:stable image: docker:stable
@ -288,6 +245,10 @@ package:docker:
- docker push ${CONTAINER_IMAGE}/server:$CI_COMMIT_REF_NAME - docker push ${CONTAINER_IMAGE}/server:$CI_COMMIT_REF_NAME
- docker push ${CONTAINER_IMAGE}/server:latest - docker push ${CONTAINER_IMAGE}/server:latest
##
## Gitlab Pages (Lua API documentation)
##
pages: pages:
stage: deploy stage: deploy
image: python:3.8 image: python:3.8
@ -303,10 +264,14 @@ pages:
only: only:
- master - master
##
## AppImage
##
package:appimage-client: package:appimage-client:
stage: package stage: package
image: appimagecrafters/appimage-builder image: appimagecrafters/appimage-builder
dependencies: needs:
- build:ubuntu-18.04 - build:ubuntu-18.04
before_script: before_script:
- apt-get update -y - apt-get update -y
@ -315,16 +280,15 @@ package:appimage-client:
- mkdir AppDir - mkdir AppDir
- cp -a artifact/minetest/usr/ AppDir/usr/ - cp -a artifact/minetest/usr/ AppDir/usr/
- rm AppDir/usr/bin/minetestserver - rm AppDir/usr/bin/minetestserver
- cp -R clientmods AppDir/usr/share/minetest - cp -a clientmods AppDir/usr/share/minetest
script: script:
- git clone $MINETEST_GAME_REPO AppDir/usr/share/minetest/games/minetest_game - git clone $MINETEST_GAME_REPO AppDir/usr/share/minetest/games/minetest_game
- rm -Rf AppDir/usr/share/minetest/games/minetest/.git - rm -rf AppDir/usr/share/minetest/games/minetest/.git
- export VERSION=$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - export VERSION=$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA
# 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
- appimage-builder --skip-test - appimage-builder --skip-test
artifacts: artifacts:
when: on_success
expire_in: 90 day expire_in: 90 day
paths: paths:
- ./*.AppImage - ./*.AppImage

View File

@ -19,8 +19,8 @@ read_globals = {
"Settings", "Settings",
string = {fields = {"split", "trim"}}, string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn", "indexof", "insert_all"}}, table = {fields = {"copy", "getn", "indexof", "insert_all", "combine"}},
math = {fields = {"hypot"}}, math = {fields = {"hypot", "round"}},
} }
globals = { globals = {

View File

@ -1,33 +1,67 @@
# Documentation: https://git-scm.com/docs/git-check-mailmap#_mapping_authors
0gb.us <0gb.us@0gb.us> <us_0gb@laptop-0gb-us.0gb.us> 0gb.us <0gb.us@0gb.us> <us_0gb@laptop-0gb-us.0gb.us>
Calinou <calinou9999@gmail.com> <calinou9999spam@gmail.com> Calinou <calinou@opmbx.org> <calinou9999@gmail.com>
Perttu Ahola <celeron55@gmail.com> celeron55 <celeron55@gmail.com> Calinou <calinou@opmbx.org> <calinou9999spam@gmail.com>
Perttu Ahola <celeron55@gmail.com>
Perttu Ahola <celeron55@gmail.com> celeron55 <celeron55@armada.(none)> Perttu Ahola <celeron55@gmail.com> celeron55 <celeron55@armada.(none)>
Craig Robbins <kde.psych@gmail.com> <crobbins@localhost.localdomain> Zeno- <kde.psych@gmail.com>
Zeno- <kde.psych@gmail.com> <crobbins@localhost.localdomain>
Diego Martínez <kaeza@users.sf.net>
Diego Martínez <kaeza@users.sf.net> <lkaezadl3@gmail.com> Diego Martínez <kaeza@users.sf.net> <lkaezadl3@gmail.com>
Ilya Zhuravlev <zhuravlevilya@ya.ru>
Ilya Zhuravlev <zhuravlevilya@ya.ru> <whatever@xyz.is> Ilya Zhuravlev <zhuravlevilya@ya.ru> <whatever@xyz.is>
kwolekr <kwolekr@minetest.net> <mirrorisim@gmail.com> kwolekr <kwolekr@minetest.net> <mirrorisim@gmail.com>
PilzAdam <pilzadam@minetest.net> PilzAdam <adam-k@outlook.com> PilzAdam <pilzadam@minetest.net> <adam-k@outlook.com>
PilzAdam <pilzadam@minetest.net> Pilz Adam <PilzAdam@gmx.de> PilzAdam <pilzadam@minetest.net> <PilzAdam@gmx.de>
PilzAdam <pilzadam@minetest.net> PilzAdam <PilzAdam@gmx.de>
proller <proller@github.com> <proler@github.com> proller <proller@github.com> <proler@github.com>
proller <proller@github.com> <proler@gmail.com> proller <proller@github.com> <proler@gmail.com>
RealBadAngel <maciej.kasatkin@o2.pl> <mk@realbadangel.pl> RealBadAngel <maciej.kasatkin@o2.pl> <mk@realbadangel.pl>
RealBadAngel <maciej.kasatkin@o2.pl> <maciej.kasatkin@yahoo.com> RealBadAngel <maciej.kasatkin@o2.pl> <maciej.kasatkin@yahoo.com>
Selat <LongExampleTestName@gmail.com> <LongExampletestName@gmail.com> Selat <LongExampleTestName@gmail.com> <LongExampletestName@gmail.com>
ShadowNinja <shadowninja@minetest.net> ShadowNinja <noreply@gmail.com> ShadowNinja <shadowninja@minetest.net> ShadowNinja <noreply@gmail.com>
Shen Zheyu <arsdragonfly@gmail.com> arsdragonfly <arsdragonfly@gmail.com> Esteban I. Ruiz Moreno <exio4.com@gmail.com>
Pavel Elagin <elagin.pasha@gmail.com> elagin <elagin.pasha@gmail.com> Esteban I. Ruiz Moreno <exio4.com@gmail.com> <me@exio4.xyz>
Esteban I. Ruiz Moreno <exio4.com@gmail.com> Esteban I. RM <exio4.com@gmail.com> Lord James <neftali_dtctv@hotmail.com>
manuel duarte <ffrogger0@yahoo.com> manuel joaquim <ffrogger0@yahoo.com> BlockMen <nmuelll@web.de>
manuel duarte <ffrogger0@yahoo.com> sweetbomber <ffrogger _zero_ at yahoo dot com> sfan5 <sfan5@live.de>
Diego Martínez <kaeza@users.sf.net> kaeza <kaeza@users.sf.net> DannyDark <the_skeleton_of_a_child@yahoo.co.uk>
Diego Martínez <kaeza@users.sf.net> Diego Martinez <kaeza@users.sf.net> Ilya Pavlov <TTChangeTheWorld@gmail.com>
Lord James <neftali_dtctv@hotmail.com> Lord89James <neftali_dtctv@hotmail.com>
BlockMen <nmuelll@web.de> Block Men <nmuelll@web.de>
sfan5 <sfan5@live.de> Sfan5 <sfan5@live.de>
DannyDark <the_skeleton_of_a_child@yahoo.co.uk> dannydark <the_skeleton_of_a_child@yahoo.co.uk>
Ilya Pavlov <TTChangeTheWorld@gmail.com> Ilya <TTChangeTheWorld@gmail.com>
Ilya Zhuravlev <zhuravlevilya@ya.ru> xyzz <zhuravlevilya@ya.ru>
sapier <Sapier at GMX dot net> sapier <sapier AT gmx DOT net> sapier <Sapier at GMX dot net> sapier <sapier AT gmx DOT net>
sapier <Sapier at GMX dot net> sapier <sapier at gmx dot net> sapier <Sapier at GMX dot net> sapier <sapier at gmx dot net>
SmallJoker <SmallJoker@users.noreply.github.com> <mk939@ymail.com>
Loïc Blot <nerzhul@users.noreply.github.com>
Loïc Blot <nerzhul@users.noreply.github.com> <loic.blot@unix-experience.fr>
numzero <numzer0@yandex.ru> Vitaliy <numzer0@yandex.ru>
numzero <numzer0@yandex.ru> <silverunicorn2011@yandex.ru>
Jean-Patrick Guerrero <kilbith@users.noreply.github.com>
Jean-Patrick Guerrero <kilbith@users.noreply.github.com> <jeanpatrick.guerrero@gmail.com>
HybridDog <3192173+HybridDog@users.noreply.github.com> <ovvv@web.de>
srfqi <muhammadrifqipriyosusanto@gmail.com>
Dániel Juhász <juhdanad@gmail.com>
rubenwardy <rw@rubenwardy.com>
rubenwardy <rw@rubenwardy.com> <rubenwardy@gmail.com>
Paul Ouellette <oue.paul18@gmail.com>
Vanessa Dannenberg <vanessa.e.dannenberg@gmail.com> <vanessaezekowitz@gmail.com>
ClobberXD <ClobberXD@gmail.com>
ClobberXD <ClobberXD@gmail.com> <ClobberXD@protonmail.com>
ClobberXD <ClobberXD@gmail.com> <36130650+ClobberXD@users.noreply.github.com>
Auke Kok <sofar+github@foo-projects.org>
Auke Kok <sofar+github@foo-projects.org> <sofar@foo-projects.org>
Desour <vorunbekannt75@web.de>
Nathanaël Courant <Ekdohibs@users.noreply.github.com> <nathanael.courant@laposte.net>
Ezhh <owlecho@live.com>
paramat <paramat@users.noreply.github.com>
paramat <paramat@users.noreply.github.com> <mat.gregory@virginmedia.com>
lhofhansl <lhofhansl@yahoo.com> <larsh@apache.org>
red-001 <red-001@outlook.ie> <red-001@openmailbox.org>
Wuzzy <wuzzy2@mail.ru> <Wuzzy2@mail.ru>
Wuzzy <wuzzy2@mail.ru> <almikes@aol.com>
Jordach <jordach.snelling@gmail.com>
MoNTE48 <MoNTE48@mail.ua>
v-rob <robinsonvincent89@gmail.com>
v-rob <robinsonvincent89@gmail.com> <31123645+v-rob@users.noreply.github.com>
EvidenceB <49488517+EvidenceBKidscode@users.noreply.github.com>
gregorycu <gregory.currie@gmail.com>
Rogier <rogier777@gmail.com>
Rogier <rogier777@gmail.com> <Rogier-5@users.noreply.github.com>

View File

@ -1,24 +1,18 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 3.5)
if(${CMAKE_VERSION} STREQUAL "2.8.2")
# Bug http://vtk.org/Bug/view.php?id=11020
message(WARNING "CMake/CPack version 2.8.2 will not create working .deb packages!")
endif()
# This can be read from ${PROJECT_NAME} after project() is called # This can be read from ${PROJECT_NAME} after project() is called
project(minetest) project(minetest)
set(PROJECT_NAME_CAPITALIZED "waspsaliva") set(PROJECT_NAME_CAPITALIZED "waspsaliva")
# Works only for cmake 3.1 and greater
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(GCC_MINIMUM_VERSION "4.8") set(GCC_MINIMUM_VERSION "4.8")
set(CLANG_MINIMUM_VERSION "3.4") set(CLANG_MINIMUM_VERSION "3.4")
# Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing # Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
set(VERSION_MAJOR 5) set(VERSION_MAJOR 5)
set(VERSION_MINOR 4) set(VERSION_MINOR 5)
set(VERSION_PATCH 0) set(VERSION_PATCH 0)
set(VERSION_EXTRA "-dragonfire" CACHE STRING "Stuff to append to version string") ##set dragonfire to make hackclient detection easier for servers set(VERSION_EXTRA "dragonfire" CACHE STRING "Stuff to append to version string")
# Change to false for releases # Change to false for releases
set(DEVELOPMENT_BUILD FALSE) set(DEVELOPMENT_BUILD FALSE)
@ -65,6 +59,29 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
# This is done here so that relative search paths are more reasonable # This is done here so that relative search paths are more reasonable
find_package(Irrlicht) find_package(Irrlicht)
if(BUILD_CLIENT AND NOT IRRLICHT_FOUND)
message(FATAL_ERROR "IrrlichtMt is required to build the client, but it was not found.")
elseif(NOT IRRLICHT_INCLUDE_DIR)
message(FATAL_ERROR "Irrlicht or IrrlichtMt headers are required to build the server, but none found.")
endif()
include(CheckSymbolExists)
set(CMAKE_REQUIRED_INCLUDES ${IRRLICHT_INCLUDE_DIR})
unset(HAS_FORKED_IRRLICHT CACHE)
check_symbol_exists(IRRLICHT_VERSION_MT "IrrCompileConfig.h" HAS_FORKED_IRRLICHT)
if(NOT HAS_FORKED_IRRLICHT)
string(CONCAT EXPLANATION_MSG
"Irrlicht found, but it is not IrrlichtMt (Minetest's Irrlicht fork). "
"The Minetest team has forked Irrlicht to make their own customizations. "
"It can be found here: https://github.com/minetest/irrlicht")
if(BUILD_CLIENT)
message(FATAL_ERROR "${EXPLANATION_MSG}\n"
"Building the client with upstream Irrlicht is no longer possible.")
else()
message(WARNING "${EXPLANATION_MSG}\n"
"The server can still be built with upstream Irrlicht but this is DISCOURAGED.")
endif()
endif()
# Installation # Installation
@ -165,7 +182,7 @@ 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/" install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game" DESTINATION "${SHAREDIR}/games/"
COMPONENT "SUBGAME_MINETEST_GAME" OPTIONAL PATTERN ".git*" EXCLUDE ) COMPONENT "SUBGAME_MINETEST_GAME" OPTIONAL PATTERN ".git*" EXCLUDE )
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/devtest" DESTINATION "${SHAREDIR}/games/" install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/devtest" DESTINATION "${SHAREDIR}/games/"
COMPONENT "SUBGAME_MINIMAL" OPTIONAL PATTERN ".git*" EXCLUDE ) COMPONENT "SUBGAME_MINIMAL" OPTIONAL PATTERN ".git*" EXCLUDE )
@ -173,7 +190,6 @@ install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/devtest" DESTINATION "${SHA
if(BUILD_CLIENT) if(BUILD_CLIENT)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client/shaders" DESTINATION "${SHAREDIR}/client") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client/shaders" DESTINATION "${SHAREDIR}/client")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/textures/base/pack" DESTINATION "${SHAREDIR}/textures/base") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/textures/base/pack" DESTINATION "${SHAREDIR}/textures/base")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/fonts" DESTINATION "${SHAREDIR}")
if(RUN_IN_PLACE) if(RUN_IN_PLACE)
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/clientmods" DESTINATION "${SHAREDIR}") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/clientmods" DESTINATION "${SHAREDIR}")
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client/serverlist" DESTINATION "${SHAREDIR}/client") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client/serverlist" DESTINATION "${SHAREDIR}/client")
@ -192,14 +208,14 @@ if(UNIX AND NOT APPLE)
install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6") install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}") install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
install(FILES "misc/net.minetest.minetest.appdata.xml" DESTINATION "${APPDATADIR}") install(FILES "misc/net.minetest.minetest.appdata.xml" DESTINATION "${APPDATADIR}")
install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps") install(FILES "misc/dragonfire.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
install(FILES "misc/minetest-xorg-icon-128.png" install(FILES "misc/dragonfire-xorg-icon-128.png"
DESTINATION "${ICONDIR}/hicolor/128x128/apps" DESTINATION "${ICONDIR}/hicolor/128x128/apps"
RENAME "minetest.png") RENAME "dragonfire.png")
endif() endif()
if(APPLE) if(APPLE)
install(FILES "misc/minetest-icon.icns" DESTINATION "${SHAREDIR}") install(FILES "misc/dragonfire-icon.icns" DESTINATION "${SHAREDIR}")
install(FILES "misc/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents") install(FILES "misc/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents")
endif() endif()
@ -208,8 +224,8 @@ find_package(GMP REQUIRED)
find_package(Json REQUIRED) find_package(Json REQUIRED)
find_package(Lua REQUIRED) find_package(Lua REQUIRED)
# JsonCPP doesn't compile well on GCC 4.8 # JsonCpp doesn't compile well on GCC 4.8
if(NOT ENABLE_SYSTEM_JSONCPP) if(NOT USE_SYSTEM_JSONCPP)
set(GCC_MINIMUM_VERSION "4.9") set(GCC_MINIMUM_VERSION "4.9")
endif() endif()
@ -218,7 +234,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
message(FATAL_ERROR "Insufficient gcc version, found ${CMAKE_CXX_COMPILER_VERSION}. " message(FATAL_ERROR "Insufficient gcc version, found ${CMAKE_CXX_COMPILER_VERSION}. "
"Version ${GCC_MINIMUM_VERSION} or higher is required.") "Version ${GCC_MINIMUM_VERSION} or higher is required.")
endif() endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") elseif(CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?Clang")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "${CLANG_MINIMUM_VERSION}") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "${CLANG_MINIMUM_VERSION}")
message(FATAL_ERROR "Insufficient clang version, found ${CMAKE_CXX_COMPILER_VERSION}. " message(FATAL_ERROR "Insufficient clang version, found ${CMAKE_CXX_COMPILER_VERSION}. "
"Version ${CLANG_MINIMUM_VERSION} or higher is required.") "Version ${CLANG_MINIMUM_VERSION} or higher is required.")
@ -278,19 +294,20 @@ if(WIN32)
set(CPACK_GENERATOR ZIP) set(CPACK_GENERATOR ZIP)
else() else()
set(CPACK_GENERATOR WIX ZIP) set(CPACK_GENERATOR WIX)
set(CPACK_PACKAGE_NAME "${PROJECT_NAME_CAPITALIZED}") set(CPACK_PACKAGE_NAME "${PROJECT_NAME_CAPITALIZED}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME_CAPITALIZED}") set(CPACK_PACKAGE_INSTALL_DIRECTORY ".")
set(CPACK_PACKAGE_EXECUTABLES ${PROJECT_NAME} "${PROJECT_NAME_CAPITALIZED}") set(CPACK_PACKAGE_EXECUTABLES ${PROJECT_NAME} "${PROJECT_NAME_CAPITALIZED}")
set(CPACK_CREATE_DESKTOP_LINKS ${PROJECT_NAME}) set(CPACK_CREATE_DESKTOP_LINKS ${PROJECT_NAME})
set(CPACK_PACKAGING_INSTALL_PREFIX "/${PROJECT_NAME_CAPITALIZED}")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/minetest-icon.ico") set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/dragonfire-icon.ico")
# Supported languages can be found at # Supported languages can be found at
# http://wixtoolset.org/documentation/manual/v3/wixui/wixui_localization.html # http://wixtoolset.org/documentation/manual/v3/wixui/wixui_localization.html
#set(CPACK_WIX_CULTURES "ar-SA,bg-BG,ca-ES,hr-HR,cs-CZ,da-DK,nl-NL,en-US,et-EE,fi-FI,fr-FR,de-DE") #set(CPACK_WIX_CULTURES "ar-SA,bg-BG,ca-ES,hr-HR,cs-CZ,da-DK,nl-NL,en-US,et-EE,fi-FI,fr-FR,de-DE")
set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/misc/CPACK_WIX_UI_BANNER.BMP") set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/misc/CPACK_WIX_UI_BANNER.BMP")
set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/misc/CPACK_WIX_UI_DIALOG.BMP") set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/misc/CPACK_WIX_UI_DIALOG.BMP")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/doc/lgpl-2.1.txt") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/doc/lgpl-2.1.txt")
# The correct way would be to include both x32 and x64 into one installer # The correct way would be to include both x32 and x64 into one installer

View File

@ -1,6 +1,7 @@
FROM alpine:3.11 FROM alpine:3.13
ENV MINETEST_GAME_VERSION master ENV MINETEST_GAME_VERSION master
ENV IRRLICHT_VERSION master
COPY .git /usr/src/minetest/.git COPY .git /usr/src/minetest/.git
COPY CMakeLists.txt /usr/src/minetest/CMakeLists.txt COPY CMakeLists.txt /usr/src/minetest/CMakeLists.txt
@ -18,9 +19,7 @@ COPY textures /usr/src/minetest/textures
WORKDIR /usr/src/minetest WORKDIR /usr/src/minetest
RUN apk add --no-cache git build-base irrlicht-dev cmake bzip2-dev libpng-dev \ RUN apk add --no-cache git build-base cmake sqlite-dev curl-dev zlib-dev \
jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev \
libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev \
gmp-dev jsoncpp-dev postgresql-dev luajit-dev ca-certificates && \ gmp-dev jsoncpp-dev postgresql-dev luajit-dev ca-certificates && \
git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \ git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \
rm -fr ./games/minetest_game/.git rm -fr ./games/minetest_game/.git
@ -36,6 +35,9 @@ RUN git clone --recursive https://github.com/jupp0r/prometheus-cpp/ && \
make -j2 && \ make -j2 && \
make install make install
RUN git clone --depth=1 https://github.com/minetest/irrlicht/ -b ${IRRLICHT_VERSION} && \
cp -r irrlicht/include /usr/include/irrlichtmt
WORKDIR /usr/src/minetest WORKDIR /usr/src/minetest
RUN mkdir build && \ RUN mkdir build && \
cd build && \ cd build && \
@ -49,9 +51,9 @@ RUN mkdir build && \
make -j2 && \ make -j2 && \
make install make install
FROM alpine:3.11 FROM alpine:3.13
RUN apk add --no-cache sqlite-libs curl gmp libstdc++ libgcc libpq luajit && \ RUN apk add --no-cache sqlite-libs curl gmp libstdc++ libgcc libpq luajit jsoncpp && \
adduser -D minetest --uid 30000 -h /var/lib/minetest && \ adduser -D minetest --uid 30000 -h /var/lib/minetest && \
chown -R minetest:minetest /var/lib/minetest chown -R minetest:minetest /var/lib/minetest

View File

@ -11,6 +11,12 @@ http://creativecommons.org/licenses/by-sa/3.0/
textures/base/pack/refresh.png is under the Apache 2 license textures/base/pack/refresh.png is under the Apache 2 license
https://www.apache.org/licenses/LICENSE-2.0.html https://www.apache.org/licenses/LICENSE-2.0.html
Textures by Zughy are under CC BY-SA 4.0
https://creativecommons.org/licenses/by-sa/4.0/
textures/base/pack/server_public.png is under CC-BY 4.0, taken from Twitter's Twemoji set
https://creativecommons.org/licenses/by/4.0/
Authors of media files Authors of media files
----------------------- -----------------------
Everything not listed in here: Everything not listed in here:
@ -23,21 +29,23 @@ paramat:
textures/base/pack/menu_header.png textures/base/pack/menu_header.png
textures/base/pack/next_icon.png textures/base/pack/next_icon.png
textures/base/pack/prev_icon.png textures/base/pack/prev_icon.png
textures/base/pack/clear.png
textures/base/pack/search.png
rubenwardy, paramat: rubenwardy, paramat:
textures/base/pack/start_icon.png textures/base/pack/start_icon.png
textures/base/pack/end_icon.png textures/base/pack/end_icon.png
erlehmann: EliasFleckenstein03:
misc/minetest-icon-24x24.png misc/dragonfire-icon-24x24.png
misc/minetest-icon.ico misc/dragonfire-icon.ico
misc/minetest.svg misc/dragonfire.svg
textures/base/pack/logo.png textures/base/pack/logo.png
JRottm JRottm:
textures/base/pack/player_marker.png textures/base/pack/player_marker.png
srifqi srifqi:
textures/base/pack/chat_hide_btn.png textures/base/pack/chat_hide_btn.png
textures/base/pack/chat_show_btn.png textures/base/pack/chat_show_btn.png
textures/base/pack/joystick_bg.png textures/base/pack/joystick_bg.png
@ -45,6 +53,17 @@ srifqi
textures/base/pack/joystick_off.png textures/base/pack/joystick_off.png
textures/base/pack/minimap_btn.png textures/base/pack/minimap_btn.png
Zughy:
textures/base/pack/cdb_add.png
textures/base/pack/cdb_clear.png
textures/base/pack/cdb_downloading.png
textures/base/pack/cdb_queued.png
textures/base/pack/cdb_update.png
textures/base/pack/cdb_viewonline.png
appgurueu:
textures/base/pack/server_incompatible.png
License of Minetest source code License of Minetest source code
------------------------------- -------------------------------
@ -68,7 +87,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Irrlicht Irrlicht
--------------- ---------------
This program uses the Irrlicht Engine. http://irrlicht.sourceforge.net/ This program uses IrrlichtMt, Minetest's fork of
the Irrlicht Engine. http://irrlicht.sourceforge.net/
The Irrlicht Engine License The Irrlicht Engine License

View File

@ -38,10 +38,10 @@ Table of Contents
Further documentation Further documentation
---------------------- ----------------------
- Website: http://minetest.net/ - Website: https://minetest.net/
- Wiki: http://wiki.minetest.net/ - Wiki: https://wiki.minetest.net/
- Developer wiki: http://dev.minetest.net/ - Developer wiki: https://dev.minetest.net/
- Forum: http://forum.minetest.net/ - Forum: https://forum.minetest.net/
- GitHub: https://github.com/minetest/minetest/ - GitHub: https://github.com/minetest/minetest/
- [doc/](doc/) directory of source distribution - [doc/](doc/) directory of source distribution
@ -75,7 +75,7 @@ Some can be changed in the key config dialog in the settings tab.
| P | Enable/disable pitch move mode | | P | Enable/disable pitch move mode |
| J | Enable/disable fast mode (needs fast privilege) | | J | Enable/disable fast mode (needs fast privilege) |
| H | Enable/disable noclip mode (needs noclip privilege) | | H | Enable/disable noclip mode (needs noclip privilege) |
| E | Move fast in fast mode | | E | Aux1 (Move fast in fast mode. Games may add special features) |
| C | Cycle through camera modes | | C | Cycle through camera modes |
| V | Cycle through minimap modes | | V | Cycle through minimap modes |
| Shift + V | Change minimap orientation | | Shift + V | Change minimap orientation |
@ -140,8 +140,8 @@ Compiling
| Dependency | Version | Commentary | | Dependency | Version | Commentary |
|------------|---------|------------| |------------|---------|------------|
| GCC | 4.9+ | Can be replaced with Clang 3.4+ | | GCC | 4.9+ | Can be replaced with Clang 3.4+ |
| CMake | 2.6+ | | | CMake | 3.5+ | |
| Irrlicht | 1.7.3+ | | | IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
| SQLite3 | 3.0+ | | | SQLite3 | 3.0+ | |
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present | | LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present | | GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
@ -149,19 +149,19 @@ Compiling
For Debian/Ubuntu users: For Debian/Ubuntu users:
sudo apt install g++ make libc6-dev libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
For Fedora users: For Fedora users:
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel irrlicht-devel bzip2-libs gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel doxygen spatialindex-devel bzip2-devel sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel
For Arch users: For Arch users:
sudo pacman -S base-devel libcurl-gnutls cmake libxxf86vm irrlicht libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses sudo pacman -S base-devel libcurl-gnutls cmake libxxf86vm libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses
For Alpine users: For Alpine users:
sudo apk add build-base irrlicht-dev cmake bzip2-dev libpng-dev jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev sudo apk add build-base cmake libpng-dev jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev
#### Download #### Download
@ -216,8 +216,8 @@ Run it:
- You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`. - You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`.
- You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`. - You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`.
- Debug build is slower, but gives much more useful output in a debugger. - Debug build is slower, but gives much more useful output in a debugger.
- If you build a bare server you don't need to have Irrlicht installed. - If you build a bare server you don't need to have the Irrlicht or IrrlichtMt library installed.
- In that case use `-DIRRLICHT_SOURCE_DIR=/the/irrlicht/source`. - In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlicht/include`.
### CMake options ### CMake options
@ -236,7 +236,7 @@ General options and their default values:
ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal) ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_FREETYPE=ON - Build with FreeType2; Allows using TTF fonts ENABLE_FREETYPE=ON - Build with FreeType2; Allows using TTF fonts
ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations
ENABLE_GLES=OFF - Build for OpenGL ES instead of OpenGL (requires support by Irrlicht) ENABLE_GLES=OFF - Build for OpenGL ES instead of OpenGL (requires support by IrrlichtMt)
ENABLE_LEVELDB=ON - Build with LevelDB; Enables use of LevelDB map backend ENABLE_LEVELDB=ON - Build with LevelDB; Enables use of LevelDB map backend
ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended) ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended)
ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend
@ -245,7 +245,7 @@ General options and their default values:
ENABLE_LUAJIT=ON - Build with LuaJIT (much faster than non-JIT Lua) ENABLE_LUAJIT=ON - Build with LuaJIT (much faster than non-JIT Lua)
ENABLE_PROMETHEUS=OFF - Build with Prometheus metrics exporter (listens on tcp/30000 by default) ENABLE_PROMETHEUS=OFF - Build with Prometheus metrics exporter (listens on tcp/30000 by default)
ENABLE_SYSTEM_GMP=ON - Use GMP from system (much faster than bundled mini-gmp) ENABLE_SYSTEM_GMP=ON - Use GMP from system (much faster than bundled mini-gmp)
ENABLE_SYSTEM_JSONCPP=OFF - Use JsonCPP from system ENABLE_SYSTEM_JSONCPP=ON - Use JsonCPP from system
OPENGL_GL_PREFERENCE=LEGACY - Linux client build only; See CMake Policy CMP0072 for reference OPENGL_GL_PREFERENCE=LEGACY - Linux client build only; See CMake Policy CMP0072 for reference
RUN_IN_PLACE=FALSE - Create a portable install (worlds, settings etc. in current directory) RUN_IN_PLACE=FALSE - Create a portable install (worlds, settings etc. in current directory)
USE_GPROF=FALSE - Enable profiling using GProf USE_GPROF=FALSE - Enable profiling using GProf
@ -253,8 +253,6 @@ General options and their default values:
Library specific options: Library specific options:
BZIP2_INCLUDE_DIR - Linux only; directory where bzlib.h is located
BZIP2_LIBRARY - Linux only; path to libbz2.a/libbz2.so
CURL_DLL - Only if building with cURL on Windows; path to libcurl.dll CURL_DLL - Only if building with cURL on Windows; path to libcurl.dll
CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located
CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib
@ -264,14 +262,13 @@ Library specific options:
FREETYPE_INCLUDE_DIR_ft2build - Only if building with FreeType 2; directory that contains ft2build.h FREETYPE_INCLUDE_DIR_ft2build - Only if building with FreeType 2; directory that contains ft2build.h
FREETYPE_LIBRARY - Only if building with FreeType 2; path to libfreetype.a/libfreetype.so/freetype.lib FREETYPE_LIBRARY - Only if building with FreeType 2; path to libfreetype.a/libfreetype.so/freetype.lib
FREETYPE_DLL - Only if building with FreeType 2 on Windows; path to libfreetype.dll FREETYPE_DLL - Only if building with FreeType 2 on Windows; path to libfreetype.dll
GETTEXT_DLL - Only when building with gettext on Windows; path to libintl3.dll GETTEXT_DLL - Only when building with gettext on Windows; paths to libintl + libiconv DLLs
GETTEXT_ICONV_DLL - Only when building with gettext on Windows; path to libiconv2.dll
GETTEXT_INCLUDE_DIR - Only when building with gettext; directory that contains iconv.h GETTEXT_INCLUDE_DIR - Only when building with gettext; directory that contains iconv.h
GETTEXT_LIBRARY - Only when building with gettext on Windows; path to libintl.dll.a GETTEXT_LIBRARY - Only when building with gettext on Windows; path to libintl.dll.a
GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe
IRRLICHT_DLL - Only on Windows; path to Irrlicht.dll IRRLICHT_DLL - Only on Windows; path to IrrlichtMt.dll
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h
IRRLICHT_LIBRARY - Path to libIrrlicht.a/libIrrlicht.so/libIrrlicht.dll.a/Irrlicht.lib IRRLICHT_LIBRARY - Path to libIrrlichtMt.a/libIrrlichtMt.so/libIrrlichtMt.dll.a/IrrlichtMt.lib
LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h
LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll
@ -283,7 +280,6 @@ Library specific options:
SPATIAL_LIBRARY - Only when building with LibSpatial; path to libspatialindex_c.so/spatialindex-32.lib SPATIAL_LIBRARY - Only when building with LibSpatial; path to libspatialindex_c.so/spatialindex-32.lib
LUA_INCLUDE_DIR - Only if you want to use LuaJIT; directory where luajit.h is located LUA_INCLUDE_DIR - Only if you want to use LuaJIT; directory where luajit.h is located
LUA_LIBRARY - Only if you want to use LuaJIT; path to libluajit.a/libluajit.so LUA_LIBRARY - Only if you want to use LuaJIT; path to libluajit.a/libluajit.so
MINGWM10_DLL - Only if compiling with MinGW; path to mingwm10.dll
OGG_DLL - Only if building with sound on Windows; path to libogg.dll OGG_DLL - Only if building with sound on Windows; path to libogg.dll
OGG_INCLUDE_DIR - Only if building with sound; directory that contains an ogg directory which contains ogg.h OGG_INCLUDE_DIR - Only if building with sound; directory that contains an ogg directory which contains ogg.h
OGG_LIBRARY - Only if building with sound; path to libogg.a/libogg.so/libogg.dll.a OGG_LIBRARY - Only if building with sound; path to libogg.a/libogg.so/libogg.dll.a
@ -294,9 +290,8 @@ Library specific options:
OPENGLES2_LIBRARY - Only if building with GLES; path to libGLESv2.a/libGLESv2.so OPENGLES2_LIBRARY - Only if building with GLES; path to libGLESv2.a/libGLESv2.so
SQLITE3_INCLUDE_DIR - Directory that contains sqlite3.h SQLITE3_INCLUDE_DIR - Directory that contains sqlite3.h
SQLITE3_LIBRARY - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib SQLITE3_LIBRARY - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib
VORBISFILE_DLL - Only if building with sound on Windows; path to libvorbisfile-3.dll
VORBISFILE_LIBRARY - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a VORBISFILE_LIBRARY - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a
VORBIS_DLL - Only if building with sound on Windows; path to libvorbis-0.dll VORBIS_DLL - Only if building with sound on Windows; paths to vorbis DLLs
VORBIS_INCLUDE_DIR - Only if building with sound; directory that contains a directory vorbis with vorbisenc.h inside VORBIS_INCLUDE_DIR - Only if building with sound; directory that contains a directory vorbis with vorbisenc.h inside
VORBIS_LIBRARY - Only if building with sound; path to libvorbis.a/libvorbis.so/libvorbis.dll.a VORBIS_LIBRARY - Only if building with sound; path to libvorbis.a/libvorbis.so/libvorbis.dll.a
XXF86VM_LIBRARY - Only on Linux; path to libXXf86vm.a/libXXf86vm.so XXF86VM_LIBRARY - Only on Linux; path to libXXf86vm.a/libXXf86vm.so
@ -321,9 +316,10 @@ It is highly recommended to use vcpkg as package manager.
After you successfully built vcpkg you can easily install the required libraries: After you successfully built vcpkg you can easily install the required libraries:
```powershell ```powershell
vcpkg install irrlicht zlib curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit gmp jsoncpp --triplet x64-windows vcpkg install zlib curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit gmp jsoncpp --triplet x64-windows
``` ```
- **Note that you currently need to build irrlicht on your own**
- `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store. - `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store.
- `openal-soft`, `libvorbis` and `libogg` are optional, but required to use sound. - `openal-soft`, `libvorbis` and `libogg` are optional, but required to use sound.
- `freetype` is optional, it allows true-type font rendering. - `freetype` is optional, it allows true-type font rendering.
@ -361,7 +357,7 @@ This is outdated and not recommended. Follow the instructions on https://dev.min
Run the following script in PowerShell: Run the following script in PowerShell:
```powershell ```powershell
cmake . -G"Visual Studio 15 2017 Win64" -DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_GETTEXT=OFF -DENABLE_CURSES=OFF -DENABLE_SYSTEM_JSONCPP=ON cmake . -G"Visual Studio 15 2017 Win64" -DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_GETTEXT=OFF -DENABLE_CURSES=OFF
cmake --build . --config Release cmake --build . --config Release
``` ```
Make sure that the right compiler is selected and the path to the vcpkg toolchain is correct. Make sure that the right compiler is selected and the path to the vcpkg toolchain is correct.

View File

@ -1,8 +1,8 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion '30.0.2' buildToolsVersion '30.0.3'
ndkVersion '21.3.6528147' ndkVersion '22.0.7026061'
defaultConfig { defaultConfig {
applicationId 'net.minetest.minetest' applicationId 'net.minetest.minetest'
minSdkVersion 16 minSdkVersion 16

View File

@ -142,8 +142,8 @@ public class GameActivity extends NativeActivity {
return getResources().getDisplayMetrics().widthPixels; return getResources().getDisplayMetrics().widthPixels;
} }
public void openURL(String url) { public void openURI(String uri) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(browserIntent); startActivity(browserIntent);
} }
} }

View File

@ -1,10 +1,10 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
project.ext.set("versionMajor", 5) // Version Major project.ext.set("versionMajor", 5) // Version Major
project.ext.set("versionMinor", 3) // Version Minor project.ext.set("versionMinor", 5) // Version Minor
project.ext.set("versionPatch", 0) // Version Patch project.ext.set("versionPatch", 0) // Version Patch
project.ext.set("versionExtra", "-dev") // Version Extra project.ext.set("versionExtra", "-dev") // Version Extra
project.ext.set("versionCode", 30) // Android Version Code project.ext.set("versionCode", 32) // Android Version Code
// NOTE: +2 after each release! // NOTE: +2 after each release!
// +1 for ARM and +1 for ARM64 APK's, because // +1 for ARM and +1 for ARM64 APK's, because
// each APK must have a larger `versionCode` than the previous // each APK must have a larger `versionCode` than the previous
@ -15,7 +15,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.0.1' classpath 'com.android.tools.build:gradle:4.1.1'
classpath 'de.undercouch:gradle-download-task:4.1.1' classpath 'de.undercouch:gradle-download-task:4.1.1'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

View File

@ -1,6 +1,6 @@
#Mon Sep 07 22:11:10 CEST 2020 #Fri Jan 08 17:52:00 UTC 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="24.000002"
inkscape:export-xdpi="24.000002"
inkscape:export-filename="/home/stu/Desktop/icons/png/aux_btn.png"
sodipodi:docname="aux_btn.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg8"
version="1.1"
viewBox="0 0 135.46666 135.46667"
height="512"
width="512">
<defs
id="defs2" />
<sodipodi:namedview
inkscape:document-rotation="0"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-others="true"
inkscape:snap-object-midpoints="false"
inkscape:snap-to-guides="true"
inkscape:snap-bbox="true"
showguides="true"
inkscape:snap-page="true"
inkscape:snap-grids="false"
inkscape:pagecheckerboard="false"
inkscape:window-maximized="1"
inkscape:window-y="31"
inkscape:window-x="0"
inkscape:window-height="1024"
inkscape:window-width="1920"
units="px"
showgrid="true"
inkscape:current-layer="layer2"
inkscape:document-units="mm"
inkscape:cy="212.91276"
inkscape:cx="201.43176"
inkscape:zoom="1.4633894"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#404040"
id="base">
<inkscape:grid
empopacity="0.25098039"
empcolor="#40ff40"
opacity="0.1254902"
color="#40ff40"
empspacing="4"
spacingy="0.26458333"
spacingx="0.26458333"
id="grid16"
type="xygrid" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
style="display:inline"
inkscape:label="Layer 2"
id="layer2"
inkscape:groupmode="layer">
<path
inkscape:connector-curvature="0"
id="path7055"
d=""
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path7035"
d=""
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path7005"
d=""
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path5127"
d=""
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
transform="scale(1.0078883,0.99217343)"
id="text4716"
y="85.59491"
x="67.78315"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.4785px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
xml:space="preserve"><tspan
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
y="85.59491"
x="67.78315"
id="tspan4714"
sodipodi:role="line">Aux1</tspan></text>
<flowRoot
transform="scale(0.26458333)"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
id="flowRoot4718"
xml:space="preserve"><flowRegion
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
id="flowRegion4720"><rect
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
y="124.10143"
x="264.65997"
height="136.37059"
width="157.5838"
id="rect4722" /></flowRegion><flowPara
id="flowPara4724" /></flowRoot>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,411 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 135.46666 135.46667"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="aux_btn.svg"
inkscape:export-filename="/home/stu/Desktop/icons/png/aux_btn.png"
inkscape:export-xdpi="24.000002"
inkscape:export-ydpi="24.000002">
<defs
id="defs2">
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Colorize"
id="filter4628">
<feComposite
in2="SourceGraphic"
operator="arithmetic"
k1="0"
k2="1"
result="composite1"
id="feComposite4614" />
<feColorMatrix
in="composite1"
values="1"
type="saturate"
result="colormatrix1"
id="feColorMatrix4616" />
<feFlood
flood-opacity="1"
flood-color="rgb(158,0,0)"
result="flood1"
id="feFlood4618" />
<feBlend
in="flood1"
in2="colormatrix1"
mode="multiply"
result="blend1"
id="feBlend4620" />
<feBlend
in2="blend1"
mode="screen"
result="blend2"
id="feBlend4622" />
<feColorMatrix
in="blend2"
values="1"
type="saturate"
result="colormatrix2"
id="feColorMatrix4624" />
<feComposite
in="colormatrix2"
in2="SourceGraphic"
operator="in"
k2="1"
result="composite2"
id="feComposite4626" />
</filter>
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Sharpen More"
id="filter5109"
inkscape:menu="Image Effects"
inkscape:menu-tooltip="Sharpen edges and boundaries within the object, force=0.3">
<feComposite
in2="SourceGraphic"
operator="arithmetic"
k1="0"
k2="1"
result="composite1"
id="feComposite5095" />
<feColorMatrix
in="composite1"
values="1"
type="saturate"
result="colormatrix1"
id="feColorMatrix5097" />
<feFlood
flood-opacity="1"
flood-color="rgb(158,67,0)"
result="flood1"
id="feFlood5099" />
<feBlend
in="flood1"
in2="colormatrix1"
mode="multiply"
result="blend1"
id="feBlend5101" />
<feBlend
in2="blend1"
mode="screen"
result="blend2"
id="feBlend5103" />
<feColorMatrix
in="blend2"
values="1"
type="saturate"
result="colormatrix2"
id="feColorMatrix5105" />
<feComposite
in="colormatrix2"
in2="SourceGraphic"
operator="in"
k2="1"
result="fbSourceGraphic"
id="feComposite5107" />
<feColorMatrix
result="fbSourceGraphicAlpha"
in="fbSourceGraphic"
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
id="feColorMatrix5111" />
<feComposite
in2="fbSourceGraphic"
id="feComposite5113"
operator="arithmetic"
k1="0"
k2="1"
result="composite1"
in="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix5115"
in="composite1"
values="1"
type="saturate"
result="colormatrix1" />
<feFlood
id="feFlood5117"
flood-opacity="1"
flood-color="rgb(158,0,0)"
result="flood1" />
<feBlend
in2="colormatrix1"
id="feBlend5119"
in="flood1"
mode="multiply"
result="blend1" />
<feBlend
in2="blend1"
id="feBlend5121"
mode="screen"
result="blend2" />
<feColorMatrix
id="feColorMatrix5123"
in="blend2"
values="1"
type="saturate"
result="colormatrix2" />
<feComposite
in2="fbSourceGraphic"
id="feComposite5125"
in="colormatrix2"
operator="in"
k2="1"
result="fbSourceGraphic" />
<feColorMatrix
result="fbSourceGraphicAlpha"
in="fbSourceGraphic"
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
id="feColorMatrix7007" />
<feConvolveMatrix
id="feConvolveMatrix7009"
order="3 3"
kernelMatrix="0 -0.15 0 -0.15 1.6 -0.15 0 -0.15 0"
divisor="1"
in="fbSourceGraphic"
targetX="1"
targetY="1"
result="fbSourceGraphic" />
<feColorMatrix
result="fbSourceGraphicAlpha"
in="fbSourceGraphic"
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 1 0"
id="feColorMatrix7011" />
<feConvolveMatrix
id="feConvolveMatrix7013"
targetY="1"
targetX="1"
in="fbSourceGraphic"
divisor="1"
kernelMatrix="0 -0.3 0 -0.3 2.2 -0.3 0 -0.3 0"
order="3 3"
result="result1" />
<feBlend
in2="fbSourceGraphic"
id="feBlend7015"
mode="normal"
result="result2" />
</filter>
<marker
style="overflow:visible"
refY="0.0"
refX="0.0"
orient="auto"
id="DistanceX">
<path
id="path7410"
style="stroke:#000000; stroke-width:0.5"
d="M 3,-3 L -3,3 M 0,-5 L 0,5" />
</marker>
<pattern
y="0"
x="0"
width="8"
patternUnits="userSpaceOnUse"
id="Hatch"
height="8">
<path
id="path7413"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M8 4 l-4,4" />
<path
id="path7415"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M6 2 l-4,4" />
<path
id="path7417"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M4 0 l-4,4" />
</pattern>
<symbol
id="*Model_Space" />
<symbol
id="*Paper_Space" />
<symbol
id="*Paper_Space0" />
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Colorize"
id="filter4883">
<feComposite
in2="SourceGraphic"
operator="arithmetic"
k1="0"
k2="1"
result="composite1"
id="feComposite4869" />
<feColorMatrix
in="composite1"
values="1"
type="saturate"
result="colormatrix1"
id="feColorMatrix4871" />
<feFlood
flood-opacity="1"
flood-color="rgb(158,21,0)"
result="flood1"
id="feFlood4873" />
<feBlend
in="flood1"
in2="colormatrix1"
mode="multiply"
result="blend1"
id="feBlend4875" />
<feBlend
in2="blend1"
mode="screen"
result="blend2"
id="feBlend4877" />
<feColorMatrix
in="blend2"
values="1"
type="saturate"
result="colormatrix2"
id="feColorMatrix4879" />
<feComposite
in="colormatrix2"
in2="SourceGraphic"
operator="in"
k2="1"
result="composite2"
id="feComposite4881" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#404040"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="-341.34157"
inkscape:cy="210.02973"
inkscape:document-units="mm"
inkscape:current-layer="layer2"
showgrid="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1023"
inkscape:window-x="0"
inkscape:window-y="34"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="false"
inkscape:snap-grids="false"
inkscape:snap-page="true"
showguides="true"
inkscape:snap-bbox="true"
inkscape:snap-to-guides="true"
inkscape:snap-object-midpoints="false"
inkscape:snap-others="true"
inkscape:snap-bbox-midpoints="true">
<inkscape:grid
type="xygrid"
id="grid16"
spacingx="0.26458333"
spacingy="0.26458333"
empspacing="4"
color="#40ff40"
opacity="0.1254902"
empcolor="#40ff40"
empopacity="0.25098039" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2"
style="display:inline">
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d=""
id="path7055"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d=""
id="path7035"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d=""
id="path7005"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d=""
id="path5127"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.47851181px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="67.78315"
y="85.59491"
id="text4716"
transform="scale(1.0078883,0.99217343)"><tspan
sodipodi:role="line"
id="tspan4714"
x="67.78315"
y="85.59491"
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">AUX</tspan></text>
<flowRoot
xml:space="preserve"
id="flowRoot4718"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
transform="scale(0.26458333)"><flowRegion
id="flowRegion4720"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"><rect
id="rect4722"
width="157.5838"
height="136.37059"
x="264.65997"
y="124.10143"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1" /></flowRegion><flowPara
id="flowPara4724" /></flowRoot> </g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -3,8 +3,8 @@ apply plugin: 'de.undercouch.download'
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion '30.0.2' buildToolsVersion '30.0.3'
ndkVersion '21.3.6528147' ndkVersion '22.0.7026061'
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 29 targetSdkVersion 29
@ -71,7 +71,7 @@ task getDeps(dependsOn: downloadDeps, type: Copy) {
} }
// get sqlite // get sqlite
def sqlite_ver = '3320200' def sqlite_ver = '3340000'
task downloadSqlite(dependsOn: getDeps, type: Download) { task downloadSqlite(dependsOn: getDeps, type: Download) {
src 'https://www.sqlite.org/2020/sqlite-amalgamation-' + sqlite_ver + '.zip' src 'https://www.sqlite.org/2020/sqlite-amalgamation-' + sqlite_ver + '.zip'
dest new File(buildDir, 'sqlite.zip') dest new File(buildDir, 'sqlite.zip')

View File

@ -14,7 +14,7 @@ include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := Irrlicht LOCAL_MODULE := Irrlicht
LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlicht.a LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlichtMt.a
include $(PREBUILT_STATIC_LIBRARY) include $(PREBUILT_STATIC_LIBRARY)
#include $(CLEAR_VARS) #include $(CLEAR_VARS)
@ -47,18 +47,6 @@ LOCAL_MODULE := OpenAL
LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a
include $(PREBUILT_STATIC_LIBRARY) include $(PREBUILT_STATIC_LIBRARY)
# You can use `OpenSSL and Crypto` instead `mbedTLS mbedx509 mbedcrypto`,
#but it increase APK size on ~0.7MB
#include $(CLEAR_VARS)
#LOCAL_MODULE := OpenSSL
#LOCAL_SRC_FILES := deps/Android/OpenSSL/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libssl.a
#include $(PREBUILT_STATIC_LIBRARY)
#include $(CLEAR_VARS)
#LOCAL_MODULE := Crypto
#LOCAL_SRC_FILES := deps/Android/OpenSSL/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcrypto.a
#include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := Vorbis LOCAL_MODULE := Vorbis
LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a
@ -207,7 +195,6 @@ LOCAL_SRC_FILES += \
LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c
LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT android_native_app_glue $(PROFILER_LIBS) #LevelDB LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT android_native_app_glue $(PROFILER_LIBS) #LevelDB
#OpenSSL Crypto
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES

View File

@ -7,7 +7,7 @@ core.register_on_sending_chat_message(function(message)
local first_char = message:sub(1,1) local first_char = message:sub(1,1)
if first_char == "/" or first_char == "." then if first_char == "/" or first_char == "." then
core.display_chat_message(core.gettext("issued command: ") .. message) core.display_chat_message(core.gettext("Issued command: ") .. message)
end end
if first_char ~= "." then if first_char ~= "." then
@ -18,7 +18,7 @@ core.register_on_sending_chat_message(function(message)
param = param or "" param = param or ""
if not cmd then if not cmd then
core.display_chat_message(core.gettext("-!- Empty command")) core.display_chat_message("-!- " .. core.gettext("Empty command."))
return true return true
end end
@ -35,7 +35,7 @@ core.register_on_sending_chat_message(function(message)
core.display_chat_message(result) core.display_chat_message(result)
end end
else else
core.display_chat_message(core.gettext("-!- Invalid command: ") .. cmd) core.display_chat_message("-!- " .. core.gettext("Invalid command: ") .. cmd)
end end
return true return true
@ -66,23 +66,10 @@ core.register_chatcommand("teleport", {
end, end,
}) })
core.register_chatcommand("teleportjump", {
params = "<X>,<Y>,<Z>",
description = "Teleport to relative coordinates.",
func = function(param)
local success, pos = core.parse_relative_pos(param)
if success then
core.localplayer:set_pos(pos)
return true, "Teleporting to " .. core.pos_to_string(pos)
end
return false, pos
end,
})
core.register_chatcommand("wielded", { core.register_chatcommand("wielded", {
description = "Print itemstring of wieleded item", description = "Print itemstring of wieleded item",
func = function() func = function()
return true, core.localplayer:get_wielded_item():get_name() return true, core.localplayer:get_wielded_item():to_string()
end end
}) })
@ -174,7 +161,7 @@ core.register_chatcommand("setyaw", {
core.localplayer:set_yaw(yaw) core.localplayer:set_yaw(yaw)
return true return true
else else
return false, "Invalid usage (See /help setyaw)" return false, "Invalid usage (See .help setyaw)"
end end
end end
}) })
@ -188,7 +175,10 @@ core.register_chatcommand("setpitch", {
core.localplayer:set_pitch(pitch) core.localplayer:set_pitch(pitch)
return true return true
else else
return false, "Invalid usage (See /help setpitch)" return false, "Invalid usage (See .help setpitch)"
end end
end end
}) })
core.register_list_command("xray", "Configure X-Ray", "xray_nodes")
core.register_list_command("search", "Configure NodeESP", "node_esp_nodes")

View File

@ -1,7 +1,6 @@
core.cheats = { core.cheats = {
["Combat"] = { ["Combat"] = {
["AntiKnockback"] = "antiknockback", ["AntiKnockback"] = "antiknockback",
["FastHit"] = "spamclick",
["AttachmentFloat"] = "float_above_parent", ["AttachmentFloat"] = "float_above_parent",
["ThroughWalls"] = "dont_point_nodes", ["ThroughWalls"] = "dont_point_nodes",
["AutoHit"] = "autohit", ["AutoHit"] = "autohit",
@ -37,16 +36,16 @@ core.cheats = {
["NodeESP"] = "enable_node_esp", ["NodeESP"] = "enable_node_esp",
["NodeTracers"] = "enable_node_tracers", ["NodeTracers"] = "enable_node_tracers",
}, },
["World"] = { ["Interact"] = {
["FastDig"] = "fastdig", ["FastDig"] = "fastdig",
["FastPlace"] = "fastplace", ["FastPlace"] = "fastplace",
["AutoDig"] = "autodig", ["AutoDig"] = "autodig",
["AutoPlace"] = "autoplace", ["AutoPlace"] = "autoplace",
["InstantBreak"] = "instant_break", ["InstantBreak"] = "instant_break",
["FastHit"] = "spamclick",
}, },
["Exploit"] = { ["Exploit"] = {
["EntitySpeed"] = "entity_speed", ["EntitySpeed"] = "entity_speed",
["ParticleExploit"] = "log_particles",
}, },
["Chat"] = { ["Chat"] = {
["IgnoreStatus"] = "ignore_status_messages", ["IgnoreStatus"] = "ignore_status_messages",
@ -55,12 +54,11 @@ core.cheats = {
["Player"] = { ["Player"] = {
["NoFallDamage"] = "prevent_natural_damage", ["NoFallDamage"] = "prevent_natural_damage",
["NoForceRotate"] = "no_force_rotate", ["NoForceRotate"] = "no_force_rotate",
["IncreasedRange"] = "increase_tool_range", ["Reach"] = "reach",
["UnlimitedRange"] = "increase_tool_range_plus",
["PointLiquids"] = "point_liquids", ["PointLiquids"] = "point_liquids",
["PrivBypass"] = "priv_bypass", ["PrivBypass"] = "priv_bypass",
["AutoRespawn"] = "autorespawn",
}, },
["Chat"] = {},
["Inventory"] = {} ["Inventory"] = {}
} }

View File

@ -0,0 +1,38 @@
local death_formspec = ""
.. "size[11,5.5]"
.. "bgcolor[#320000b4;true]"
.. "label[4.85,1.35;" .. "You died" .. "]"
.. "button_exit[2,3;3,0.5;btn_respawn;" .. "Respawn" .. "]"
.. "button_exit[6,3;3,0.5;btn_ghost_mode;" .. "Ghost Mode" .. "]"
.. "set_focus[btn_respawn;true]"
core.register_on_death(function()
core.display_chat_message("You died at " .. core.pos_to_string(vector.round(core.localplayer:get_pos())) .. ".")
if core.settings:get_bool("autorespawn") then
core.send_respawn()
else
core.show_formspec("bultin:death", death_formspec)
end
end)
core.register_on_formspec_input(function(formname, fields)
if formname == "bultin:death" then
if fields.btn_ghost_mode then
core.display_chat_message("You are in ghost mode. Use .respawn to Respawn.")
else
core.send_respawn()
end
end
end)
core.register_chatcommand("respawn", {
description = "Respawn when in ghost mode",
func = function()
if core.localplayer:get_hp() == 0 then
core.send_respawn()
core.display_chat_message("Respawned.")
else
core.display_chat_message("You are not in ghost mode.")
end
end
})

View File

@ -11,3 +11,4 @@ dofile(clientpath .. "util.lua")
dofile(clientpath .. "chatcommands.lua") dofile(clientpath .. "chatcommands.lua")
dofile(clientpath .. "cheats.lua") dofile(clientpath .. "cheats.lua")
dofile(clientpath .. "wasplib.lua") dofile(clientpath .. "wasplib.lua")
dofile(clientpath .. "death_formspec.lua")

View File

@ -110,3 +110,10 @@ core.registered_on_play_sound, core.register_on_play_sound = make_registration()
core.registered_on_spawn_particle, core.register_on_spawn_particle = make_registration() core.registered_on_spawn_particle, core.register_on_spawn_particle = make_registration()
core.registered_on_sending_inventory_fields, core.register_on_sending_inventory_fields = make_registration() core.registered_on_sending_inventory_fields, core.register_on_sending_inventory_fields = make_registration()
core.registered_on_sending_nodemeta_fields, core.register_on_sending_nodemeta_fields = make_registration() core.registered_on_sending_nodemeta_fields, core.register_on_sending_nodemeta_fields = make_registration()
core.registered_on_object_properties_change, core.register_on_object_properties_change = make_registration()
core.registered_on_object_hp_change, core.register_on_object_hp_change = make_registration()
core.registered_on_object_add, core.register_on_object_add = make_registration()
core.registered_nodes = {}
core.registered_items = {}
core.object_refs = {}

View File

@ -44,3 +44,27 @@ end
function core.close_formspec(formname) function core.close_formspec(formname)
return core.show_formspec(formname, "") return core.show_formspec(formname, "")
end end
function core.get_nearby_objects(radius)
return core.get_objects_inside_radius(core.localplayer:get_pos(), radius)
end
-- HTTP callback interface
function core.http_add_fetch(httpenv)
httpenv.fetch = function(req, callback)
local handle = httpenv.fetch_async(req)
local function update_http_status()
local res = httpenv.fetch_async_get(handle)
if res.completed then
callback(res)
else
core.after(0, update_http_status)
end
end
core.after(0, update_http_status)
end
return httpenv
end

View File

@ -1,5 +1,9 @@
-- Minetest: builtin/common/chatcommands.lua -- Minetest: builtin/common/chatcommands.lua
-- For server-side translations (if INIT == "game")
-- Otherwise, use core.gettext
local S = core.get_translator("__builtin")
core.registered_chatcommands = {} core.registered_chatcommands = {}
function core.register_chatcommand(cmd, def) function core.register_chatcommand(cmd, def)
@ -49,7 +53,7 @@ if INIT == "client" then
local i = table.indexof(list, item) local i = table.indexof(list, item)
if i == -1 then if i == -1 then
return false, item .. " is not on the list." return false, item .. " is not on the list."
else else
table.remove(list, i) table.remove(list, i)
core.settings:set(setting, table.concat(list, ",")) core.settings:set(setting, table.concat(list, ","))
return true, "Removed " .. item .. " from the list." return true, "Removed " .. item .. " from the list."
@ -74,25 +78,12 @@ if INIT == "client" then
end end
end end
local cmd_marker = "/"
local function gettext(...)
return ...
end
local function gettext_replace(text, replace)
return text:gsub("$1", replace)
end
if INIT == "client" then
cmd_marker = "."
gettext = core.gettext
gettext_replace = fgettext_ne
end
local function do_help_cmd(name, param) local function do_help_cmd(name, param)
local function format_help_line(cmd, def) local function format_help_line(cmd, def)
local cmd_marker = "/"
if INIT == "client" then
cmd_marker = "."
end
local msg = core.colorize("#00ffff", cmd_marker .. cmd) local msg = core.colorize("#00ffff", cmd_marker .. cmd)
if def.params and def.params ~= "" then if def.params and def.params ~= "" then
msg = msg .. " " .. def.params msg = msg .. " " .. def.params
@ -110,9 +101,21 @@ local function do_help_cmd(name, param)
end end
end end
table.sort(cmds) table.sort(cmds)
return true, gettext("Available commands: ") .. table.concat(cmds, " ") .. "\n" local msg
.. gettext_replace("Use '$1help <cmd>' to get more information," if INIT == "game" then
.. " or '$1help all' to list everything.", cmd_marker) msg = S("Available commands: @1",
table.concat(cmds, " ")) .. "\n"
.. S("Use '/help <cmd>' to get more "
.. "information, or '/help all' to list "
.. "everything.")
else
msg = core.gettext("Available commands: ")
.. table.concat(cmds, " ") .. "\n"
.. core.gettext("Use '.help <cmd>' to get more "
.. "information, or '.help all' to list "
.. "everything.")
end
return true, msg
elseif param == "all" then elseif param == "all" then
local cmds = {} local cmds = {}
for cmd, def in pairs(core.registered_chatcommands) do for cmd, def in pairs(core.registered_chatcommands) do
@ -121,19 +124,31 @@ local function do_help_cmd(name, param)
end end
end end
table.sort(cmds) table.sort(cmds)
return true, gettext("Available commands:").."\n"..table.concat(cmds, "\n") local msg
if INIT == "game" then
msg = S("Available commands:")
else
msg = core.gettext("Available commands:")
end
return true, msg.."\n"..table.concat(cmds, "\n")
elseif INIT == "game" and param == "privs" then elseif INIT == "game" and param == "privs" then
local privs = {} local privs = {}
for priv, def in pairs(core.registered_privileges) do for priv, def in pairs(core.registered_privileges) do
privs[#privs + 1] = priv .. ": " .. def.description privs[#privs + 1] = priv .. ": " .. def.description
end end
table.sort(privs) table.sort(privs)
return true, "Available privileges:\n"..table.concat(privs, "\n") return true, S("Available privileges:").."\n"..table.concat(privs, "\n")
else else
local cmd = param local cmd = param
local def = core.registered_chatcommands[cmd] local def = core.registered_chatcommands[cmd]
if not def then if not def then
return false, gettext("Command not available: ")..cmd local msg
if INIT == "game" then
msg = S("Command not available: @1", cmd)
else
msg = core.gettext("Command not available: ") .. cmd
end
return false, msg
else else
return true, format_help_line(cmd, def) return true, format_help_line(cmd, def)
end end
@ -142,8 +157,8 @@ end
if INIT == "client" then if INIT == "client" then
core.register_chatcommand("help", { core.register_chatcommand("help", {
params = gettext("[all | <cmd>]"), params = core.gettext("[all | <cmd>]"),
description = gettext("Get help for commands"), description = core.gettext("Get help for commands"),
func = function(param) func = function(param)
return do_help_cmd(nil, param) return do_help_cmd(nil, param)
end, end,
@ -193,8 +208,8 @@ if INIT == "client" then
end end
else else
core.register_chatcommand("help", { core.register_chatcommand("help", {
params = "[all | privs | <cmd>]", params = S("[all | privs | <cmd>]"),
description = "Get help for commands or list privileges", description = S("Get help for commands or list privileges"),
func = do_help_cmd, func = do_help_cmd,
}) })
end end

View File

@ -20,7 +20,8 @@ local LIST_FORMSPEC_DESCRIPTION = [[
button_exit[5,7;3,1;quit;%s] button_exit[5,7;3,1;quit;%s]
]] ]]
local formspec_escape = core.formspec_escape local F = core.formspec_escape
local S = core.get_translator("__builtin")
local check_player_privs = core.check_player_privs local check_player_privs = core.check_player_privs
@ -51,22 +52,23 @@ core.after(0, load_mod_command_tree)
local function build_chatcommands_formspec(name, sel, copy) local function build_chatcommands_formspec(name, sel, copy)
local rows = {} local rows = {}
rows[1] = "#FFF,0,Command,Parameters" rows[1] = "#FFF,0,"..F(S("Command"))..","..F(S("Parameters"))
local description = "For more information, click on any entry in the list.\n" .. local description = S("For more information, click on "
"Double-click to copy the entry to the chat history." .. "any entry in the list.").. "\n" ..
S("Double-click to copy the entry to the chat history.")
for i, data in ipairs(mod_cmds) do for i, data in ipairs(mod_cmds) do
rows[#rows + 1] = COLOR_BLUE .. ",0," .. formspec_escape(data[1]) .. "," rows[#rows + 1] = COLOR_BLUE .. ",0," .. F(data[1]) .. ","
for j, cmds in ipairs(data[2]) do for j, cmds in ipairs(data[2]) do
local has_priv = check_player_privs(name, cmds[2].privs) local has_priv = check_player_privs(name, cmds[2].privs)
rows[#rows + 1] = ("%s,1,%s,%s"):format( rows[#rows + 1] = ("%s,1,%s,%s"):format(
has_priv and COLOR_GREEN or COLOR_GRAY, has_priv and COLOR_GREEN or COLOR_GRAY,
cmds[1], formspec_escape(cmds[2].params)) cmds[1], F(cmds[2].params))
if sel == #rows then if sel == #rows then
description = cmds[2].description description = cmds[2].description
if copy then if copy then
core.chat_send_player(name, ("Command: %s %s"):format( core.chat_send_player(name, S("Command: @1 @2",
core.colorize("#0FF", "/" .. cmds[1]), cmds[2].params)) core.colorize("#0FF", "/" .. cmds[1]), cmds[2].params))
end end
end end
@ -74,9 +76,9 @@ local function build_chatcommands_formspec(name, sel, copy)
end end
return LIST_FORMSPEC_DESCRIPTION:format( return LIST_FORMSPEC_DESCRIPTION:format(
"Available commands: (see also: /help <cmd>)", F(S("Available commands: (see also: /help <cmd>)")),
table.concat(rows, ","), sel or 0, table.concat(rows, ","), sel or 0,
description, "Close" F(description), F(S("Close"))
) )
end end
@ -91,19 +93,19 @@ local function build_privs_formspec(name)
table.sort(privs, function(a, b) return a[1] < b[1] end) table.sort(privs, function(a, b) return a[1] < b[1] end)
local rows = {} local rows = {}
rows[1] = "#FFF,0,Privilege,Description" rows[1] = "#FFF,0,"..F(S("Privilege"))..","..F(S("Description"))
local player_privs = core.get_player_privs(name) local player_privs = core.get_player_privs(name)
for i, data in ipairs(privs) do for i, data in ipairs(privs) do
rows[#rows + 1] = ("%s,0,%s,%s"):format( rows[#rows + 1] = ("%s,0,%s,%s"):format(
player_privs[data[1]] and COLOR_GREEN or COLOR_GRAY, player_privs[data[1]] and COLOR_GREEN or COLOR_GRAY,
data[1], formspec_escape(data[2].description)) data[1], F(data[2].description))
end end
return LIST_FORMSPEC:format( return LIST_FORMSPEC:format(
"Available privileges:", F(S("Available privileges:")),
table.concat(rows, ","), table.concat(rows, ","),
"Close" F(S("Close"))
) )
end end
@ -115,7 +117,7 @@ core.register_on_player_receive_fields(function(player, formname, fields)
return return
end end
local event = minetest.explode_table_event(fields.list) local event = core.explode_table_event(fields.list)
if event.type ~= "INV" then if event.type ~= "INV" then
local name = player:get_player_name() local name = player:get_player_name()
core.show_formspec(name, "__builtin:help_cmds", core.show_formspec(name, "__builtin:help_cmds",

View File

@ -244,6 +244,15 @@ function math.factorial(x)
return v return v
end end
function math.round(x)
if x >= 0 then
return math.floor(x + 0.5)
end
return math.ceil(x - 0.5)
end
function core.formspec_escape(text) function core.formspec_escape(text)
if text ~= nil then if text ~= nil then
text = string.gsub(text,"\\","\\\\") text = string.gsub(text,"\\","\\\\")
@ -516,6 +525,7 @@ function table.shuffle(t, from, to, random)
end end
end end
function table.combine(t, other) function table.combine(t, other)
other = other or {} other = other or {}
for k, v in pairs(other) do for k, v in pairs(other) do
@ -595,22 +605,21 @@ function core.colorize(color, message)
end end
local function rgb_to_hex(rgb) local function rgb_to_hex(rgb)
local hexadecimal = '#' local hexadecimal = "#"
for key, value in pairs(rgb) do for key, value in pairs(rgb) do
local hex = '' local hex = ""
while(value > 0)do while(value > 0)do
local index = math.fmod(value, 16) + 1 local index = math.fmod(value, 16) + 1
value = math.floor(value / 16) value = math.floor(value / 16)
hex = string.sub('0123456789ABCDEF', index, index) .. hex hex = string.sub("0123456789ABCDEF", index, index) .. hex
end end
if(string.len(hex) == 0)then if(string.len(hex) == 0)then
hex = '00' hex = "00"
elseif(string.len(hex) == 1)then elseif(string.len(hex) == 1)then
hex = '0' .. hex hex = "0" .. hex
end end
hexadecimal = hexadecimal .. hex hexadecimal = hexadecimal .. hex
@ -622,21 +631,21 @@ end
local function color_from_hue(hue) local function color_from_hue(hue)
local h = hue / 60 local h = hue / 60
local c = 255 local c = 255
local x = (1 - math.abs(h%2 - 1)) * 255 local x = (1 - math.abs(h % 2 - 1)) * 255
local i = math.floor(h); local i = math.floor(h)
if (i == 0) then if i == 0 then
return rgb_to_hex({c, x, 0}) return rgb_to_hex({c, x, 0})
elseif (i == 1) then elseif i == 1 then
return rgb_to_hex({x, c, 0}) return rgb_to_hex({x, c, 0})
elseif (i == 2) then elseif i == 2 then
return rgb_to_hex({0, c, x}) return rgb_to_hex({0, c, x})
elseif (i == 3) then elseif i == 3 then
return rgb_to_hex({0, x, c}); return rgb_to_hex({0, x, c})
elseif (i == 4) then elseif i == 4 then
return rgb_to_hex({x, 0, c}); return rgb_to_hex({x, 0, c})
else else
return rgb_to_hex({c, 0, x}); return rgb_to_hex({c, 0, x})
end end
end end
@ -645,13 +654,13 @@ function core.rainbow(input)
local hue = 0 local hue = 0
local output = "" local output = ""
for i = 1, input:len() do for i = 1, input:len() do
local char = input:sub(i,i) local char = input:sub(i, i)
if char:match("%s") then if char:match("%s") then
output = output .. char output = output .. char
else else
output = output .. core.get_color_escape_sequence(color_from_hue(hue)) .. char output = output .. core.get_color_escape_sequence(color_from_hue(hue)) .. char
end end
hue = hue + step hue = hue + step
end end
return output return output
end end
@ -781,3 +790,16 @@ function core.privs_to_string(privs, delim)
end end
return table.concat(list, delim) return table.concat(list, delim)
end end
function core.is_nan(number)
return number ~= number
end
function core.inventorycube(img1, img2, img3)
img2 = img2 or img1
img3 = img3 or img1
return "[inventorycube"
.. "{" .. img1:gsub("%^", "&")
.. "{" .. img2:gsub("%^", "&")
.. "{" .. img3:gsub("%^", "&")
end

View File

@ -48,6 +48,25 @@ describe("vector", function()
assert.same({ x = 41, y = 52, z = 63 }, vector.offset(vector.new(1, 2, 3), 40, 50, 60)) assert.same({ x = 41, y = 52, z = 63 }, vector.offset(vector.new(1, 2, 3), 40, 50, 60))
end) end)
it("to_string()", function()
local v = vector.new(1, 2, 3.14)
assert.same("(1, 2, 3.14)", vector.to_string(v))
end)
it("from_string()", function()
local v = vector.new(1, 2, 3.14)
assert.same({v, 13}, {vector.from_string("(1, 2, 3.14)")})
assert.same({v, 12}, {vector.from_string("(1,2 ,3.14)")})
assert.same({v, 12}, {vector.from_string("(1,2,3.14,)")})
assert.same({v, 11}, {vector.from_string("(1 2 3.14)")})
assert.same({v, 15}, {vector.from_string("( 1, 2, 3.14 )")})
assert.same({v, 15}, {vector.from_string(" ( 1, 2, 3.14) ")})
assert.same({vector.new(), 8}, {vector.from_string("(0,0,0) ( 1, 2, 3.14) ")})
assert.same({v, 22}, {vector.from_string("(0,0,0) ( 1, 2, 3.14) ", 8)})
assert.same({v, 22}, {vector.from_string("(0,0,0) ( 1, 2, 3.14) ", 9)})
assert.same(nil, vector.from_string("nothing"))
end)
-- This function is needed because of floating point imprecision. -- This function is needed because of floating point imprecision.
local function almost_equal(a, b) local function almost_equal(a, b)
if type(a) == "number" then if type(a) == "number" then

View File

@ -12,6 +12,22 @@ function vector.new(a, b, c)
return {x=0, y=0, z=0} return {x=0, y=0, z=0}
end end
function vector.from_string(s, init)
local x, y, z, np = string.match(s, "^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]" ..
"%s*([^%s,]+)%s*[,%s]?%s*%)()", init)
x = tonumber(x)
y = tonumber(y)
z = tonumber(z)
if not (x and y and z) then
return nil
end
return {x = x, y = y, z = z}, np
end
function vector.to_string(v)
return string.format("(%g, %g, %g)", v.x, v.y, v.z)
end
function vector.equals(a, b) function vector.equals(a, b)
return a.x == b.x and return a.x == b.x and
a.y == b.y and a.y == b.y and
@ -41,9 +57,9 @@ end
function vector.round(v) function vector.round(v)
return { return {
x = math.floor(v.x + 0.5), x = math.round(v.x),
y = math.floor(v.y + 0.5), y = math.round(v.y),
z = math.floor(v.z + 0.5) z = math.round(v.z)
} }
end end

View File

@ -58,26 +58,20 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local function get_formspec(self) local function get_formspec(self)
local formspec = "" if self.hidden or (self.parent ~= nil and self.parent.hidden) then
return ""
if not self.hidden and (self.parent == nil or not self.parent.hidden) then
if self.parent == nil then
local tsize = self.tablist[self.last_tab_index].tabsize or
{width=self.width, height=self.height}
formspec = formspec ..
string.format("size[%f,%f,%s]",tsize.width,tsize.height,
dump(self.fixed_size))
end
formspec = formspec .. self:tab_header()
formspec = formspec ..
self.tablist[self.last_tab_index].get_formspec(
self,
self.tablist[self.last_tab_index].name,
self.tablist[self.last_tab_index].tabdata,
self.tablist[self.last_tab_index].tabsize
)
end end
local tab = self.tablist[self.last_tab_index]
local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize)
if self.parent == nil and not prepend then
local tsize = tab.tabsize or {width=self.width, height=self.height}
prepend = string.format("size[%f,%f,%s]", tsize.width, tsize.height,
dump(self.fixed_size))
end
local formspec = (prepend or "") .. self:tab_header() .. content
return formspec return formspec
end end
@ -97,14 +91,9 @@ local function handle_buttons(self,fields)
return true return true
end end
if self.tablist[self.last_tab_index].button_handler ~= nil then local tab = self.tablist[self.last_tab_index]
return if tab.button_handler ~= nil then
self.tablist[self.last_tab_index].button_handler( return tab.button_handler(self, fields, tab.name, tab.tabdata)
self,
fields,
self.tablist[self.last_tab_index].name,
self.tablist[self.last_tab_index].tabdata
)
end end
return false return false
@ -122,14 +111,9 @@ local function handle_events(self,event)
return true return true
end end
if self.tablist[self.last_tab_index].evt_handler ~= nil then local tab = self.tablist[self.last_tab_index]
return if tab.evt_handler ~= nil then
self.tablist[self.last_tab_index].evt_handler( return tab.evt_handler(self, event, tab.name, tab.tabdata)
self,
event,
self.tablist[self.last_tab_index].name,
self.tablist[self.last_tab_index].tabdata
)
end end
return false return false

View File

@ -18,6 +18,8 @@
ui = {} ui = {}
ui.childlist = {} ui.childlist = {}
ui.default = nil ui.default = nil
-- Whether fstk is currently showing its own formspec instead of active ui elements.
ui.overridden = false
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
function ui.add(child) function ui.add(child)
@ -55,6 +57,7 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
function ui.update() function ui.update()
ui.overridden = false
local formspec = {} local formspec = {}
-- handle errors -- handle errors
@ -71,6 +74,7 @@ function ui.update()
"button[2,6.6;4,1;btn_reconnect_yes;" .. fgettext("Reconnect") .. "]", "button[2,6.6;4,1;btn_reconnect_yes;" .. fgettext("Reconnect") .. "]",
"button[8,6.6;4,1;btn_reconnect_no;" .. fgettext("Main menu") .. "]" "button[8,6.6;4,1;btn_reconnect_no;" .. fgettext("Main menu") .. "]"
} }
ui.overridden = true
elseif gamedata ~= nil and gamedata.errormessage ~= nil then elseif gamedata ~= nil and gamedata.errormessage ~= nil then
local error_message = core.formspec_escape(gamedata.errormessage) local error_message = core.formspec_escape(gamedata.errormessage)
@ -89,6 +93,7 @@ function ui.update()
error_title, error_message), error_title, error_message),
"button[5,6.6;4,1;btn_error_confirm;" .. fgettext("OK") .. "]" "button[5,6.6;4,1;btn_error_confirm;" .. fgettext("OK") .. "]"
} }
ui.overridden = true
else else
local active_toplevel_ui_elements = 0 local active_toplevel_ui_elements = 0
for key,value in pairs(ui.childlist) do for key,value in pairs(ui.childlist) do
@ -185,6 +190,16 @@ end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
core.event_handler = function(event) core.event_handler = function(event)
-- Handle error messages
if ui.overridden then
if event == "MenuQuit" then
gamedata.errormessage = nil
gamedata.reconnect_requested = false
ui.update()
end
return
end
if ui.handle_events(event) then if ui.handle_events(event) then
ui.update() ui.update()
return return

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,5 @@
-- Minetest: builtin/deprecated.lua -- Minetest: builtin/deprecated.lua
--
-- Default material types
--
local function digprop_err()
core.log("deprecated", "The core.digprop_* functions are obsolete and need to be replaced by item groups.")
end
core.digprop_constanttime = digprop_err
core.digprop_stonelike = digprop_err
core.digprop_dirtlike = digprop_err
core.digprop_gravellike = digprop_err
core.digprop_woodlike = digprop_err
core.digprop_leaveslike = digprop_err
core.digprop_glasslike = digprop_err
function core.node_metadata_inventory_move_allow_all()
core.log("deprecated", "core.node_metadata_inventory_move_allow_all is obsolete and does nothing.")
end
function core.add_to_creative_inventory(itemstring)
core.log("deprecated", "core.add_to_creative_inventory is obsolete and does nothing.")
end
-- --
-- EnvRef -- EnvRef
-- --
@ -77,7 +54,7 @@ core.setting_save = setting_proxy("write")
function core.register_on_auth_fail(func) function core.register_on_auth_fail(func)
core.log("deprecated", "core.register_on_auth_fail " .. core.log("deprecated", "core.register_on_auth_fail " ..
"is obsolete and should be replaced by " .. "is deprecated and should be replaced by " ..
"core.register_on_authplayer instead.") "core.register_on_authplayer instead.")
core.register_on_authplayer(function (player_name, ip, is_success) core.register_on_authplayer(function (player_name, ip, is_success)

View File

@ -84,9 +84,6 @@ core.register_entity(":__builtin:falling_node", {
local textures local textures
if def.tiles and def.tiles[1] then if def.tiles and def.tiles[1] then
local tile = def.tiles[1] local tile = def.tiles[1]
if def.drawtype == "torchlike" and def.paramtype2 ~= "wallmounted" then
tile = def.tiles[2] or def.tiles[1]
end
if type(tile) == "table" then if type(tile) == "table" then
tile = tile.name tile = tile.name
end end
@ -130,7 +127,7 @@ core.register_entity(":__builtin:falling_node", {
-- Set collision box (certain nodeboxes only for now) -- Set collision box (certain nodeboxes only for now)
local nb_types = {fixed=true, leveled=true, connected=true} local nb_types = {fixed=true, leveled=true, connected=true}
if def.drawtype == "nodebox" and def.node_box and if def.drawtype == "nodebox" and def.node_box and
nb_types[def.node_box.type] then nb_types[def.node_box.type] and def.node_box.fixed then
local box = table.copy(def.node_box.fixed) local box = table.copy(def.node_box.fixed)
if type(box[1]) == "table" then if type(box[1]) == "table" then
box = #box == 1 and box[1] or nil -- We can only use a single box box = #box == 1 and box[1] or nil -- We can only use a single box
@ -147,13 +144,9 @@ core.register_entity(":__builtin:falling_node", {
-- Rotate entity -- Rotate entity
if def.drawtype == "torchlike" then if def.drawtype == "torchlike" then
if def.paramtype2 == "wallmounted" then self.object:set_yaw(math.pi*0.25)
self.object:set_yaw(math.pi*0.25) elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
else and (def.wield_image == "" or def.wield_image == nil))
self.object:set_yaw(-math.pi*0.25)
end
elseif (node.param2 ~= 0 and (def.wield_image == ""
or def.wield_image == nil))
or def.drawtype == "signlike" or def.drawtype == "signlike"
or def.drawtype == "mesh" or def.drawtype == "mesh"
or def.drawtype == "normal" or def.drawtype == "normal"
@ -165,19 +158,37 @@ core.register_entity(":__builtin:falling_node", {
if euler then if euler then
self.object:set_rotation(euler) self.object:set_rotation(euler)
end end
elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted") then elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" or def.drawtype == "signlike") then
local rot = node.param2 % 8 local rot = node.param2 % 8
if (def.drawtype == "signlike" and def.paramtype2 ~= "wallmounted" and def.paramtype2 ~= "colorwallmounted") then
-- Change rotation to "floor" by default for non-wallmounted paramtype2
rot = 1
end
local pitch, yaw, roll = 0, 0, 0 local pitch, yaw, roll = 0, 0, 0
if rot == 1 then if def.drawtype == "nodebox" or def.drawtype == "mesh" then
pitch, yaw = math.pi, math.pi if rot == 0 then
elseif rot == 2 then pitch, yaw = math.pi/2, 0
pitch, yaw = math.pi/2, math.pi/2 elseif rot == 1 then
elseif rot == 3 then pitch, yaw = -math.pi/2, math.pi
pitch, yaw = math.pi/2, -math.pi/2 elseif rot == 2 then
elseif rot == 4 then pitch, yaw = 0, math.pi/2
pitch, yaw = math.pi/2, math.pi elseif rot == 3 then
elseif rot == 5 then pitch, yaw = 0, -math.pi/2
pitch, yaw = math.pi/2, 0 elseif rot == 4 then
pitch, yaw = 0, math.pi
end
else
if rot == 1 then
pitch, yaw = math.pi, math.pi
elseif rot == 2 then
pitch, yaw = math.pi/2, math.pi/2
elseif rot == 3 then
pitch, yaw = math.pi/2, -math.pi/2
elseif rot == 4 then
pitch, yaw = math.pi/2, math.pi
elseif rot == 5 then
pitch, yaw = math.pi/2, 0
end
end end
if def.drawtype == "signlike" then if def.drawtype == "signlike" then
pitch = pitch - math.pi/2 pitch = pitch - math.pi/2
@ -186,7 +197,7 @@ core.register_entity(":__builtin:falling_node", {
elseif rot == 1 then elseif rot == 1 then
yaw = yaw - math.pi/2 yaw = yaw - math.pi/2
end end
elseif def.drawtype == "mesh" or def.drawtype == "normal" then elseif def.drawtype == "mesh" or def.drawtype == "normal" or def.drawtype == "nodebox" then
if rot >= 0 and rot <= 1 then if rot >= 0 and rot <= 1 then
roll = roll + math.pi roll = roll + math.pi
else else
@ -194,6 +205,14 @@ core.register_entity(":__builtin:falling_node", {
end end
end end
self.object:set_rotation({x=pitch, y=yaw, z=roll}) self.object:set_rotation({x=pitch, y=yaw, z=roll})
elseif (def.drawtype == "mesh" and def.paramtype2 == "degrotate") then
local p2 = (node.param2 - (def.place_param2 or 0)) % 240
local yaw = (p2 / 240) * (math.pi * 2)
self.object:set_yaw(yaw)
elseif (def.drawtype == "mesh" and def.paramtype2 == "colordegrotate") then
local p2 = (node.param2 % 32 - (def.place_param2 or 0) % 32) % 24
local yaw = (p2 / 24) * (math.pi * 2)
self.object:set_yaw(yaw)
end end
end end
end, end,
@ -393,7 +412,7 @@ local function convert_to_falling_node(pos, node)
obj:get_luaentity():set_node(node, metatable) obj:get_luaentity():set_node(node, metatable)
core.remove_node(pos) core.remove_node(pos)
return true return true, obj
end end
function core.spawn_falling_node(pos) function core.spawn_falling_node(pos)

View File

@ -18,6 +18,8 @@ core.features = {
pathfinder_works = true, pathfinder_works = true,
object_step_has_moveresult = true, object_step_has_moveresult = true,
direct_velocity_on_players = true, direct_velocity_on_players = true,
use_texture_alpha_string_modes = true,
degrotate_240_steps = true,
} }
function core.has_feature(arg) function core.has_feature(arg)

View File

@ -15,15 +15,6 @@ end
-- Item definition helpers -- Item definition helpers
-- --
function core.inventorycube(img1, img2, img3)
img2 = img2 or img1
img3 = img3 or img1
return "[inventorycube"
.. "{" .. img1:gsub("%^", "&")
.. "{" .. img2:gsub("%^", "&")
.. "{" .. img3:gsub("%^", "&")
end
function core.dir_to_facedir(dir, is6d) function core.dir_to_facedir(dir, is6d)
--account for y if requested --account for y if requested
if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
@ -144,7 +135,7 @@ end
function core.is_colored_paramtype(ptype) function core.is_colored_paramtype(ptype)
return (ptype == "color") or (ptype == "colorfacedir") or return (ptype == "color") or (ptype == "colorfacedir") or
(ptype == "colorwallmounted") (ptype == "colorwallmounted") or (ptype == "colordegrotate")
end end
function core.strip_param2_color(param2, paramtype2) function core.strip_param2_color(param2, paramtype2)
@ -155,6 +146,8 @@ function core.strip_param2_color(param2, paramtype2)
param2 = math.floor(param2 / 32) * 32 param2 = math.floor(param2 / 32) * 32
elseif paramtype2 == "colorwallmounted" then elseif paramtype2 == "colorwallmounted" then
param2 = math.floor(param2 / 8) * 8 param2 = math.floor(param2 / 8) * 8
elseif paramtype2 == "colordegrotate" then
param2 = math.floor(param2 / 32) * 32
end end
-- paramtype2 == "color" requires no modification. -- paramtype2 == "color" requires no modification.
return param2 return param2
@ -332,6 +325,8 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
color_divisor = 8 color_divisor = 8
elseif def.paramtype2 == "colorfacedir" then elseif def.paramtype2 == "colorfacedir" then
color_divisor = 32 color_divisor = 32
elseif def.paramtype2 == "colordegrotate" then
color_divisor = 32
end end
if color_divisor then if color_divisor then
local color = math.floor(metatable.palette_index / color_divisor) local color = math.floor(metatable.palette_index / color_divisor)
@ -544,7 +539,7 @@ function core.node_dig(pos, node, digger)
log("info", diggername .. " tried to dig " log("info", diggername .. " tried to dig "
.. node.name .. " which is not diggable " .. node.name .. " which is not diggable "
.. core.pos_to_string(pos)) .. core.pos_to_string(pos))
return return false
end end
if core.is_protected(pos, diggername) then if core.is_protected(pos, diggername) then
@ -553,7 +548,7 @@ function core.node_dig(pos, node, digger)
.. " at protected position " .. " at protected position "
.. core.pos_to_string(pos)) .. core.pos_to_string(pos))
core.record_protection_violation(pos, diggername) core.record_protection_violation(pos, diggername)
return return false
end end
log('action', diggername .. " digs " log('action', diggername .. " digs "
@ -636,6 +631,8 @@ function core.node_dig(pos, node, digger)
local node_copy = {name=node.name, param1=node.param1, param2=node.param2} local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
callback(pos_copy, node_copy, digger) callback(pos_copy, node_copy, digger)
end end
return true
end end
function core.itemstring_with_palette(item, palette_index) function core.itemstring_with_palette(item, palette_index)
@ -663,7 +660,7 @@ end
-- Item definition defaults -- Item definition defaults
-- --
local default_stack_max = tonumber(minetest.settings:get("default_stack_max")) or 99 local default_stack_max = tonumber(core.settings:get("default_stack_max")) or 99
core.nodedef_default = { core.nodedef_default = {
-- Item properties -- Item properties
@ -692,10 +689,6 @@ core.nodedef_default = {
on_receive_fields = nil, on_receive_fields = nil,
on_metadata_inventory_move = core.node_metadata_inventory_move_allow_all,
on_metadata_inventory_offer = core.node_metadata_inventory_offer_allow_all,
on_metadata_inventory_take = core.node_metadata_inventory_take_allow_all,
-- Node properties -- Node properties
drawtype = "normal", drawtype = "normal",
visual_scale = 1.0, visual_scale = 1.0,
@ -706,7 +699,6 @@ core.nodedef_default = {
-- {name="", backface_culling=true}, -- {name="", backface_culling=true},
-- {name="", backface_culling=true}, -- {name="", backface_culling=true},
--}, --},
alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0}, post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none", paramtype = "none",
paramtype2 = "none", paramtype2 = "none",

View File

@ -42,5 +42,5 @@ core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool
return -- barely noticeable, so don't even send return -- barely noticeable, so don't even send
end end
player:add_player_velocity(kdir) player:add_velocity(kdir)
end) end)

View File

@ -1,5 +1,7 @@
-- Minetest: builtin/misc.lua -- Minetest: builtin/misc.lua
local S = core.get_translator("__builtin")
-- --
-- Misc. API functions -- Misc. API functions
-- --
@ -42,15 +44,15 @@ end
function core.send_join_message(player_name) function core.send_join_message(player_name)
if not core.is_singleplayer() then if not core.is_singleplayer() then
core.chat_send_all("*** " .. player_name .. " joined the game.") core.chat_send_all("*** " .. S("@1 joined the game.", player_name))
end end
end end
function core.send_leave_message(player_name, timed_out) function core.send_leave_message(player_name, timed_out)
local announcement = "*** " .. player_name .. " left the game." local announcement = "*** " .. S("@1 left the game.", player_name)
if timed_out then if timed_out then
announcement = announcement .. " (timed out)" announcement = "*** " .. S("@1 left the game (timed out).", player_name)
end end
core.chat_send_all(announcement) core.chat_send_all(announcement)
end end
@ -266,3 +268,26 @@ end
function core.cancel_shutdown_requests() function core.cancel_shutdown_requests()
core.request_shutdown("", false, -1) core.request_shutdown("", false, -1)
end end
-- Callback handling for dynamic_add_media
local dynamic_add_media_raw = core.dynamic_add_media_raw
core.dynamic_add_media_raw = nil
function core.dynamic_add_media(filepath, callback)
local ret = dynamic_add_media_raw(filepath)
if ret == false then
return ret
end
if callback == nil then
core.log("deprecated", "Calling minetest.dynamic_add_media without "..
"a callback is deprecated and will stop working in future versions.")
else
-- At the moment async loading is not actually implemented, so we
-- immediately call the callback ourselves
for _, name in ipairs(ret) do
callback(name)
end
end
return true
end

View File

@ -1,5 +1,7 @@
-- Minetest: builtin/privileges.lua -- Minetest: builtin/privileges.lua
local S = core.get_translator("__builtin")
-- --
-- Privileges -- Privileges
-- --
@ -15,7 +17,7 @@ function core.register_privilege(name, param)
def.give_to_admin = def.give_to_singleplayer def.give_to_admin = def.give_to_singleplayer
end end
if def.description == nil then if def.description == nil then
def.description = "(no description)" def.description = S("(no description)")
end end
end end
local def local def
@ -28,69 +30,75 @@ function core.register_privilege(name, param)
core.registered_privileges[name] = def core.registered_privileges[name] = def
end end
core.register_privilege("interact", "Can interact with things and modify the world") core.register_privilege("interact", S("Can interact with things and modify the world"))
core.register_privilege("shout", "Can speak in chat") core.register_privilege("shout", S("Can speak in chat"))
core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privileges")
core.register_privilege("privs", "Can modify privileges") local basic_privs =
core.string_to_privs((core.settings:get("basic_privs") or "shout,interact"))
local basic_privs_desc = S("Can modify basic privileges (@1)",
core.privs_to_string(basic_privs, ', '))
core.register_privilege("basic_privs", basic_privs_desc)
core.register_privilege("privs", S("Can modify privileges"))
core.register_privilege("teleport", { core.register_privilege("teleport", {
description = "Can teleport self", description = S("Can teleport self"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("bring", { core.register_privilege("bring", {
description = "Can teleport other players", description = S("Can teleport other players"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("settime", { core.register_privilege("settime", {
description = "Can set the time of day using /time", description = S("Can set the time of day using /time"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("server", { core.register_privilege("server", {
description = "Can do server maintenance stuff", description = S("Can do server maintenance stuff"),
give_to_singleplayer = false, give_to_singleplayer = false,
give_to_admin = true, give_to_admin = true,
}) })
core.register_privilege("protection_bypass", { core.register_privilege("protection_bypass", {
description = "Can bypass node protection in the world", description = S("Can bypass node protection in the world"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("ban", { core.register_privilege("ban", {
description = "Can ban and unban players", description = S("Can ban and unban players"),
give_to_singleplayer = false, give_to_singleplayer = false,
give_to_admin = true, give_to_admin = true,
}) })
core.register_privilege("kick", { core.register_privilege("kick", {
description = "Can kick players", description = S("Can kick players"),
give_to_singleplayer = false, give_to_singleplayer = false,
give_to_admin = true, give_to_admin = true,
}) })
core.register_privilege("give", { core.register_privilege("give", {
description = "Can use /give and /giveme", description = S("Can use /give and /giveme"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("password", { core.register_privilege("password", {
description = "Can use /setpassword and /clearpassword", description = S("Can use /setpassword and /clearpassword"),
give_to_singleplayer = false, give_to_singleplayer = false,
give_to_admin = true, give_to_admin = true,
}) })
core.register_privilege("fly", { core.register_privilege("fly", {
description = "Can use fly mode", description = S("Can use fly mode"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("fast", { core.register_privilege("fast", {
description = "Can use fast mode", description = S("Can use fast mode"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("noclip", { core.register_privilege("noclip", {
description = "Can fly through solid nodes using noclip mode", description = S("Can fly through solid nodes using noclip mode"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("rollback", { core.register_privilege("rollback", {
description = "Can use the rollback functionality", description = S("Can use the rollback functionality"),
give_to_singleplayer = false, give_to_singleplayer = false,
}) })
core.register_privilege("debug", { core.register_privilege("debug", {
description = "Allows enabling various debug options that may affect gameplay", description = S("Allows enabling various debug options that may affect gameplay"),
give_to_singleplayer = false, give_to_singleplayer = false,
give_to_admin = true, give_to_admin = true,
}) })

View File

@ -1,5 +1,7 @@
-- Minetest: builtin/misc_register.lua -- Minetest: builtin/misc_register.lua
local S = core.get_translator("__builtin")
-- --
-- Make raw registration functions inaccessible to anyone except this file -- Make raw registration functions inaccessible to anyone except this file
-- --
@ -118,10 +120,6 @@ function core.register_item(name, itemdef)
end end
itemdef.name = name itemdef.name = name
-- default short_description to first line of description
itemdef.short_description = itemdef.short_description or
(itemdef.description or ""):gsub("\n.*","")
-- Apply defaults and add to registered_* table -- Apply defaults and add to registered_* table
if itemdef.type == "node" then if itemdef.type == "node" then
-- Use the nodebox as selection box if it's not set manually -- Use the nodebox as selection box if it's not set manually
@ -324,20 +322,13 @@ for name in pairs(forbidden_item_names) do
register_alias_raw(name, "") register_alias_raw(name, "")
end end
-- Obsolete:
-- Aliases for core.register_alias (how ironic...)
-- core.alias_node = core.register_alias
-- core.alias_tool = core.register_alias
-- core.alias_craftitem = core.register_alias
-- --
-- Built-in node definitions. Also defined in C. -- Built-in node definitions. Also defined in C.
-- --
core.register_item(":unknown", { core.register_item(":unknown", {
type = "none", type = "none",
description = "Unknown Item", description = S("Unknown Item"),
inventory_image = "unknown_item.png", inventory_image = "unknown_item.png",
on_place = core.item_place, on_place = core.item_place,
on_secondary_use = core.item_secondary_use, on_secondary_use = core.item_secondary_use,
@ -347,7 +338,7 @@ core.register_item(":unknown", {
}) })
core.register_node(":air", { core.register_node(":air", {
description = "Air", description = S("Air"),
inventory_image = "air.png", inventory_image = "air.png",
wield_image = "air.png", wield_image = "air.png",
drawtype = "airlike", drawtype = "airlike",
@ -364,7 +355,7 @@ core.register_node(":air", {
}) })
core.register_node(":ignore", { core.register_node(":ignore", {
description = "Ignore", description = S("Ignore"),
inventory_image = "ignore.png", inventory_image = "ignore.png",
wield_image = "ignore.png", wield_image = "ignore.png",
drawtype = "airlike", drawtype = "airlike",
@ -377,11 +368,12 @@ core.register_node(":ignore", {
air_equivalent = true, air_equivalent = true,
drop = "", drop = "",
groups = {not_in_creative_inventory=1}, groups = {not_in_creative_inventory=1},
node_placement_prediction = "",
on_place = function(itemstack, placer, pointed_thing) on_place = function(itemstack, placer, pointed_thing)
core.chat_send_player( core.chat_send_player(
placer:get_player_name(), placer:get_player_name(),
core.colorize("#FF0000", core.colorize("#FF0000",
"You can't place 'ignore' nodes!")) S("You can't place 'ignore' nodes!")))
return "" return ""
end, end,
}) })
@ -617,6 +609,7 @@ core.registered_can_bypass_userlimit, core.register_can_bypass_userlimit = make_
core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration() core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
core.registered_on_player_inventory_actions, core.register_on_player_inventory_action = make_registration() core.registered_on_player_inventory_actions, core.register_on_player_inventory_action = make_registration()
core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration() core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration()
core.registered_on_rightclickplayers, core.register_on_rightclickplayer = make_registration()
-- --
-- Compatibility for on_mapgen_init() -- Compatibility for on_mapgen_init()

View File

@ -84,8 +84,8 @@ local function update_builtin_statbars(player)
end end
if hud.id_breathbar and (not show_breathbar or breath == breath_max) then if hud.id_breathbar and (not show_breathbar or breath == breath_max) then
minetest.after(1, function(player_name, breath_bar) core.after(1, function(player_name, breath_bar)
local player = minetest.get_player_by_name(player_name) local player = core.get_player_by_name(player_name)
if player then if player then
player:hud_remove(breath_bar) player:hud_remove(breath_bar)
end end

View File

@ -38,9 +38,20 @@ if INIT == "game" then
dofile(gamepath .. "init.lua") dofile(gamepath .. "init.lua")
elseif INIT == "mainmenu" then elseif INIT == "mainmenu" then
local mm_script = core.settings:get("main_menu_script") local mm_script = core.settings:get("main_menu_script")
local custom_loaded = false
if mm_script and mm_script ~= "" then if mm_script and mm_script ~= "" then
dofile(mm_script) local testfile = io.open(mm_script, "r")
else if testfile then
testfile:close()
dofile(mm_script)
custom_loaded = true
core.log("info", "Loaded custom main menu script: "..mm_script)
else
core.log("error", "Failed to load custom main menu script: "..mm_script)
core.log("info", "Falling back to default main menu script")
end
end
if not custom_loaded then
dofile(core.get_mainmenu_path() .. DIR_DELIM .. "init.lua") dofile(core.get_mainmenu_path() .. DIR_DELIM .. "init.lua")
end end
elseif INIT == "async" then elseif INIT == "async" then

View File

@ -0,0 +1,240 @@
# textdomain: __builtin
Empty command.=Leerer Befehl.
Invalid command: @1=Ungültiger Befehl: @1
Invalid command usage.=Ungültige Befehlsverwendung.
(@1 s)= (@1 s)
Command execution took @1 s=Befehlsausführung brauchte @1 s
You don't have permission to run this command (missing privileges: @1).=Sie haben keine Erlaubnis, diesen Befehl auszuführen (fehlende Privilegien: @1).
Unable to get position of player @1.=Konnte Position vom Spieler @1 nicht ermitteln.
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Ungültiges Gebietsformat. Erwartet: (x1,y1,z1) (x2,y2,z2)
<action>=<Aktion>
Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pizza')=Chataktion zeigen (z.B. wird „/me isst Pizza“ zu „<Spielername> isst Pizza“)
Show the name of the server owner=Den Namen des Servereigentümers zeigen
The administrator of this server is @1.=Der Administrator dieses Servers ist @1.
There's no administrator named in the config file.=In der Konfigurationsdatei wurde kein Administrator angegeben.
@1 does not have any privileges.=@1 hat keine Privilegien.
Privileges of @1: @2=Privilegien von @1: @2
[<name>]=[<Name>]
Show privileges of yourself or another player=Ihre eigenen Privilegien oder die eines anderen Spielers anzeigen
Player @1 does not exist.=Spieler @1 existiert nicht.
<privilege>=<Privileg>
Return list of all online players with privilege=Liste aller Spieler mit einem Privileg ausgeben
Invalid parameters (see /help haspriv).=Ungültige Parameter (siehe „/help haspriv“).
Unknown privilege!=Unbekanntes Privileg!
Players online with the "@1" privilege: @2=Derzeit online spielende Spieler mit dem „@1“-Privileg: @2
Your privileges are insufficient.=Ihre Privilegien sind unzureichend.
Your privileges are insufficient. '@1' only allows you to grant: @2=Ihre Privilegien sind unzureichend. Mit „@1“ können Sie nur folgendes gewähren: @2
Unknown privilege: @1=Unbekanntes Privileg: @1
@1 granted you privileges: @2=@1 gewährte Ihnen Privilegien: @2
<name> (<privilege> [, <privilege2> [<...>]] | all)=<Name> (<Privileg> [, <Privileg2> [<...>]] | all)
Give privileges to player=Privileg an Spieler vergeben
Invalid parameters (see /help grant).=Ungültige Parameter (siehe „/help grant“).
<privilege> [, <privilege2> [<...>]] | all=<Privileg> [, <Privileg2> [<...>]] | all
Grant privileges to yourself=Privilegien an Ihnen selbst vergeben
Invalid parameters (see /help grantme).=Ungültige Parameter (siehe „/help grantme“).
Your privileges are insufficient. '@1' only allows you to revoke: @2=Ihre Privilegien sind unzureichend. Mit „@1“ können Sie nur folgendes entziehen: @2
Note: Cannot revoke in singleplayer: @1=Anmerkung: Im Einzelspielermodus kann man folgendes nicht entziehen: @1
Note: Cannot revoke from admin: @1=Anmerkung: Vom Admin kann man folgendes nicht entziehen: @1
No privileges were revoked.=Es wurden keine Privilegien entzogen.
@1 revoked privileges from you: @2=@1 entfernte Privilegien von Ihnen: @2
Remove privileges from player=Privilegien von Spieler entfernen
Invalid parameters (see /help revoke).=Ungültige Parameter (siehe „/help revoke“).
Revoke privileges from yourself=Privilegien von Ihnen selbst entfernen
Invalid parameters (see /help revokeme).=Ungültige Parameter (siehe „/help revokeme“).
<name> <password>=<Name> <Passwort>
Set player's password=Passwort von Spieler setzen
Name field required.=Namensfeld benötigt.
Your password was cleared by @1.=Ihr Passwort wurde von @1 geleert.
Password of player "@1" cleared.=Passwort von Spieler „@1“ geleert.
Your password was set by @1.=Ihr Passwort wurde von @1 gesetzt.
Password of player "@1" set.=Passwort von Spieler „@1“ gesetzt.
<name>=<Name>
Set empty password for a player=Leeres Passwort für einen Spieler setzen
Reload authentication data=Authentifizierungsdaten erneut laden
Done.=Fertig.
Failed.=Fehlgeschlagen.
Remove a player's data=Daten eines Spielers löschen
Player "@1" removed.=Spieler „@1“ gelöscht.
No such player "@1" to remove.=Es gibt keinen Spieler „@1“, der gelöscht werden könnte.
Player "@1" is connected, cannot remove.=Spieler „@1“ ist verbunden, er kann nicht gelöscht werden.
Unhandled remove_player return code @1.=Nicht berücksichtigter remove_player-Rückgabewert @1.
Cannot teleport out of map bounds!=Eine Teleportation außerhalb der Kartengrenzen ist nicht möglich!
Cannot get player with name @1.=Spieler mit Namen @1 kann nicht gefunden werden.
Cannot teleport, @1 is attached to an object!=Teleportation nicht möglich, @1 ist an einem Objekt befestigt!
Teleporting @1 to @2.=Teleportation von @1 nach @2
One does not teleport to oneself.=Man teleportiert sich doch nicht zu sich selbst.
Cannot get teleportee with name @1.=Der zu teleportierende Spieler mit Namen @1 kann nicht gefunden werden.
Cannot get target player with name @1.=Zielspieler mit Namen @1 kann nicht gefunden werden.
Teleporting @1 to @2 at @3.=Teleportation von @1 zu @2 bei @3
<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>=<X>,<Y>,<Z> | <zu_Name> | <Name> <X>,<Y>,<Z> | <Name> <zu_Name>
Teleport to position or player=Zu Position oder Spieler teleportieren
You don't have permission to teleport other players (missing privilege: @1).=Sie haben nicht die Erlaubnis, andere Spieler zu teleportieren (fehlendes Privileg: @1).
([-n] <name> <value>) | <name>=([-n] <Name> <Wert>) | <Name>
Set or read server configuration setting=Serverkonfigurationseinstellung setzen oder lesen
Failed. Use '/set -n <name> <value>' to create a new setting.=Fehlgeschlagen. Benutzen Sie „/set -n <Name> <Wert>“, um eine neue Einstellung zu erstellen.
@1 @= @2=@1 @= @2
<not set>=<nicht gesetzt>
Invalid parameters (see /help set).=Ungültige Parameter (siehe „/help set“).
Finished emerging @1 blocks in @2ms.=Fertig mit Erzeugung von @1 Blöcken in @2 ms.
emergeblocks update: @1/@2 blocks emerged (@3%)=emergeblocks-Update: @1/@2 Kartenblöcke geladen (@3%)
(here [<radius>]) | (<pos1> <pos2>)=(here [<Radius>]) | (<Pos1> <Pos2>)
Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Lade (oder, wenn nicht existent, generiere) Kartenblöcke im Gebiet zwischen Pos1 und Pos2 (<Pos1> und <Pos2> müssen in Klammern stehen)
Started emerge of area ranging from @1 to @2.=Start des Ladevorgangs des Gebiets zwischen @1 und @2.
Delete map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Kartenblöcke innerhalb des Gebiets zwischen Pos1 und Pos2 löschen (<Pos1> und <Pos2> müssen in Klammern stehen)
Successfully cleared area ranging from @1 to @2.=Gebiet zwischen @1 und @2 erfolgreich geleert.
Failed to clear one or more blocks in area.=Fehlgeschlagen: Ein oder mehrere Kartenblöcke im Gebiet konnten nicht geleert werden.
Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in parentheses)=Setzt das Licht im Gebiet zwischen Pos1 und Pos2 zurück (<Pos1> und <Pos2> müssen in Klammern stehen)
Successfully reset light in the area ranging from @1 to @2.=Das Licht im Gebiet zwischen @1 und @2 wurde erfolgreich zurückgesetzt.
Failed to load one or more blocks in area.=Fehlgeschlagen: Ein oder mehrere Kartenblöcke im Gebiet konnten nicht geladen werden.
List mods installed on the server=Installierte Mods auf dem Server auflisten
Cannot give an empty item.=Ein leerer Gegenstand kann nicht gegeben werden.
Cannot give an unknown item.=Ein unbekannter Gegenstand kann nicht gegeben werden.
Giving 'ignore' is not allowed.=„ignore“ darf nicht gegeben werden.
@1 is not a known player.=@1 ist kein bekannter Spieler.
@1 partially added to inventory.=@1 teilweise ins Inventar eingefügt.
@1 could not be added to inventory.=@1 konnte nicht ins Inventar eingefügt werden.
@1 added to inventory.=@1 zum Inventar hinzugefügt.
@1 partially added to inventory of @2.=@1 teilweise ins Inventar von @2 eingefügt.
@1 could not be added to inventory of @2.=@1 konnte nicht ins Inventar von @2 eingefügt werden.
@1 added to inventory of @2.=@1 ins Inventar von @2 eingefügt.
<name> <ItemString> [<count> [<wear>]]=<Name> <ItemString> [<Anzahl> [<Abnutzung>]]
Give item to player=Gegenstand an Spieler geben
Name and ItemString required.=Name und ItemString benötigt.
<ItemString> [<count> [<wear>]]=<ItemString> [<Anzahl> [<Abnutzung>]]
Give item to yourself=Gegenstand Ihnen selbst geben
ItemString required.=ItemString benötigt.
<EntityName> [<X>,<Y>,<Z>]=<EntityName> [<X>,<Y>,<Z>]
Spawn entity at given (or your) position=Entity an angegebener (oder Ihrer eigenen) Position spawnen
EntityName required.=EntityName benötigt.
Unable to spawn entity, player is nil.=Entity konnte nicht gespawnt werden, Spieler ist nil.
Cannot spawn an unknown entity.=Ein unbekanntes Entity kann nicht gespawnt werden.
Invalid parameters (@1).=Ungültige Parameter (@1).
@1 spawned.=@1 gespawnt.
@1 failed to spawn.=@1 konnte nicht gespawnt werden.
Destroy item in hand=Gegenstand in der Hand zerstören
Unable to pulverize, no player.=Konnte nicht pulverisieren, kein Spieler.
Unable to pulverize, no item in hand.=Konnte nicht pulverisieren, kein Gegenstand in der Hand.
An item was pulverized.=Ein Gegenstand wurde pulverisiert.
[<range>] [<seconds>] [<limit>]=[<Reichweite>] [<Sekunden>] [<Limit>]
Check who last touched a node or a node near it within the time specified by <seconds>. Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set <seconds> to inf for no time limit=Überprüfen, wer als letztes einen Node oder einen Node in der Nähe innerhalb der in <Sekunden> angegebenen Zeitspanne angefasst hat. Standard: Reichweite @= 0, Sekunden @= 86400 @= 24h, Limit @= 5. <Sekunden> auf „inf“ setzen, um Zeitlimit zu deaktivieren.
Rollback functions are disabled.=Rollback-Funktionen sind deaktiviert.
That limit is too high!=Dieses Limit ist zu hoch!
Checking @1 ...=Überprüfe @1 ...
Nobody has touched the specified location in @1 seconds.=Niemand hat die angegebene Position seit @1 Sekunden angefasst.
@1 @2 @3 -> @4 @5 seconds ago.=@1 @2 @3 -> @4 vor @5 Sekunden.
Punch a node (range@=@1, seconds@=@2, limit@=@3).=Hauen Sie einen Node (Reichweite@=@1, Sekunden@=@2, Limit@=@3).
(<name> [<seconds>]) | (:<actor> [<seconds>])=(<Name> [<Sekunden>]) | (:<Akteur> [<Sekunden>])
Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit=Aktionen eines Spielers zurückrollen. Standard für <Sekunden> ist 60. <Sekunden> auf „inf“ setzen, um Zeitlimit zu deaktivieren
Invalid parameters. See /help rollback and /help rollback_check.=Ungültige Parameter. Siehe /help rollback und /help rollback_check.
Reverting actions of player '@1' since @2 seconds.=Die Aktionen des Spielers „@1“ seit @2 Sekunden werden rückgängig gemacht.
Reverting actions of @1 since @2 seconds.=Die Aktionen von @1 seit @2 Sekunden werden rückgängig gemacht.
(log is too long to show)=(Protokoll ist zu lang für die Anzeige)
Reverting actions succeeded.=Die Aktionen wurden erfolgreich rückgängig gemacht.
Reverting actions FAILED.=FEHLGESCHLAGEN: Die Aktionen konnten nicht rückgängig gemacht werden.
Show server status=Serverstatus anzeigen
This command was disabled by a mod or game.=Dieser Befehl wurde von einer Mod oder einem Spiel deaktiviert.
[<0..23>:<0..59> | <0..24000>]=[<0..23>:<0..59> | <0..24000>]
Show or set time of day=Tageszeit anzeigen oder setzen
Current time is @1:@2.=Es ist jetzt @1:@2 Uhr.
You don't have permission to run this command (missing privilege: @1).=Sie haben nicht die Erlaubnis, diesen Befehl auszuführen (fehlendes Privileg: @1).
Invalid time.=Ungültige Zeit.
Time of day changed.=Tageszeit geändert.
Invalid hour (must be between 0 and 23 inclusive).=Ungültige Stunde (muss zwischen 0 und 23 inklusive liegen).
Invalid minute (must be between 0 and 59 inclusive).=Ungültige Minute (muss zwischen 0 und 59 inklusive liegen).
Show day count since world creation=Anzahl Tage seit der Erschaffung der Welt anzeigen
Current day is @1.=Aktueller Tag ist @1.
[<delay_in_seconds> | -1] [reconnect] [<message>]=[<Verzögerung_in_Sekunden> | -1] [reconnect] [<Nachricht>]
Shutdown server (-1 cancels a delayed shutdown)=Server herunterfahren (-1 bricht einen verzögerten Abschaltvorgang ab)
Server shutting down (operator request).=Server wird heruntergefahren (Betreiberanfrage).
Ban the IP of a player or show the ban list=Die IP eines Spielers verbannen oder die Bannliste anzeigen
The ban list is empty.=Die Bannliste ist leer.
Ban list: @1=Bannliste: @1
Player is not online.=Spieler ist nicht online.
Failed to ban player.=Konnte Spieler nicht verbannen.
Banned @1.=@1 verbannt.
<name> | <IP_address>=<Name> | <IP_Adresse>
Remove IP ban belonging to a player/IP=Einen IP-Bann auf einen Spieler zurücknehmen
Failed to unban player/IP.=Konnte Bann auf Spieler/IP nicht zurücknehmen.
Unbanned @1.=Bann auf @1 zurückgenommen.
<name> [<reason>]=<Name> [<Grund>]
Kick a player=Spieler hinauswerfen
Failed to kick player @1.=Spieler @1 konnte nicht hinausgeworfen werden.
Kicked @1.=@1 hinausgeworfen.
[full | quick]=[full | quick]
Clear all objects in world=Alle Objekte in der Welt löschen
Invalid usage, see /help clearobjects.=Ungültige Verwendung, siehe /help clearobjects.
Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=Lösche alle Objekte. Dies kann eine lange Zeit dauern. Eine Netzwerkzeitüberschreitung könnte für Sie auftreten. (von @1)
Cleared all objects.=Alle Objekte gelöscht.
<name> <message>=<Name> <Nachricht>
Send a direct message to a player=Eine Direktnachricht an einen Spieler senden
Invalid usage, see /help msg.=Ungültige Verwendung, siehe /help msg.
The player @1 is not online.=Der Spieler @1 ist nicht online.
DM from @1: @2=DN von @1: @2
Message sent.=Nachricht gesendet.
Get the last login time of a player or yourself=Den letzten Loginzeitpunkt eines Spielers oder Ihren eigenen anfragen
@1's last login time was @2.=Letzter Loginzeitpunkt von @1 war @2.
@1's last login time is unknown.=Letzter Loginzeitpunkt von @1 ist unbekannt.
Clear the inventory of yourself or another player=Das Inventar von Ihnen oder einem anderen Spieler leeren
You don't have permission to clear another player's inventory (missing privilege: @1).=Sie haben nicht die Erlaubnis, das Inventar eines anderen Spielers zu leeren (fehlendes Privileg: @1).
@1 cleared your inventory.=@1 hat Ihr Inventar geleert.
Cleared @1's inventory.=Inventar von @1 geleert.
Player must be online to clear inventory!=Spieler muss online sein, um das Inventar leeren zu können!
Players can't be killed, damage has been disabled.=Spieler können nicht getötet werden, Schaden ist deaktiviert.
Player @1 is not online.=Spieler @1 ist nicht online.
You are already dead.=Sie sind schon tot.
@1 is already dead.=@1 ist bereits tot.
@1 has been killed.=@1 wurde getötet.
Kill player or yourself=Einen Spieler oder Sie selbst töten
Available commands: @1=Verfügbare Befehle: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=„/help <Befehl>“ benutzen, um mehr Informationen zu erhalten, oder „/help all“, um alles aufzulisten.
Available commands:=Verfügbare Befehle:
Command not available: @1=Befehl nicht verfügbar: @1
[all | privs | <cmd>]=[all | privs | <Befehl>]
Get help for commands or list privileges=Hilfe für Befehle erhalten oder Privilegien auflisten
Command=Befehl
Parameters=Parameter
For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste.
Double-click to copy the entry to the chat history.=Doppelklicken, um den Eintrag in die Chathistorie einzufügen.
Command: @1 @2=Befehl: @1 @2
Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /help <Befehl>)
Close=Schließen
Privilege=Privileg
Description=Beschreibung
Available privileges:=Verfügbare Privilegien:
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]]
Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten
Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben.
Statistics were reset.=Statistiken wurden zurückgesetzt.
Usage: @1=Verwendung: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format kann entweder „txt“, „csv“, „lua“, „json“ oder „json_pretty“ sein (die Struktur kann sich in Zukunft ändern).
@1 joined the game.=@1 ist dem Spiel beigetreten.
@1 left the game.=@1 hat das Spiel verlassen.
@1 left the game (timed out).=@1 hat das Spiel verlassen (Netzwerkzeitüberschreitung).
(no description)=(keine Beschreibung)
Can interact with things and modify the world=Kann mit Dingen interagieren und die Welt verändern
Can speak in chat=Kann im Chat sprechen
Can modify basic privileges (@1)=Kann grundlegende Privilegien anpassen (@1)
Can modify privileges=Kann Privilegien anpassen
Can teleport self=Kann sich selbst teleportieren
Can teleport other players=Kann andere Spieler teleportieren
Can set the time of day using /time=Kann die Tageszeit mit /time setzen
Can do server maintenance stuff=Kann Serverwartungsdinge machen
Can bypass node protection in the world=Kann den Schutz auf Blöcken in der Welt umgehen
Can ban and unban players=Kann Spieler verbannen und entbannen
Can kick players=Kann Spieler hinauswerfen
Can use /give and /giveme=Kann /give und /giveme benutzen
Can use /setpassword and /clearpassword=Kann /setpassword und /clearpassword benutzen
Can use fly mode=Kann den Flugmodus benutzen
Can use fast mode=Kann den Schnellmodus benutzen
Can fly through solid nodes using noclip mode=Kann durch feste Blöcke mit dem Geistmodus fliegen
Can use the rollback functionality=Kann die Rollback-Funktionalität benutzen
Allows enabling various debug options that may affect gameplay=Erlaubt die Aktivierung diverser Debugoptionen, die das Spielgeschehen beeinflussen könnten
Unknown Item=Unbekannter Gegenstand
Air=Luft
Ignore=Ignorieren
You can't place 'ignore' nodes!=Sie können keine „ignore“-Blöcke platzieren!
Values below show absolute/relative times spend per server step by the instrumented function.=Die unten angegebenen Werte zeigen absolute/relative Zeitspannen, die je Server-Step von der instrumentierten Funktion in Anspruch genommen wurden.
A total of @1 sample(s) were taken.=Es wurden insgesamt @1 Datenpunkt(e) aufgezeichnet.
The output is limited to '@1'.=Die Ausgabe ist beschränkt auf „@1“.
Saving of profile failed: @1=Speichern des Profils fehlgeschlagen: @1
Profile saved to @1=Profil abgespeichert nach @1

View File

@ -0,0 +1,247 @@
# textdomain: __builtin
Empty command.=Comando vuoto.
Invalid command: @1=Comando non valido: @1
Invalid command usage.=Utilizzo del comando non valido.
(@1 s)=
Command execution took @1 s=
You don't have permission to run this command (missing privileges: @1).=Non hai il permesso di eseguire questo comando (privilegi mancanti: @1).
Unable to get position of player @1.=Impossibile ottenere la posizione del giocatore @1.
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Formato dell'area non corretto. Richiesto: (x1,y1,z1) (x2,y2,z2)
<action>=<azione>
Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pizza')=Mostra un'azione in chat (es. `/me ordina una pizza` mostra `<nome giocatore> ordina una pizza`)
Show the name of the server owner=Mostra il nome del proprietario del server
The administrator of this server is @1.=L'amministratore di questo server è @1.
There's no administrator named in the config file.=Non c'è nessun amministratore nel file di configurazione.
@1 does not have any privileges.=
Privileges of @1: @2=Privilegi di @1: @2
[<name>]=[<nome>]
Show privileges of yourself or another player=Mostra i privilegi propri o di un altro giocatore
Player @1 does not exist.=Il giocatore @1 non esiste.
<privilege>=<privilegio>
Return list of all online players with privilege=Ritorna una lista di tutti i giocatori connessi col tale privilegio
Invalid parameters (see /help haspriv).=Parametri non validi (vedi /help haspriv).
Unknown privilege!=Privilegio sconosciuto!
Players online with the "@1" privilege: @2=Giocatori connessi con il privilegio "@1": @2
Your privileges are insufficient.=I tuoi privilegi sono insufficienti.
Your privileges are insufficient. '@1' only allows you to grant: @2=
Unknown privilege: @1=Privilegio sconosciuto: @1
@1 granted you privileges: @2=@1 ti ha assegnato i seguenti privilegi: @2
<name> (<privilege> [, <privilege2> [<...>]] | all)=
Give privileges to player=Dà privilegi al giocatore
Invalid parameters (see /help grant).=Parametri non validi (vedi /help grant).
<privilege> [, <privilege2> [<...>]] | all=
Grant privileges to yourself=Assegna dei privilegi a te stessǝ
Invalid parameters (see /help grantme).=Parametri non validi (vedi /help grantme).
Your privileges are insufficient. '@1' only allows you to revoke: @2=
Note: Cannot revoke in singleplayer: @1=
Note: Cannot revoke from admin: @1=
No privileges were revoked.=
@1 revoked privileges from you: @2=@1 ti ha revocato i seguenti privilegi: @2
Remove privileges from player=Rimuove privilegi dal giocatore
Invalid parameters (see /help revoke).=Parametri non validi (vedi /help revoke).
Revoke privileges from yourself=Revoca privilegi a te stessǝ
Invalid parameters (see /help revokeme).=Parametri non validi (vedi /help revokeme).
<name> <password>=<nome> <password>
Set player's password=Imposta la password del giocatore
Name field required.=Campo "nome" richiesto.
Your password was cleared by @1.=La tua password è stata resettata da @1.
Password of player "@1" cleared.=Password del giocatore "@1" resettata.
Your password was set by @1.=La tua password è stata impostata da @1.
Password of player "@1" set.=Password del giocatore "@1" impostata.
<name>=<nome>
Set empty password for a player=Imposta una password vuota a un giocatore
Reload authentication data=Ricarica i dati d'autenticazione
Done.=Fatto.
Failed.=Errore.
Remove a player's data=Rimuove i dati di un giocatore
Player "@1" removed.=Giocatore "@1" rimosso.
No such player "@1" to remove.=Non è presente nessun giocatore "@1" da rimuovere.
Player "@1" is connected, cannot remove.=Il giocatore "@1" è connesso, non può essere rimosso.
Unhandled remove_player return code @1.=Codice ritornato da remove_player non gestito (@1).
Cannot teleport out of map bounds!=Non ci si può teletrasportare fuori dai limiti della mappa!
Cannot get player with name @1.=Impossibile trovare il giocatore chiamato @1.
Cannot teleport, @1 is attached to an object!=Impossibile teletrasportare, @1 è attaccato a un oggetto!
Teleporting @1 to @2.=Teletrasportando @1 da @2.
One does not teleport to oneself.=Non ci si può teletrasportare su se stessi.
Cannot get teleportee with name @1.=Impossibile trovare il giocatore chiamato @1 per il teletrasporto
Cannot get target player with name @1.=Impossibile trovare il giocatore chiamato @1 per il teletrasporto
Teleporting @1 to @2 at @3.=Teletrasportando @1 da @2 a @3
<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>=<X>,<Y>,<Z> | <da_nome> | <nome> <X>,<Y>,<Z> | <nome> <da_nome>
Teleport to position or player=Teletrasporta a una posizione o da un giocatore
You don't have permission to teleport other players (missing privilege: @1).=Non hai il permesso di teletrasportare altri giocatori (privilegio mancante: @1).
([-n] <name> <value>) | <name>=([-n] <nome> <valore>) | <nome>
Set or read server configuration setting=Imposta o ottieni le configurazioni del server
Failed. Use '/set -n <name> <value>' to create a new setting.=Errore. Usa 'set -n <nome> <valore>' per creare una nuova impostazione
@1 @= @2=@1 @= @2
<not set>=<non impostato>
Invalid parameters (see /help set).=Parametri non validi (vedi /help set).
Finished emerging @1 blocks in @2ms.=Finito di emergere @1 blocchi in @2ms
emergeblocks update: @1/@2 blocks emerged (@3%)=aggiornamento emergeblocks: @1/@2 blocchi emersi (@3%)
(here [<radius>]) | (<pos1> <pos2>)=(here [<raggio>]) | (<pos1> <pos2>)
Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Carica (o, se non esiste, genera) blocchi mappa contenuti nell'area tra pos1 e pos2 (<pos1> e <pos2> vanno tra parentesi)
Started emerge of area ranging from @1 to @2.=Iniziata emersione dell'area tra @1 e @2.
Delete map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=Cancella i blocchi mappa contenuti nell'area tra pos1 e pos2 (<pos1> e <pos2> vanno tra parentesi)
Successfully cleared area ranging from @1 to @2.=Area tra @1 e @2 ripulita con successo.
Failed to clear one or more blocks in area.=Errore nel ripulire uno o più blocchi mappa nell'area
Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in parentheses)=Reimposta l'illuminazione nell'area tra pos1 e po2 (<pos1> e <pos2> vanno tra parentesi)
Successfully reset light in the area ranging from @1 to @2.=Luce nell'area tra @1 e @2 reimpostata con successo.
Failed to load one or more blocks in area.=Errore nel caricare uno o più blocchi mappa nell'area.
List mods installed on the server=Elenca le mod installate nel server
Cannot give an empty item.=Impossibile dare un oggetto vuoto.
Cannot give an unknown item.=Impossibile dare un oggetto sconosciuto.
Giving 'ignore' is not allowed.=Non è permesso dare 'ignore'.
@1 is not a known player.=@1 non è un giocatore conosciuto.
@1 partially added to inventory.=@1 parzialmente aggiunto all'inventario.
@1 could not be added to inventory.=@1 non può essere aggiunto all'inventario.
@1 added to inventory.=@1 aggiunto all'inventario.
@1 partially added to inventory of @2.=@1 parzialmente aggiunto all'inventario di @2.
@1 could not be added to inventory of @2.=Non è stato possibile aggiungere @1 all'inventario di @2.
@1 added to inventory of @2.=@1 aggiunto all'inventario di @2.
<name> <ItemString> [<count> [<wear>]]=<nome> <NomeOggetto> [<quantità> [<usura>]]
Give item to player=Dà oggetti ai giocatori
Name and ItemString required.=Richiesti nome e NomeOggetto.
<ItemString> [<count> [<wear>]]=<NomeOggetto> [<quantità> [<usura>]]
Give item to yourself=Dà oggetti a te stessǝ
ItemString required.=Richiesto NomeOggetto.
<EntityName> [<X>,<Y>,<Z>]=<NomeEntità> [<X>,<Y>,<Z>]
Spawn entity at given (or your) position=Genera un'entità alla data coordinata (o la tua)
EntityName required.=Richiesto NomeEntità
Unable to spawn entity, player is nil.=Impossibile generare l'entità, il giocatore è nil.
Cannot spawn an unknown entity.=Impossibile generare un'entità sconosciuta.
Invalid parameters (@1).=Parametri non validi (@1).
@1 spawned.=Generata entità @1.
@1 failed to spawn.=Errore nel generare @1
Destroy item in hand=Distrugge l'oggetto in mano
Unable to pulverize, no player.=Impossibile polverizzare, nessun giocatore.
Unable to pulverize, no item in hand.=Impossibile polverizzare, nessun oggetto in mano.
An item was pulverized.=Un oggetto è stato polverizzato.
[<range>] [<seconds>] [<limit>]=[<raggio>] [<secondi>] [<limite>]
Check who last touched a node or a node near it within the time specified by <seconds>. Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set <seconds> to inf for no time limit=Controlla chi è l'ultimo giocatore che ha toccato un nodo o un nodo nelle sue vicinanze, negli ultimi secondi indicati. Di base: raggio @= 0, secondi @= 86400 @= 24h, limite @= 5.
Rollback functions are disabled.=Le funzioni di rollback sono disabilitate.
That limit is too high!=Il limite è troppo alto!
Checking @1 ...=Controllando @1 ...
Nobody has touched the specified location in @1 seconds.=Nessuno ha toccato il punto specificato negli ultimi @1 secondi.
@1 @2 @3 -> @4 @5 seconds ago.=@1 @2 @3 -> @4 @5 secondi fa.
Punch a node (range@=@1, seconds@=@2, limit@=@3).=Colpisce un nodo (raggio@=@1, secondi@=@2, limite@=@3)
(<name> [<seconds>]) | (:<actor> [<seconds>])=(<nome> [<secondi>]) | (:<attore> [<secondi>])
Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit=Riavvolge le azioni di un giocatore. Di base, <secondi> è 60. Imposta <secondi> a inf per nessun limite di tempo
Invalid parameters. See /help rollback and /help rollback_check.=Parametri non validi. Vedi /help rollback e /help rollback_check.
Reverting actions of player '@1' since @2 seconds.=Riavvolge le azioni del giocatore '@1' avvenute negli ultimi @2 secondi.
Reverting actions of @1 since @2 seconds.=Riavvolge le azioni di @1 avvenute negli ultimi @2 secondi.
(log is too long to show)=(il log è troppo lungo per essere mostrato)
Reverting actions succeeded.=Riavvolgimento azioni avvenuto con successo.
Reverting actions FAILED.=Errore nel riavvolgere le azioni.
Show server status=Mostra lo stato del server
This command was disabled by a mod or game.=Questo comando è stato disabilitato da una mod o dal gioco.
[<0..23>:<0..59> | <0..24000>]=[<0..23>:<0..59> | <0..24000>]
Show or set time of day=Mostra o imposta l'orario della giornata
Current time is @1:@2.=Orario corrente: @1:@2.
You don't have permission to run this command (missing privilege: @1).=Non hai il permesso di eseguire questo comando (privilegio mancante: @1)
Invalid time.=Orario non valido.
Time of day changed.=Orario della giornata cambiato.
Invalid hour (must be between 0 and 23 inclusive).=Ora non valida (deve essere tra 0 e 23 inclusi)
Invalid minute (must be between 0 and 59 inclusive).=Minuto non valido (deve essere tra 0 e 59 inclusi)
Show day count since world creation=Mostra il conteggio dei giorni da quando il mondo è stato creato
Current day is @1.=Giorno attuale: @1.
[<delay_in_seconds> | -1] [reconnect] [<message>]=[<ritardo_in_secondi> | -1] [reconnect] [<messaggio>]
Shutdown server (-1 cancels a delayed shutdown)=Arresta il server (-1 annulla un arresto programmato)
Server shutting down (operator request).=Arresto del server in corso (per richiesta dell'operatore)
Ban the IP of a player or show the ban list=Bandisce l'IP del giocatore o mostra la lista di quelli banditi
The ban list is empty.=La lista banditi è vuota.
Ban list: @1=Lista banditi: @1
Player is not online.=Il giocatore non è connesso.
Failed to ban player.=Errore nel bandire il giocatore.
Banned @1.=@1 banditǝ.
<name> | <IP_address>=<nome> | <indirizzo_IP>
Remove IP ban belonging to a player/IP=Perdona l'IP appartenente a un giocatore/IP
Failed to unban player/IP.=Errore nel perdonare il giocatore/IP
Unbanned @1.=@1 perdonatǝ
<name> [<reason>]=<nome> [<ragione>]
Kick a player=Caccia un giocatore
Failed to kick player @1.=Errore nel cacciare il giocatore @1.
Kicked @1.=@1 cacciatǝ.
[full | quick]=[full | quick]
Clear all objects in world=Elimina tutti gli oggetti/entità nel mondo
Invalid usage, see /help clearobjects.=Uso incorretto, vedi /help clearobjects.
Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=Eliminando tutti gli oggetti/entità. Questo potrebbe richiedere molto tempo e farti eventualmente crashare. (di @1)
Cleared all objects.=Tutti gli oggetti sono stati eliminati.
<name> <message>=<nome> <messaggio>
Send a direct message to a player=Invia un messaggio privato al giocatore
Invalid usage, see /help msg.=Uso incorretto, vedi /help msg
The player @1 is not online.=Il giocatore @1 non è connesso.
DM from @1: @2=Messaggio privato da @1: @2
Message sent.=Messaggio inviato.
Get the last login time of a player or yourself=Ritorna l'ultimo accesso di un giocatore o di te stessǝ
@1's last login time was @2.=L'ultimo accesso di @1 è avvenuto il @2
@1's last login time is unknown.=L'ultimo accesso di @1 non è conosciuto
Clear the inventory of yourself or another player=Svuota l'inventario tuo o di un altro giocatore
You don't have permission to clear another player's inventory (missing privilege: @1).=Non hai il permesso di svuotare l'inventario di un altro giocatore (privilegio mancante: @1).
@1 cleared your inventory.=@1 ha svuotato il tuo inventario.
Cleared @1's inventory.=L'inventario di @1 è stato svuotato.
Player must be online to clear inventory!=Il giocatore deve essere connesso per svuotarne l'inventario!
Players can't be killed, damage has been disabled.=I giocatori non possono essere uccisi, il danno è disabilitato.
Player @1 is not online.=Il giocatore @1 non è connesso.
You are already dead.=Sei già mortǝ.
@1 is already dead.=@1 è già mortǝ.
@1 has been killed.=@1 è stato uccisǝ.
Kill player or yourself=Uccide un giocatore o te stessǝ
Available commands: @1=Comandi disponibili: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=Usa '/help <comando>' per ottenere più informazioni, o '/help all' per elencare tutti i comandi.
Available commands:=Comandi disponibili:
Command not available: @1=Comando non disponibile: @1
[all | privs | <cmd>]=[all | privs | <comando>]
Get help for commands or list privileges=Richiama la finestra d'aiuto dei comandi o dei privilegi
Command=Comando
Parameters=Parametri
For more information, click on any entry in the list.=Per più informazioni, clicca su una qualsiasi voce dell'elenco.
Double-click to copy the entry to the chat history.=Doppio click per copiare la voce nella cronologia della chat.
Command: @1 @2=Comando: @1 @2
Available commands: (see also: /help <cmd>)=Comandi disponibili: (vedi anche /help <comando>)
Close=Chiudi
Privilege=Privilegio
Description=Descrizione
Available privileges:=Privilegi disponibili:
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filtro>] | dump [<filtro>] | save [<formato> [<filtro>]] | reset
Handle the profiler and profiling data=Gestisce il profiler e i dati da esso elaborati
Statistics written to action log.=Statistiche scritte nel log delle azioni.
Statistics were reset.=Le statistiche sono state resettate.
Usage: @1=Utilizzo: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=I formati supportati sono txt, csv, lua, json e json_pretty (le strutture potrebbero essere soggetti a cambiamenti).
@1 joined the game.=
@1 left the game.=
@1 left the game (timed out).=
(no description)=(nessuna descrizione)
Can interact with things and modify the world=Si può interagire con le cose e modificare il mondo
Can speak in chat=Si può parlare in chat
Can modify basic privileges (@1)=
Can modify privileges=Si possono modificare i privilegi
Can teleport self=Si può teletrasportare se stessз
Can teleport other players=Si possono teletrasportare gli altri giocatori
Can set the time of day using /time=Si può impostate l'orario della giornata tramite /time
Can do server maintenance stuff=Si possono eseguire operazioni di manutenzione del server
Can bypass node protection in the world=Si può aggirare la protezione dei nodi nel mondo
Can ban and unban players=Si possono bandire e perdonare i giocatori
Can kick players=Si possono cacciare i giocatori
Can use /give and /giveme=Si possono usare /give e /give me
Can use /setpassword and /clearpassword=Si possono usare /setpassword e /clearpassword
Can use fly mode=Si può usare la modalità volo
Can use fast mode=Si può usare la modalità rapida
Can fly through solid nodes using noclip mode=Si può volare attraverso i nodi solidi con la modalità incorporea
Can use the rollback functionality=Si può usare la funzione di rollback
Allows enabling various debug options that may affect gameplay=Permette di abilitare varie opzioni di debug che potrebbero influenzare l'esperienza di gioco
Unknown Item=Oggetto sconosciuto
Air=Aria
Ignore=Ignora
You can't place 'ignore' nodes!=Non puoi piazzare nodi 'ignore'!
Values below show absolute/relative times spend per server step by the instrumented function.=
A total of @1 sample(s) were taken.=
The output is limited to '@1'.=
Saving of profile failed: @1=
Profile saved to @1=
##### not used anymore #####
<name> (<privilege> | all)=<nome> (<privilegio> | all)
<privilege> | all=<privilegio> | all
Can modify 'shout' and 'interact' privileges=Si possono modificare i privilegi 'shout' e 'interact'

240
builtin/locale/template.txt Normal file
View File

@ -0,0 +1,240 @@
# textdomain: __builtin
Empty command.=
Invalid command: @1=
Invalid command usage.=
(@1 s)=
Command execution took @1 s=
You don't have permission to run this command (missing privileges: @1).=
Unable to get position of player @1.=
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=
<action>=
Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pizza')=
Show the name of the server owner=
The administrator of this server is @1.=
There's no administrator named in the config file.=
@1 does not have any privileges.=
Privileges of @1: @2=
[<name>]=
Show privileges of yourself or another player=
Player @1 does not exist.=
<privilege>=
Return list of all online players with privilege=
Invalid parameters (see /help haspriv).=
Unknown privilege!=
Players online with the "@1" privilege: @2=
Your privileges are insufficient.=
Your privileges are insufficient. '@1' only allows you to grant: @2=
Unknown privilege: @1=
@1 granted you privileges: @2=
<name> (<privilege> [, <privilege2> [<...>]] | all)=
Give privileges to player=
Invalid parameters (see /help grant).=
<privilege> [, <privilege2> [<...>]] | all=
Grant privileges to yourself=
Invalid parameters (see /help grantme).=
Your privileges are insufficient. '@1' only allows you to revoke: @2=
Note: Cannot revoke in singleplayer: @1=
Note: Cannot revoke from admin: @1=
No privileges were revoked.=
@1 revoked privileges from you: @2=
Remove privileges from player=
Invalid parameters (see /help revoke).=
Revoke privileges from yourself=
Invalid parameters (see /help revokeme).=
<name> <password>=
Set player's password=
Name field required.=
Your password was cleared by @1.=
Password of player "@1" cleared.=
Your password was set by @1.=
Password of player "@1" set.=
<name>=
Set empty password for a player=
Reload authentication data=
Done.=
Failed.=
Remove a player's data=
Player "@1" removed.=
No such player "@1" to remove.=
Player "@1" is connected, cannot remove.=
Unhandled remove_player return code @1.=
Cannot teleport out of map bounds!=
Cannot get player with name @1.=
Cannot teleport, @1 is attached to an object!=
Teleporting @1 to @2.=
One does not teleport to oneself.=
Cannot get teleportee with name @1.=
Cannot get target player with name @1.=
Teleporting @1 to @2 at @3.=
<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>=
Teleport to position or player=
You don't have permission to teleport other players (missing privilege: @1).=
([-n] <name> <value>) | <name>=
Set or read server configuration setting=
Failed. Use '/set -n <name> <value>' to create a new setting.=
@1 @= @2=
<not set>=
Invalid parameters (see /help set).=
Finished emerging @1 blocks in @2ms.=
emergeblocks update: @1/@2 blocks emerged (@3%)=
(here [<radius>]) | (<pos1> <pos2>)=
Load (or, if nonexistent, generate) map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=
Started emerge of area ranging from @1 to @2.=
Delete map blocks contained in area pos1 to pos2 (<pos1> and <pos2> must be in parentheses)=
Successfully cleared area ranging from @1 to @2.=
Failed to clear one or more blocks in area.=
Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in parentheses)=
Successfully reset light in the area ranging from @1 to @2.=
Failed to load one or more blocks in area.=
List mods installed on the server=
Cannot give an empty item.=
Cannot give an unknown item.=
Giving 'ignore' is not allowed.=
@1 is not a known player.=
@1 partially added to inventory.=
@1 could not be added to inventory.=
@1 added to inventory.=
@1 partially added to inventory of @2.=
@1 could not be added to inventory of @2.=
@1 added to inventory of @2.=
<name> <ItemString> [<count> [<wear>]]=
Give item to player=
Name and ItemString required.=
<ItemString> [<count> [<wear>]]=
Give item to yourself=
ItemString required.=
<EntityName> [<X>,<Y>,<Z>]=
Spawn entity at given (or your) position=
EntityName required.=
Unable to spawn entity, player is nil.=
Cannot spawn an unknown entity.=
Invalid parameters (@1).=
@1 spawned.=
@1 failed to spawn.=
Destroy item in hand=
Unable to pulverize, no player.=
Unable to pulverize, no item in hand.=
An item was pulverized.=
[<range>] [<seconds>] [<limit>]=
Check who last touched a node or a node near it within the time specified by <seconds>. Default: range @= 0, seconds @= 86400 @= 24h, limit @= 5. Set <seconds> to inf for no time limit=
Rollback functions are disabled.=
That limit is too high!=
Checking @1 ...=
Nobody has touched the specified location in @1 seconds.=
@1 @2 @3 -> @4 @5 seconds ago.=
Punch a node (range@=@1, seconds@=@2, limit@=@3).=
(<name> [<seconds>]) | (:<actor> [<seconds>])=
Revert actions of a player. Default for <seconds> is 60. Set <seconds> to inf for no time limit=
Invalid parameters. See /help rollback and /help rollback_check.=
Reverting actions of player '@1' since @2 seconds.=
Reverting actions of @1 since @2 seconds.=
(log is too long to show)=
Reverting actions succeeded.=
Reverting actions FAILED.=
Show server status=
This command was disabled by a mod or game.=
[<0..23>:<0..59> | <0..24000>]=
Show or set time of day=
Current time is @1:@2.=
You don't have permission to run this command (missing privilege: @1).=
Invalid time.=
Time of day changed.=
Invalid hour (must be between 0 and 23 inclusive).=
Invalid minute (must be between 0 and 59 inclusive).=
Show day count since world creation=
Current day is @1.=
[<delay_in_seconds> | -1] [reconnect] [<message>]=
Shutdown server (-1 cancels a delayed shutdown)=
Server shutting down (operator request).=
Ban the IP of a player or show the ban list=
The ban list is empty.=
Ban list: @1=
Player is not online.=
Failed to ban player.=
Banned @1.=
<name> | <IP_address>=
Remove IP ban belonging to a player/IP=
Failed to unban player/IP.=
Unbanned @1.=
<name> [<reason>]=
Kick a player=
Failed to kick player @1.=
Kicked @1.=
[full | quick]=
Clear all objects in world=
Invalid usage, see /help clearobjects.=
Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=
Cleared all objects.=
<name> <message>=
Send a direct message to a player=
Invalid usage, see /help msg.=
The player @1 is not online.=
DM from @1: @2=
Message sent.=
Get the last login time of a player or yourself=
@1's last login time was @2.=
@1's last login time is unknown.=
Clear the inventory of yourself or another player=
You don't have permission to clear another player's inventory (missing privilege: @1).=
@1 cleared your inventory.=
Cleared @1's inventory.=
Player must be online to clear inventory!=
Players can't be killed, damage has been disabled.=
Player @1 is not online.=
You are already dead.=
@1 is already dead.=
@1 has been killed.=
Kill player or yourself=
Available commands: @1=
Use '/help <cmd>' to get more information, or '/help all' to list everything.=
Available commands:=
Command not available: @1=
[all | privs | <cmd>]=
Get help for commands or list privileges=
Command=
Parameters=
For more information, click on any entry in the list.=
Double-click to copy the entry to the chat history.=
Command: @1 @2=
Available commands: (see also: /help <cmd>)=
Close=
Privilege=
Description=
Available privileges:=
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
Handle the profiler and profiling data=
Statistics written to action log.=
Statistics were reset.=
Usage: @1=
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=
@1 joined the game.=
@1 left the game.=
@1 left the game (timed out).=
(no description)=
Can interact with things and modify the world=
Can speak in chat=
Can modify basic privileges (@1)=
Can modify privileges=
Can teleport self=
Can teleport other players=
Can set the time of day using /time=
Can do server maintenance stuff=
Can bypass node protection in the world=
Can ban and unban players=
Can kick players=
Can use /give and /giveme=
Can use /setpassword and /clearpassword=
Can use fly mode=
Can use fast mode=
Can fly through solid nodes using noclip mode=
Can use the rollback functionality=
Allows enabling various debug options that may affect gameplay=
Unknown Item=
Air=
Ignore=
You can't place 'ignore' nodes!=
Values below show absolute/relative times spend per server step by the instrumented function.=
A total of @1 sample(s) were taken.=
The output is limited to '@1'.=
Saving of profile failed: @1=
Profile saved to @1=

View File

@ -14,14 +14,11 @@
--You should have received a copy of the GNU Lesser General Public License along --You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc., --with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--------------------------------------------------------------------------------
-- Global menu data -- Global menu data
--------------------------------------------------------------------------------
menudata = {} menudata = {}
--------------------------------------------------------------------------------
-- Local cached values -- Local cached values
--------------------------------------------------------------------------------
local min_supp_proto, max_supp_proto local min_supp_proto, max_supp_proto
function common_update_cached_supp_proto() function common_update_cached_supp_proto()
@ -29,14 +26,12 @@ function common_update_cached_supp_proto()
max_supp_proto = core.get_max_supp_proto() max_supp_proto = core.get_max_supp_proto()
end end
common_update_cached_supp_proto() common_update_cached_supp_proto()
--------------------------------------------------------------------------------
-- Menu helper functions
--------------------------------------------------------------------------------
-------------------------------------------------------------------------------- -- Menu helper functions
local function render_client_count(n) local function render_client_count(n)
if n > 99 then return '99+' if n > 999 then return '99+'
elseif n >= 0 then return tostring(n) elseif n >= 0 then return tostring(n)
else return '?' end else return '?' end
end end
@ -50,74 +45,40 @@ local function configure_selected_world_params(idx)
end end
end end
-------------------------------------------------------------------------------- function render_serverlist_row(spec)
function image_column(tooltip, flagname)
return "image,tooltip=" .. core.formspec_escape(tooltip) .. "," ..
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
"1=" .. core.formspec_escape(defaulttexturedir ..
(flagname and "server_flags_" .. flagname .. ".png" or "blank.png")) .. "," ..
"2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," ..
"3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," ..
"4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," ..
"5=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png")
end
--------------------------------------------------------------------------------
function order_favorite_list(list)
local res = {}
--orders the favorite list after support
for i = 1, #list do
local fav = list[i]
if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
res[#res + 1] = fav
end
end
for i = 1, #list do
local fav = list[i]
if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
res[#res + 1] = fav
end
end
return res
end
--------------------------------------------------------------------------------
function render_serverlist_row(spec, is_favorite)
local text = "" local text = ""
if spec.name then if spec.name then
text = text .. core.formspec_escape(spec.name:trim()) text = text .. core.formspec_escape(spec.name:trim())
elseif spec.address then elseif spec.address then
text = text .. spec.address:trim() text = text .. core.formspec_escape(spec.address:trim())
if spec.port then if spec.port then
text = text .. ":" .. spec.port text = text .. ":" .. spec.port
end end
end end
local grey_out = not is_server_protocol_compat(spec.proto_min, spec.proto_max) local grey_out = not spec.is_compatible
local details local details = {}
if is_favorite then
details = "1,"
else
details = "0,"
end
if spec.ping then if spec.lag or spec.ping then
local ping = spec.ping * 1000 local lag = (spec.lag or 0) * 1000 + (spec.ping or 0) * 250
if ping <= 50 then if lag <= 125 then
details = details .. "2," table.insert(details, "1")
elseif ping <= 100 then elseif lag <= 175 then
details = details .. "3," table.insert(details, "2")
elseif ping <= 250 then elseif lag <= 250 then
details = details .. "4," table.insert(details, "3")
else else
details = details .. "5," table.insert(details, "4")
end end
else else
details = details .. "0," table.insert(details, "0")
end end
if spec.clients and spec.clients_max then table.insert(details, ",")
local color = (grey_out and "#aaaaaa") or ((spec.is_favorite and "#ddddaa") or "#ffffff")
if spec.clients and (spec.clients_max or 0) > 0 then
local clients_percent = 100 * spec.clients / spec.clients_max local clients_percent = 100 * spec.clients / spec.clients_max
-- Choose a color depending on how many clients are connected -- Choose a color depending on how many clients are connected
@ -128,74 +89,50 @@ function render_serverlist_row(spec, is_favorite)
elseif clients_percent <= 60 then clients_color = '#a1e587' -- 0-60%: green elseif clients_percent <= 60 then clients_color = '#a1e587' -- 0-60%: green
elseif clients_percent <= 90 then clients_color = '#ffdc97' -- 60-90%: yellow elseif clients_percent <= 90 then clients_color = '#ffdc97' -- 60-90%: yellow
elseif clients_percent == 100 then clients_color = '#dd5b5b' -- full server: red (darker) elseif clients_percent == 100 then clients_color = '#dd5b5b' -- full server: red (darker)
else clients_color = '#ffba97' -- 90-100%: orange else clients_color = '#ffba97' -- 90-100%: orange
end end
details = details .. clients_color .. ',' .. table.insert(details, clients_color)
render_client_count(spec.clients) .. ',/,' .. table.insert(details, render_client_count(spec.clients) .. " / " ..
render_client_count(spec.clients_max) .. ',' render_client_count(spec.clients_max))
elseif grey_out then
details = details .. '#aaaaaa,?,/,?,'
else else
details = details .. ',?,/,?,' table.insert(details, color)
table.insert(details, "?")
end end
if spec.creative then if spec.creative then
details = details .. "1," table.insert(details, "1") -- creative icon
else else
details = details .. "0," table.insert(details, "0")
end
if spec.damage then
details = details .. "1,"
else
details = details .. "0,"
end end
if spec.pvp then if spec.pvp then
details = details .. "1," table.insert(details, "2") -- pvp icon
elseif spec.damage then
table.insert(details, "1") -- heart icon
else else
details = details .. "0," table.insert(details, "0")
end end
return details .. (grey_out and '#aaaaaa,' or ',') .. text table.insert(details, color)
table.insert(details, text)
return table.concat(details, ",")
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
os.tempfolder = function() os.tempfolder = function()
if core.settings:get("TMPFolder") then local temp = core.get_temp_path()
return core.settings:get("TMPFolder") .. DIR_DELIM .. "MT_" .. math.random(0,10000) return temp .. DIR_DELIM .. "MT_" .. math.random(0, 10000)
end
local filetocheck = os.tmpname()
os.remove(filetocheck)
-- luacheck: ignore
-- https://blogs.msdn.microsoft.com/vcblog/2014/06/18/c-runtime-crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1/
-- The C runtime (CRT) function called by os.tmpname is tmpnam.
-- Microsofts tmpnam implementation in older CRT / MSVC releases is defective.
-- tmpnam return values starting with a backslash characterize this behavior.
-- https://sourceforge.net/p/mingw-w64/bugs/555/
-- MinGW tmpnam implementation is forwarded to the CRT directly.
-- https://sourceforge.net/p/mingw-w64/discussion/723797/thread/55520785/
-- MinGW links to an older CRT release (msvcrt.dll).
-- Due to legal concerns MinGW will never use a newer CRT.
--
-- Make use of TEMP to compose the temporary filename if an old
-- style tmpnam return value is detected.
if filetocheck:sub(1, 1) == "\\" then
local tempfolder = os.getenv("TEMP")
return tempfolder .. filetocheck
end
local randname = "MTTempModFolder_" .. math.random(0,10000)
local backstring = filetocheck:reverse()
return filetocheck:sub(0, filetocheck:len() - backstring:find(DIR_DELIM) + 1) ..
randname
end end
os.tmpname = function()
local path = os.tempfolder()
io.open(path, "w"):close()
return path
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
function menu_render_worldlist() function menu_render_worldlist()
local retval = "" local retval = ""
local current_worldlist = menudata.worldlist:get_list() local current_worldlist = menudata.worldlist:get_list()
@ -209,7 +146,6 @@ function menu_render_worldlist()
return retval return retval
end end
--------------------------------------------------------------------------------
function menu_handle_key_up_down(fields, textlist, settingname) function menu_handle_key_up_down(fields, textlist, settingname)
local oldidx, newidx = core.get_textlist_index(textlist), 1 local oldidx, newidx = core.get_textlist_index(textlist), 1
if fields.key_up or fields.key_down then if fields.key_up or fields.key_down then
@ -226,42 +162,6 @@ function menu_handle_key_up_down(fields, textlist, settingname)
return false return false
end end
--------------------------------------------------------------------------------
function asyncOnlineFavourites()
if not menudata.public_known then
menudata.public_known = {{
name = fgettext("Loading..."),
description = fgettext_ne("Try reenabling public serverlist and check your internet connection.")
}}
end
menudata.favorites = menudata.public_known
menudata.favorites_is_public = true
if not menudata.public_downloading then
menudata.public_downloading = true
else
return
end
core.handle_async(
function(param)
return core.get_favorites("online")
end,
nil,
function(result)
menudata.public_downloading = nil
local favs = order_favorite_list(result)
if favs[1] then
menudata.public_known = favs
menudata.favorites = menudata.public_known
menudata.favorites_is_public = true
end
core.event_handler("Refresh")
end
)
end
--------------------------------------------------------------------------------
function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency) function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
local textlines = core.wrap_text(text, textlen, true) local textlines = core.wrap_text(text, textlen, true)
local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width .. local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
@ -279,7 +179,6 @@ function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transp
return retval return retval
end end
--------------------------------------------------------------------------------
function is_server_protocol_compat(server_proto_min, server_proto_max) function is_server_protocol_compat(server_proto_min, server_proto_max)
if (not server_proto_min) or (not server_proto_max) then if (not server_proto_min) or (not server_proto_max) then
-- There is no info. Assume the best and act as if we would be compatible. -- There is no info. Assume the best and act as if we would be compatible.
@ -287,7 +186,7 @@ function is_server_protocol_compat(server_proto_min, server_proto_max)
end end
return min_supp_proto <= server_proto_max and max_supp_proto >= server_proto_min return min_supp_proto <= server_proto_max and max_supp_proto >= server_proto_min
end end
--------------------------------------------------------------------------------
function is_server_protocol_compat_or_error(server_proto_min, server_proto_max) function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
if not is_server_protocol_compat(server_proto_min, server_proto_max) then if not is_server_protocol_compat(server_proto_min, server_proto_max) then
local server_prot_ver_info, client_prot_ver_info local server_prot_ver_info, client_prot_ver_info
@ -315,7 +214,7 @@ function is_server_protocol_compat_or_error(server_proto_min, server_proto_max)
return true return true
end end
--------------------------------------------------------------------------------
function menu_worldmt(selected, setting, value) function menu_worldmt(selected, setting, value)
local world = menudata.worldlist:get_list()[selected] local world = menudata.worldlist:get_list()[selected]
if world then if world then

View File

@ -74,7 +74,7 @@ local function get_formspec(data)
"label[1.75,0;" .. data.worldspec.name .. "]" "label[1.75,0;" .. data.worldspec.name .. "]"
if mod.is_modpack or mod.type == "game" then if mod.is_modpack or mod.type == "game" then
local info = minetest.formspec_escape( local info = core.formspec_escape(
core.get_content_info(mod.path).description) core.get_content_info(mod.path).description)
if info == "" then if info == "" then
if mod.is_modpack then if mod.is_modpack then

View File

@ -15,7 +15,7 @@
--with this program; if not, write to the Free Software Foundation, Inc., --with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
if not minetest.get_http_api then if not core.get_http_api then
function create_store_dlg() function create_store_dlg()
return messagebox("store", return messagebox("store",
fgettext("ContentDB is not available when Minetest was compiled without cURL")) fgettext("ContentDB is not available when Minetest was compiled without cURL"))
@ -23,9 +23,11 @@ if not minetest.get_http_api then
return return
end end
local store = { packages = {}, packages_full = {} } -- Unordered preserves the original order of the ContentDB API,
-- before the package list is ordered based on installed state.
local store = { packages = {}, packages_full = {}, packages_full_unordered = {} }
local http = minetest.get_http_api() local http = core.get_http_api()
-- Screenshot -- Screenshot
local screenshot_dir = core.get_cache_path() .. DIR_DELIM .. "cdb" local screenshot_dir = core.get_cache_path() .. DIR_DELIM .. "cdb"
@ -150,7 +152,7 @@ local function start_install(package)
end end
local function queue_download(package) local function queue_download(package)
local max_concurrent_downloads = tonumber(minetest.settings:get("contentdb_max_concurrent_downloads")) local max_concurrent_downloads = tonumber(core.settings:get("contentdb_max_concurrent_downloads"))
if number_downloading < max_concurrent_downloads then if number_downloading < max_concurrent_downloads then
start_install(package) start_install(package)
else else
@ -159,6 +161,331 @@ local function queue_download(package)
end end
end end
local function get_raw_dependencies(package)
if package.raw_deps then
return package.raw_deps
end
local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s"
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local url = base_url .. url_fmt:format(package.id, core.get_max_supp_proto(), version.string)
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
local data = core.parse_json(response.data) or {}
local content_lookup = {}
for _, pkg in pairs(store.packages_full) do
content_lookup[pkg.id] = pkg
end
for id, raw_deps in pairs(data) do
local package2 = content_lookup[id:lower()]
if package2 and not package2.raw_deps then
package2.raw_deps = raw_deps
for _, dep in pairs(raw_deps) do
local packages = {}
for i=1, #dep.packages do
packages[#packages + 1] = content_lookup[dep.packages[i]:lower()]
end
dep.packages = packages
end
end
end
return package.raw_deps
end
local function has_hard_deps(raw_deps)
for i=1, #raw_deps do
if not raw_deps[i].is_optional then
return true
end
end
return false
end
-- Recursively resolve dependencies, given the installed mods
local function resolve_dependencies_2(raw_deps, installed_mods, out)
local function resolve_dep(dep)
-- Check whether it's already installed
if installed_mods[dep.name] then
return {
is_optional = dep.is_optional,
name = dep.name,
installed = true,
}
end
-- Find exact name matches
local fallback
for _, package in pairs(dep.packages) do
if package.type ~= "game" then
if package.name == dep.name then
return {
is_optional = dep.is_optional,
name = dep.name,
installed = false,
package = package,
}
elseif not fallback then
fallback = package
end
end
end
-- Otherwise, find the first mod that fulfils it
if fallback then
return {
is_optional = dep.is_optional,
name = dep.name,
installed = false,
package = fallback,
}
end
return {
is_optional = dep.is_optional,
name = dep.name,
installed = false,
}
end
for _, dep in pairs(raw_deps) do
if not dep.is_optional and not out[dep.name] then
local result = resolve_dep(dep)
out[dep.name] = result
if result and result.package and not result.installed then
local raw_deps2 = get_raw_dependencies(result.package)
if raw_deps2 then
resolve_dependencies_2(raw_deps2, installed_mods, out)
end
end
end
end
return true
end
-- Resolve dependencies for a package, calls the recursive version.
local function resolve_dependencies(raw_deps, game)
assert(game)
local installed_mods = {}
local mods = {}
pkgmgr.get_game_mods(game, mods)
for _, mod in pairs(mods) do
installed_mods[mod.name] = true
end
for _, mod in pairs(pkgmgr.global_mods:get_list()) do
installed_mods[mod.name] = true
end
local out = {}
if not resolve_dependencies_2(raw_deps, installed_mods, out) then
return nil
end
local retval = {}
for _, dep in pairs(out) do
retval[#retval + 1] = dep
end
table.sort(retval, function(a, b)
return a.name < b.name
end)
return retval
end
local install_dialog = {}
function install_dialog.get_formspec()
local package = install_dialog.package
local raw_deps = install_dialog.raw_deps
local will_install_deps = install_dialog.will_install_deps
local selected_game_idx = 1
local selected_gameid = core.settings:get("menu_last_game")
local games = table.copy(pkgmgr.games)
for i=1, #games do
if selected_gameid and games[i].id == selected_gameid then
selected_game_idx = i
end
games[i] = core.formspec_escape(games[i].name)
end
local selected_game = pkgmgr.games[selected_game_idx]
local deps_to_install = 0
local deps_not_found = 0
install_dialog.dependencies = resolve_dependencies(raw_deps, selected_game)
local formatted_deps = {}
for _, dep in pairs(install_dialog.dependencies) do
formatted_deps[#formatted_deps + 1] = "#fff"
formatted_deps[#formatted_deps + 1] = core.formspec_escape(dep.name)
if dep.installed then
formatted_deps[#formatted_deps + 1] = "#ccf"
formatted_deps[#formatted_deps + 1] = fgettext("Already installed")
elseif dep.package then
formatted_deps[#formatted_deps + 1] = "#cfc"
formatted_deps[#formatted_deps + 1] = fgettext("$1 by $2", dep.package.title, dep.package.author)
deps_to_install = deps_to_install + 1
else
formatted_deps[#formatted_deps + 1] = "#f00"
formatted_deps[#formatted_deps + 1] = fgettext("Not found")
deps_not_found = deps_not_found + 1
end
end
local message_bg = "#3333"
local message
if will_install_deps then
message = fgettext("$1 and $2 dependencies will be installed.", package.title, deps_to_install)
else
message = fgettext("$1 will be installed, and $2 dependencies will be skipped.", package.title, deps_to_install)
end
if deps_not_found > 0 then
message = fgettext("$1 required dependencies could not be found.", deps_not_found) ..
" " .. fgettext("Please check that the base game is correct.", deps_not_found) ..
"\n" .. message
message_bg = mt_color_orange
end
local formspec = {
"formspec_version[3]",
"size[7,7.85]",
"style[title;border=false]",
"box[0,0;7,0.5;#3333]",
"button[0,0;7,0.5;title;", fgettext("Install $1", package.title) , "]",
"container[0.375,0.70]",
"label[0,0.25;", fgettext("Base Game:"), "]",
"dropdown[2,0;4.25,0.5;gameid;", table.concat(games, ","), ";", selected_game_idx, "]",
"label[0,0.8;", fgettext("Dependencies:"), "]",
"tablecolumns[color;text;color;text]",
"table[0,1.1;6.25,3;packages;", table.concat(formatted_deps, ","), "]",
"container_end[]",
"checkbox[0.375,5.1;will_install_deps;",
fgettext("Install missing dependencies"), ";",
will_install_deps and "true" or "false", "]",
"box[0,5.4;7,1.2;", message_bg, "]",
"textarea[0.375,5.5;6.25,1;;;", message, "]",
"container[1.375,6.85]",
"button[0,0;2,0.8;install_all;", fgettext("Install"), "]",
"button[2.25,0;2,0.8;cancel;", fgettext("Cancel"), "]",
"container_end[]",
}
return table.concat(formspec, "")
end
function install_dialog.handle_submit(this, fields)
if fields.cancel then
this:delete()
return true
end
if fields.will_install_deps ~= nil then
install_dialog.will_install_deps = core.is_yes(fields.will_install_deps)
return true
end
if fields.install_all then
queue_download(install_dialog.package)
if install_dialog.will_install_deps then
for _, dep in pairs(install_dialog.dependencies) do
if not dep.is_optional and not dep.installed and dep.package then
queue_download(dep.package)
end
end
end
this:delete()
return true
end
if fields.gameid then
for _, game in pairs(pkgmgr.games) do
if game.name == fields.gameid then
core.settings:set("menu_last_game", game.id)
break
end
end
return true
end
return false
end
function install_dialog.create(package, raw_deps)
install_dialog.dependencies = nil
install_dialog.package = package
install_dialog.raw_deps = raw_deps
install_dialog.will_install_deps = true
return dialog_create("install_dialog",
install_dialog.get_formspec,
install_dialog.handle_submit,
nil)
end
local confirm_overwrite = {}
function confirm_overwrite.get_formspec()
local package = confirm_overwrite.package
return "size[11.5,4.5,true]" ..
"label[2,2;" ..
fgettext("\"$1\" already exists. Would you like to overwrite it?", package.name) .. "]"..
"style[install;bgcolor=red]" ..
"button[3.25,3.5;2.5,0.5;install;" .. fgettext("Overwrite") .. "]" ..
"button[5.75,3.5;2.5,0.5;cancel;" .. fgettext("Cancel") .. "]"
end
function confirm_overwrite.handle_submit(this, fields)
if fields.cancel then
this:delete()
return true
end
if fields.install then
this:delete()
confirm_overwrite.callback()
return true
end
return false
end
function confirm_overwrite.create(package, callback)
assert(type(package) == "table")
assert(type(callback) == "function")
confirm_overwrite.package = package
confirm_overwrite.callback = callback
return dialog_create("confirm_overwrite",
confirm_overwrite.get_formspec,
confirm_overwrite.handle_submit,
nil)
end
local function get_file_extension(path) local function get_file_extension(path)
local parts = path:split(".") local parts = path:split(".")
return parts[#parts] return parts[#parts]
@ -226,7 +553,7 @@ function store.load()
end end
end end
local timeout = tonumber(minetest.settings:get("curl_file_download_timeout")) local timeout = tonumber(core.settings:get("curl_file_download_timeout"))
local response = http.fetch_sync({ url = url, timeout = timeout }) local response = http.fetch_sync({ url = url, timeout = timeout })
if not response.succeeded then if not response.succeeded then
return return
@ -247,6 +574,7 @@ function store.load()
end end
end end
store.packages_full_unordered = store.packages_full
store.packages = store.packages_full store.packages = store.packages_full
store.loaded = true store.loaded = true
end end
@ -255,7 +583,7 @@ function store.update_paths()
local mod_hash = {} local mod_hash = {}
pkgmgr.refresh_globals() pkgmgr.refresh_globals()
for _, mod in pairs(pkgmgr.clientmods:get_list()) do for _, mod in pairs(pkgmgr.clientmods:get_list()) do
if mod.author then if mod.author and mod.release > 0 then
mod_hash[mod.author:lower() .. "/" .. mod.name] = mod mod_hash[mod.author:lower() .. "/" .. mod.name] = mod
end end
end end
@ -263,14 +591,14 @@ function store.update_paths()
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 ~= "" then if game.author ~= "" and game.release > 0 then
game_hash[game.author:lower() .. "/" .. game.id] = game game_hash[game.author:lower() .. "/" .. game.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 then if txp.author and txp.release > 0 then
txp_hash[txp.author:lower() .. "/" .. txp.name] = txp txp_hash[txp.author:lower() .. "/" .. txp.name] = txp
end end
end end
@ -294,6 +622,33 @@ function store.update_paths()
end end
end end
function store.sort_packages()
local ret = {}
-- Add installed content
for i=1, #store.packages_full_unordered do
local package = store.packages_full_unordered[i]
if package.path then
ret[#ret + 1] = package
end
end
-- Sort installed content by title
table.sort(ret, function(a, b)
return a.title < b.title
end)
-- Add uninstalled content
for i=1, #store.packages_full_unordered do
local package = store.packages_full_unordered[i]
if not package.path then
ret[#ret + 1] = package
end
end
store.packages_full = ret
end
function store.filter_packages(query) function store.filter_packages(query)
if query == "" and filter_type == 1 then if query == "" and filter_type == 1 then
store.packages = store.packages_full store.packages = store.packages_full
@ -327,7 +682,6 @@ function store.filter_packages(query)
store.packages[#store.packages + 1] = package store.packages[#store.packages + 1] = package
end end
end end
end end
function store.get_formspec(dlgdata) function store.get_formspec(dlgdata)
@ -340,7 +694,6 @@ function store.get_formspec(dlgdata)
local W = 15.75 local W = 15.75
local H = 9.5 local H = 9.5
local formspec local formspec
if #store.packages_full > 0 then if #store.packages_full > 0 then
formspec = { formspec = {
@ -348,12 +701,13 @@ function store.get_formspec(dlgdata)
"size[15.75,9.5]", "size[15.75,9.5]",
"position[0.5,0.55]", "position[0.5,0.55]",
"style[status;border=false]", "style[status,downloading,queued;border=false]",
"container[0.375,0.375]", "container[0.375,0.375]",
"field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]", "field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]",
"field_close_on_enter[search_string;false]", "field_close_on_enter[search_string;false]",
"button[7.225,0;2,0.8;search;", fgettext("Search"), "]", "image_button[7.3,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
"image_button[8.125,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]",
"dropdown[9.6,0;2.4,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]", "dropdown[9.6,0;2.4,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]",
"container_end[]", "container_end[]",
@ -374,7 +728,7 @@ function store.get_formspec(dlgdata)
} }
if number_downloading > 0 then if number_downloading > 0 then
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;status;" formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;downloading;"
if #download_queue > 0 then if #download_queue > 0 then
formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue) formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue)
else else
@ -418,11 +772,17 @@ function store.get_formspec(dlgdata)
} }
end end
-- download/queued tooltips always have the same message
local tooltip_colors = ";#dff6f5;#302c2e]"
formspec[#formspec + 1] = "tooltip[downloading;" .. fgettext("Downloading...") .. tooltip_colors
formspec[#formspec + 1] = "tooltip[queued;" .. fgettext("Queued") .. tooltip_colors
local start_idx = (cur_page - 1) * num_per_page + 1 local start_idx = (cur_page - 1) * num_per_page + 1
for i=start_idx, math.min(#store.packages, start_idx+num_per_page-1) do for i=start_idx, math.min(#store.packages, start_idx+num_per_page-1) do
local package = store.packages[i] local package = store.packages[i]
local container_y = (i - start_idx) * 1.375 + (2*0.375 + 0.8)
formspec[#formspec + 1] = "container[0.375," formspec[#formspec + 1] = "container[0.375,"
formspec[#formspec + 1] = (i - start_idx) * 1.375 + (2*0.375 + 0.8) formspec[#formspec + 1] = container_y
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "]"
-- image -- image
@ -433,57 +793,55 @@ function store.get_formspec(dlgdata)
-- title -- title
formspec[#formspec + 1] = "label[1.875,0.1;" formspec[#formspec + 1] = "label[1.875,0.1;"
formspec[#formspec + 1] = core.formspec_escape( formspec[#formspec + 1] = core.formspec_escape(
minetest.colorize(mt_color_green, package.title) .. core.colorize(mt_color_green, package.title) ..
minetest.colorize("#BFBFBF", " by " .. package.author)) core.colorize("#BFBFBF", " by " .. package.author))
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "]"
-- buttons -- buttons
local description_width = W - 0.375*5 - 1 - 2*1.5 local left_base = "image_button[-1.55,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "container[" formspec[#formspec + 1] = "container["
formspec[#formspec + 1] = W - 0.375*2 formspec[#formspec + 1] = W - 0.375*2
formspec[#formspec + 1] = ",0.1]" formspec[#formspec + 1] = ",0.1]"
if package.downloading then if package.downloading then
formspec[#formspec + 1] = "button[-3.5,0;2,0.8;status;" formspec[#formspec + 1] = "animated_image[-1.7,-0.15;1,1;downloading;"
formspec[#formspec + 1] = fgettext("Downloading...") formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
elseif package.queued then elseif package.queued then
formspec[#formspec + 1] = "button[-3.5,0;2,0.8;status;" formspec[#formspec + 1] = left_base
formspec[#formspec + 1] = fgettext("Queued") formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "cdb_queued.png;queued]"
elseif not package.path then elseif not package.path then
formspec[#formspec + 1] = "button[-3,0;1.5,0.8;install_" local elem_name = "install_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]"
formspec[#formspec + 1] = ";" formspec[#formspec + 1] = left_base .. "cdb_add.png;" .. elem_name .. "]"
formspec[#formspec + 1] = fgettext("Install") formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Install") .. tooltip_colors
formspec[#formspec + 1] = "]"
else else
if package.installed_release < package.release then if package.installed_release < package.release then
description_width = description_width - 1.5
-- The install_ action also handles updating -- The install_ action also handles updating
formspec[#formspec + 1] = "button[-4.5,0;1.5,0.8;install_" local elem_name = "install_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#28ccdf]"
formspec[#formspec + 1] = ";" formspec[#formspec + 1] = left_base .. "cdb_update.png;" .. elem_name .. "]"
formspec[#formspec + 1] = fgettext("Update") formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Update") .. tooltip_colors
formspec[#formspec + 1] = "]" else
end
formspec[#formspec + 1] = "button[-3,0;1.5,0.8;uninstall_" local elem_name = "uninstall_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#a93b3b]"
formspec[#formspec + 1] = ";" formspec[#formspec + 1] = left_base .. "cdb_clear.png;" .. elem_name .. "]"
formspec[#formspec + 1] = fgettext("Uninstall") formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Uninstall") .. tooltip_colors
formspec[#formspec + 1] = "]" end
end end
formspec[#formspec + 1] = "button[-1.5,0;1.5,0.8;view_" local web_elem_name = "view_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "image_button[-0.7,0;0.7,0.7;" ..
formspec[#formspec + 1] = ";" core.formspec_escape(defaulttexturedir) .. "cdb_viewonline.png;" .. web_elem_name .. "]"
formspec[#formspec + 1] = fgettext("View") formspec[#formspec + 1] = "tooltip[" .. web_elem_name ..
formspec[#formspec + 1] = "]" fgettext("View more information in a web browser") .. tooltip_colors
formspec[#formspec + 1] = "container_end[]" formspec[#formspec + 1] = "container_end[]"
-- description -- description
local description_width = W - 0.375*5 - 0.85 - 2*0.7
formspec[#formspec + 1] = "textarea[1.855,0.3;" formspec[#formspec + 1] = "textarea[1.855,0.3;"
formspec[#formspec + 1] = tostring(description_width) formspec[#formspec + 1] = tostring(description_width)
formspec[#formspec + 1] = ",0.8;;;" formspec[#formspec + 1] = ",0.8;;;"
@ -504,6 +862,13 @@ function store.handle_submit(this, fields)
return true return true
end end
if fields.clear then
search_string = ""
cur_page = 1
store.filter_packages("")
return true
end
if fields.back then if fields.back then
this:delete() this:delete()
return true return true
@ -563,15 +928,47 @@ function store.handle_submit(this, fields)
assert(package) assert(package)
if fields["install_" .. i] then if fields["install_" .. i] then
queue_download(package) local install_parent
if package.type == "mod" then
install_parent = core.get_modpath()
elseif package.type == "game" then
install_parent = core.get_gamepath()
elseif package.type == "txp" then
install_parent = core.get_texturepath()
else
error("Unknown package type: " .. package.type)
end
local function on_confirm()
local deps = get_raw_dependencies(package)
if deps and has_hard_deps(deps) then
local dlg = install_dialog.create(package, deps)
dlg:set_parent(this)
this:hide()
dlg:show()
else
queue_download(package)
end
end
if not package.path and core.is_dir(install_parent .. DIR_DELIM .. package.name) then
local dlg = confirm_overwrite.create(package, on_confirm)
dlg:set_parent(this)
this:hide()
dlg:show()
else
on_confirm()
end
return true return true
end end
if fields["uninstall_" .. i] then if fields["uninstall_" .. i] then
local dlg_delmod = create_delete_content_dlg(package) local dlg = create_delete_content_dlg(package)
dlg_delmod:set_parent(this) dlg:set_parent(this)
this:hide() this:hide()
dlg_delmod:show() dlg:show()
return true return true
end end
@ -592,6 +989,9 @@ function create_store_dlg(type)
store.load() store.load()
end end
store.update_paths()
store.sort_packages()
search_string = "" search_string = ""
cur_page = 1 cur_page = 1

View File

@ -98,7 +98,7 @@ local function create_world_formspec(dialogdata)
-- Error out when no games found -- Error out when no games found
if #pkgmgr.games == 0 then if #pkgmgr.games == 0 then
return "size[12.25,3,true]" .. return "size[12.25,3,true]" ..
"box[0,0;12,2;#ff8800]" .. "box[0,0;12,2;" .. mt_color_orange .. "]" ..
"textarea[0.3,0;11.7,2;;;".. "textarea[0.3,0;11.7,2;;;"..
fgettext("You have no games installed.") .. "\n" .. fgettext("You have no games installed.") .. "\n" ..
fgettext("Download one from minetest.net") .. "]" .. fgettext("Download one from minetest.net") .. "]" ..
@ -443,7 +443,7 @@ local function create_world_buttonhandler(this, fields)
end end
if fields["mgv6_biomes"] then if fields["mgv6_biomes"] then
local entry = minetest.formspec_escape(fields["mgv6_biomes"]) local entry = core.formspec_escape(fields["mgv6_biomes"])
for b=1, #mgv6_biomes do for b=1, #mgv6_biomes do
if entry == mgv6_biomes[b][1] then if entry == mgv6_biomes[b][1] then
local ftable = core.settings:get_flags("mgv6_spflags") local ftable = core.settings:get_flags("mgv6_spflags")

View File

@ -400,7 +400,7 @@ local function parse_config_file(read_all, parse_mods)
file:close() file:close()
end end
end end
-- Parse clientmods -- Parse clientmods
local clientmods_category_initialized = false local clientmods_category_initialized = false
local clientmods = {} local clientmods = {}

View File

@ -19,6 +19,7 @@ mt_color_grey = "#AAAAAA"
mt_color_blue = "#6389FF" mt_color_blue = "#6389FF"
mt_color_green = "#72FF63" mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191" mt_color_dark_green = "#25C191"
mt_color_orange = "#FF8800"
local menupath = core.get_mainmenu_path() local menupath = core.get_mainmenu_path()
local basepath = core.get_builtin_path() local basepath = core.get_builtin_path()
@ -33,6 +34,7 @@ dofile(basepath .. "fstk" .. DIR_DELIM .. "ui.lua")
dofile(menupath .. DIR_DELIM .. "async_event.lua") dofile(menupath .. DIR_DELIM .. "async_event.lua")
dofile(menupath .. DIR_DELIM .. "common.lua") dofile(menupath .. DIR_DELIM .. "common.lua")
dofile(menupath .. DIR_DELIM .. "pkgmgr.lua") dofile(menupath .. DIR_DELIM .. "pkgmgr.lua")
dofile(menupath .. DIR_DELIM .. "serverlistmgr.lua")
dofile(menupath .. DIR_DELIM .. "textures.lua") dofile(menupath .. DIR_DELIM .. "textures.lua")
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua") dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
@ -47,7 +49,7 @@ local tabs = {}
tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua") tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
tabs.content = dofile(menupath .. DIR_DELIM .. "tab_content.lua") tabs.content = dofile(menupath .. DIR_DELIM .. "tab_content.lua")
tabs.credits = dofile(menupath .. DIR_DELIM .. "tab_credits.lua") tabs.about = dofile(menupath .. DIR_DELIM .. "tab_about.lua")
tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua") tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua")
tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua") tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua")
@ -96,7 +98,7 @@ local function init_globals()
tv_main:add(tabs.content) tv_main:add(tabs.content)
tv_main:add(tabs.settings) tv_main:add(tabs.settings)
tv_main:add(tabs.credits) tv_main:add(tabs.about)
tv_main:set_global_event_handler(main_event_handler) tv_main:set_global_event_handler(main_event_handler)
tv_main:set_fixed_size(false) tv_main:set_fixed_size(false)
@ -105,6 +107,16 @@ local function init_globals()
if last_tab and tv_main.current_tab ~= last_tab then if last_tab and tv_main.current_tab ~= last_tab then
tv_main:set_tab(last_tab) tv_main:set_tab(last_tab)
end end
-- In case the folder of the last selected game has been deleted,
-- display "Minetest" as a header
if tv_main.current_tab == "local" then
local game = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
if game == nil then
mm_texture.reset()
end
end
ui.set_default("maintab") ui.set_default("maintab")
tv_main:show() tv_main:show()

View File

@ -72,6 +72,34 @@ local function cleanup_path(temppath)
return temppath return temppath
end end
local function load_texture_packs(txtpath, retval)
local list = core.get_dir_list(txtpath, true)
local current_texture_path = core.settings:get("texture_path")
for _, item in ipairs(list) do
if item ~= "base" then
local name = item
local path = txtpath .. DIR_DELIM .. item .. DIR_DELIM
if path == current_texture_path then
name = fgettext("$1 (Enabled)", name)
end
local conf = Settings(path .. "texture_pack.conf")
retval[#retval + 1] = {
name = item,
author = conf:get("author"),
release = tonumber(conf:get("release")) or 0,
list_name = name,
type = "txp",
path = path,
enabled = path == current_texture_path,
}
end
end
end
function get_mods(path,retval,modpack) function get_mods(path,retval,modpack)
local mods = core.get_dir_list(path, true) local mods = core.get_dir_list(path, true)
@ -107,12 +135,12 @@ function get_mods(path,retval,modpack)
-- Read from config -- Read from config
toadd.name = name toadd.name = name
toadd.author = mod_conf.author toadd.author = mod_conf.author
toadd.release = tonumber(mod_conf.release or "0") toadd.release = tonumber(mod_conf.release) or 0
toadd.path = prefix toadd.path = prefix
toadd.type = "mod" toadd.type = "mod"
-- Check modpack.txt -- Check modpack.txt
-- Note: modpack.conf is already checked above -- Note: modpack.conf is already checked above
local modpackfile = io.open(prefix .. DIR_DELIM .. "modpack.txt") local modpackfile = io.open(prefix .. DIR_DELIM .. "modpack.txt")
if modpackfile then if modpackfile then
modpackfile:close() modpackfile:close()
@ -136,32 +164,13 @@ pkgmgr = {}
function pkgmgr.get_texture_packs() function pkgmgr.get_texture_packs()
local txtpath = core.get_texturepath() local txtpath = core.get_texturepath()
local list = core.get_dir_list(txtpath, true) local txtpath_system = core.get_texturepath_share()
local retval = {} local retval = {}
local current_texture_path = core.settings:get("texture_path") load_texture_packs(txtpath, retval)
-- on portable versions these two paths coincide. It avoids loading the path twice
for _, item in ipairs(list) do if txtpath ~= txtpath_system then
if item ~= "base" then load_texture_packs(txtpath_system, retval)
local name = item
local path = txtpath .. DIR_DELIM .. item .. DIR_DELIM
if path == current_texture_path then
name = fgettext("$1 (Enabled)", name)
end
local conf = Settings(path .. "texture_pack.conf")
retval[#retval + 1] = {
name = item,
author = conf:get("author"),
release = tonumber(conf:get("release") or "0"),
list_name = name,
type = "txp",
path = path,
enabled = path == current_texture_path,
}
end
end end
table.sort(retval, function(a, b) table.sort(retval, function(a, b)
@ -404,18 +413,7 @@ function pkgmgr.is_modpack_entirely_enabled(data, name)
end end
---------- toggles or en/disables a mod or modpack and its dependencies -------- ---------- toggles or en/disables a mod or modpack and its dependencies --------
function pkgmgr.enable_mod(this, toset) local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
local list = this.data.list:get_list()
local mod = list[this.data.selected_mod]
-- Game mods can't be enabled or disabled
if mod.is_game_content then
return
end
local toggled_mods = {}
local enabled_mods = {}
if not mod.is_modpack then if not mod.is_modpack then
-- Toggle or en/disable the mod -- Toggle or en/disable the mod
if toset == nil then if toset == nil then
@ -434,23 +432,29 @@ function pkgmgr.enable_mod(this, toset)
-- interleaved unsupported -- interleaved unsupported
for i = 1, #list do for i = 1, #list do
if list[i].modpack == mod.name then if list[i].modpack == mod.name then
if toset == nil then toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, list[i])
toset = not list[i].enabled
end
if list[i].enabled ~= toset then
list[i].enabled = toset
toggled_mods[#toggled_mods+1] = list[i].name
end
if toset then
enabled_mods[list[i].name] = true
end
end end
end end
end end
end
function pkgmgr.enable_mod(this, toset)
local list = this.data.list:get_list()
local mod = list[this.data.selected_mod]
-- Game mods can't be enabled or disabled
if mod.is_game_content then
return
end
local toggled_mods = {}
local enabled_mods = {}
toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
if not toset then if not toset then
-- Mod(s) were disabled, so no dependencies need to be enabled -- Mod(s) were disabled, so no dependencies need to be enabled
table.sort(toggled_mods) table.sort(toggled_mods)
minetest.log("info", "Following mods were disabled: " .. core.log("info", "Following mods were disabled: " ..
table.concat(toggled_mods, ", ")) table.concat(toggled_mods, ", "))
return return
end end
@ -487,7 +491,7 @@ function pkgmgr.enable_mod(this, toset)
enabled_mods[name] = true enabled_mods[name] = true
local mod_to_enable = list[mod_ids[name]] local mod_to_enable = list[mod_ids[name]]
if not mod_to_enable then if not mod_to_enable then
minetest.log("warning", "Mod dependency \"" .. name .. core.log("warning", "Mod dependency \"" .. name ..
"\" not found!") "\" not found!")
else else
if mod_to_enable.enabled == false then if mod_to_enable.enabled == false then
@ -508,7 +512,7 @@ function pkgmgr.enable_mod(this, toset)
-- Log the list of enabled mods -- Log the list of enabled mods
table.sort(toggled_mods) table.sort(toggled_mods)
minetest.log("info", "Following mods were enabled: " .. core.log("info", "Following mods were enabled: " ..
table.concat(toggled_mods, ", ")) table.concat(toggled_mods, ", "))
end end

View File

@ -0,0 +1,252 @@
--Minetest
--Copyright (C) 2020 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
serverlistmgr = {}
--------------------------------------------------------------------------------
local function order_server_list(list)
local res = {}
--orders the favorite list after support
for i = 1, #list do
local fav = list[i]
if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
res[#res + 1] = fav
end
end
for i = 1, #list do
local fav = list[i]
if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
res[#res + 1] = fav
end
end
return res
end
local public_downloading = false
--------------------------------------------------------------------------------
function serverlistmgr.sync()
if not serverlistmgr.servers then
serverlistmgr.servers = {{
name = fgettext("Loading..."),
description = fgettext_ne("Try reenabling public serverlist and check your internet connection.")
}}
end
local serverlist_url = core.settings:get("serverlist_url") or ""
if not core.get_http_api or serverlist_url == "" then
serverlistmgr.servers = {{
name = fgettext("Public server list is disabled"),
description = ""
}}
return
end
if public_downloading then
return
end
public_downloading = true
core.handle_async(
function(param)
local http = core.get_http_api()
local url = ("%s/list?proto_version_min=%d&proto_version_max=%d"):format(
core.settings:get("serverlist_url"),
core.get_min_supp_proto(),
core.get_max_supp_proto())
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return {}
end
local retval = core.parse_json(response.data)
return retval and retval.list or {}
end,
nil,
function(result)
public_downloading = nil
local favs = order_server_list(result)
if favs[1] then
serverlistmgr.servers = favs
end
core.event_handler("Refresh")
end
)
end
--------------------------------------------------------------------------------
local function get_favorites_path(folder)
local base = core.get_user_path() .. DIR_DELIM .. "client" .. DIR_DELIM .. "serverlist" .. DIR_DELIM
if folder then
return base
end
return base .. core.settings:get("serverlist_file")
end
--------------------------------------------------------------------------------
local function save_favorites(favorites)
local filename = core.settings:get("serverlist_file")
-- If setting specifies legacy format change the filename to the new one
if filename:sub(#filename - 3):lower() == ".txt" then
core.settings:set("serverlist_file", filename:sub(1, #filename - 4) .. ".json")
end
assert(core.create_dir(get_favorites_path(true)))
core.safe_file_write(get_favorites_path(), core.write_json(favorites))
end
--------------------------------------------------------------------------------
function serverlistmgr.read_legacy_favorites(path)
local file = io.open(path, "r")
if not file then
return nil
end
local lines = {}
for line in file:lines() do
lines[#lines + 1] = line
end
file:close()
local favorites = {}
local i = 1
while i < #lines do
local function pop()
local line = lines[i]
i = i + 1
return line and line:trim()
end
if pop():lower() == "[server]" then
local name = pop()
local address = pop()
local port = tonumber(pop())
local description = pop()
if name == "" then
name = nil
end
if description == "" then
description = nil
end
if not address or #address < 3 then
core.log("warning", "Malformed favorites file, missing address at line " .. i)
elseif not port or port < 1 or port > 65535 then
core.log("warning", "Malformed favorites file, missing port at line " .. i)
elseif (name and name:upper() == "[SERVER]") or
(address and address:upper() == "[SERVER]") or
(description and description:upper() == "[SERVER]") then
core.log("warning", "Potentially malformed favorites file, overran at line " .. i)
else
favorites[#favorites + 1] = {
name = name,
address = address,
port = port,
description = description
}
end
end
end
return favorites
end
--------------------------------------------------------------------------------
local function read_favorites()
local path = get_favorites_path()
-- If new format configured fall back to reading the legacy file
if path:sub(#path - 4):lower() == ".json" then
local file = io.open(path, "r")
if file then
local json = file:read("*all")
file:close()
return core.parse_json(json)
end
path = path:sub(1, #path - 5) .. ".txt"
end
local favs = serverlistmgr.read_legacy_favorites(path)
if favs then
save_favorites(favs)
os.remove(path)
end
return favs
end
--------------------------------------------------------------------------------
local function delete_favorite(favorites, del_favorite)
for i=1, #favorites do
local fav = favorites[i]
if fav.address == del_favorite.address and fav.port == del_favorite.port then
table.remove(favorites, i)
return
end
end
end
--------------------------------------------------------------------------------
function serverlistmgr.get_favorites()
if serverlistmgr.favorites then
return serverlistmgr.favorites
end
serverlistmgr.favorites = {}
-- Add favorites, removing duplicates
local seen = {}
for _, fav in ipairs(read_favorites() or {}) do
local key = ("%s:%d"):format(fav.address:lower(), fav.port)
if not seen[key] then
seen[key] = true
serverlistmgr.favorites[#serverlistmgr.favorites + 1] = fav
end
end
return serverlistmgr.favorites
end
--------------------------------------------------------------------------------
function serverlistmgr.add_favorite(new_favorite)
assert(type(new_favorite.port) == "number")
-- Whitelist favorite keys
new_favorite = {
name = new_favorite.name,
address = new_favorite.address,
port = new_favorite.port,
description = new_favorite.description,
}
local favorites = serverlistmgr.get_favorites()
delete_favorite(favorites, new_favorite)
table.insert(favorites, 1, new_favorite)
save_favorites(favorites)
end
--------------------------------------------------------------------------------
function serverlistmgr.delete_favorite(del_favorite)
local favorites = serverlistmgr.get_favorites()
delete_favorite(favorites, del_favorite)
save_favorites(favorites)
end

View File

@ -24,6 +24,7 @@ local dragonfire_team = {
"joshia_wi [Developer]", "joshia_wi [Developer]",
"Code-Sploit [Developer]", "Code-Sploit [Developer]",
"DerZombiiie [User Support]", "DerZombiiie [User Support]",
"Rtx [User Support]",
} }
local core_developers = { local core_developers = {
@ -32,28 +33,37 @@ local core_developers = {
"Nathanaël Courant (Nore/Ekdohibs) <nore@mesecons.net>", "Nathanaël Courant (Nore/Ekdohibs) <nore@mesecons.net>",
"Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>", "Loic Blot (nerzhul/nrz) <loic.blot@unix-experience.fr>",
"paramat", "paramat",
"Auke Kok (sofar) <sofar@foo-projects.org>",
"Andrew Ward (rubenwardy) <rw@rubenwardy.com>", "Andrew Ward (rubenwardy) <rw@rubenwardy.com>",
"Krock/SmallJoker <mk939@ymail.com>", "Krock/SmallJoker <mk939@ymail.com>",
"Lars Hofhansl <larsh@apache.org>", "Lars Hofhansl <larsh@apache.org>",
"Pierre-Yves Rollo <dev@pyrollo.com>",
"v-rob <robinsonvincent89@gmail.com>",
} }
-- For updating active/previous contributors, see the script in ./util/gather_git_credits.py
local active_contributors = { local active_contributors = {
"Hugues Ross [Formspecs]", "Wuzzy [devtest game, visual corrections]",
"Zughy [Visual improvements, various fixes]",
"Maksim (MoNTE48) [Android]", "Maksim (MoNTE48) [Android]",
"DS [Formspecs]", "numzero [Graphics and rendering]",
"pyrollo [Formspecs: Hypertext]", "appgurueu [Various internal fixes]",
"v-rob [Formspecs]", "Desour [Formspec and vector API changes]",
"Jordach [set_sky]", "HybridDog [Rendering fixes and documentation]",
"random-geek [Formspecs]", "Hugues Ross [Graphics-related improvements]",
"Wuzzy [Pathfinder, builtin, translations]", "ANAND (ClobberXD) [Mouse buttons rebinding]",
"ANAND (ClobberXD) [Fixes, per-player FOV]", "luk3yx [Fixes]",
"Warr1024 [Fixes]", "hecks [Audiovisuals, Lua API]",
"Paul Ouellette (pauloue) [Fixes, Script API]", "LoneWolfHT [Object crosshair, documentation fixes]",
"Jean-Patrick G (kilbith) <jeanpatrick.guerrero@gmail.com> [Audiovisuals]", "Lejo [Server-related improvements]",
"HybridDog [Script API]", "EvidenceB [Compass HUD element]",
"Paul Ouellette (pauloue) [Lua API, documentation]",
"TheTermos [Collision detection, physics]",
"David CARLIER [Unix & Haiku build fixes]",
"dcbrwn [Object shading]", "dcbrwn [Object shading]",
"srifqi [Fixes]", "Elias Fleckenstein [API features/fixes]",
"Jean-Patrick Guerrero (kilbith) [model element, visual fixes]",
"k.h.lai [Memory leak fixes, documentation]",
} }
local previous_core_developers = { local previous_core_developers = {
@ -69,30 +79,23 @@ local previous_core_developers = {
"sapier", "sapier",
"Zeno", "Zeno",
"ShadowNinja <shadowninja@minetest.net>", "ShadowNinja <shadowninja@minetest.net>",
"Auke Kok (sofar) <sofar@foo-projects.org>",
} }
local previous_contributors = { local previous_contributors = {
"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest Logo]", "Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest Logo]",
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
"red-001 <red-001@outlook.ie>", "red-001 <red-001@outlook.ie>",
"numberZero [Audiovisuals: meshgen]",
"Giuseppe Bilotta", "Giuseppe Bilotta",
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
"MirceaKitsune <mirceakitsune@gmail.com>", "MirceaKitsune <mirceakitsune@gmail.com>",
"Constantin Wenger (SpeedProg)", "Constantin Wenger (SpeedProg)",
"Ciaran Gultnieks (CiaranG)", "Ciaran Gultnieks (CiaranG)",
"stujones11 [Android UX improvements]", "stujones11 [Android UX improvements]",
"Jeija <jeija@mesecons.net> [HTTP, particles]",
"Vincent Glize (Dumbeldor) [Cleanups, CSM APIs]",
"Ben Deutsch [Rendering, Fixes, SQLite auth]",
"TeTpaAka [Hand overriding, nametag colors]",
"Rui [Sound Pitch]",
"Duane Robertson <duane@duanerobertson.com> [MGValleys]",
"Raymoo [Tool Capabilities]",
"Rogier <rogier777@gmail.com> [Fixes]", "Rogier <rogier777@gmail.com> [Fixes]",
"Gregory Currie (gregorycu) [optimisation]", "Gregory Currie (gregorycu) [optimisation]",
"TriBlade9 <triblade9@mail.com> [Audiovisuals]", "srifqi [Fixes]",
"T4im [Profiler]", "JacobF",
"Jurgen Doser (doserj) <jurgen.doser@gmail.com>", "Jeija <jeija@mesecons.net> [HTTP, particles]",
} }
local function buildCreditList(source) local function buildCreditList(source)
@ -104,14 +107,15 @@ local function buildCreditList(source)
end end
return { return {
name = "credits", name = "about",
caption = fgettext("Credits"), caption = fgettext("About"),
cbf_formspec = function(tabview, name, tabdata) cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png" local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version() local version = core.get_version()
return "image[0.5,1;" .. core.formspec_escape(logofile) .. "]" .. local fs = "image[0.75,0.5;2.2,2.2;" .. core.formspec_escape(logofile) .. "]" ..
"label[0.5,2.8;" .. version.project .. " " .. version.string .. "]" .. "style[label_button;border=false]" ..
"button[0.5,3;2,2;homepage;minetest.net]" .. "button[0.5,2;2.5,2;label_button;" .. version.project .. " " .. version.string .. "]" ..
"button[0.75,2.75;2,2;homepage;minetest.net]" ..
"tablecolumns[color;text]" .. "tablecolumns[color;text]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" .. "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[3.5,-0.25;8.5,6.05;list_credits;" .. "table[3.5,-0.25;8.5,6.05;list_credits;" ..
@ -126,10 +130,28 @@ return {
"#FFFF00," .. fgettext("Previous Contributors") .. ",," .. "#FFFF00," .. fgettext("Previous Contributors") .. ",," ..
buildCreditList(previous_contributors) .. "," .. buildCreditList(previous_contributors) .. "," ..
";1]" ";1]"
-- Render information
fs = fs .. "label[0.75,4.9;" ..
fgettext("Active renderer:") .. "\n" ..
core.formspec_escape(core.get_screen_info().render_info) .. "]"
if PLATFORM ~= "Android" then
fs = fs .. "tooltip[userdata;" ..
fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" ..
"and texture packs in a file manager / explorer.") .. "]"
fs = fs .. "button[0,4;3.5,1;userdata;" .. fgettext("Open User Data Directory") .. "]"
end
return fs
end, end,
cbf_button_handler = function(this, fields, name, tabdata) cbf_button_handler = function(this, fields, name, tabdata)
if fields.homepage then if fields.homepage then
core.open_url("https://www.minetest.net") core.open_url("https://www.minetest.net")
end end
if fields.userdata then
core.open_dir(core.get_user_path())
end
end, end,
} }

View File

@ -50,12 +50,12 @@ local function get_formspec(tabview, name, tabdata)
packages = filterlist.create(get_data, pkgmgr.compare_package, packages = filterlist.create(get_data, pkgmgr.compare_package,
is_equal, nil, {}) is_equal, nil, {})
local filename = core.get_clientmodpath() .. DIR_DELIM .. "mods.conf" local filename = core.get_clientmodpath() .. DIR_DELIM .. "mods.conf"
local conffile = Settings(filename) local conffile = Settings(filename)
local mods = conffile:to_table() local mods = conffile:to_table()
for i = 1, #packages_raw do for i = 1, #packages_raw do
local mod = packages_raw[i] local mod = packages_raw[i]
if mod.is_clientside and not mod.is_modpack then if mod.is_clientside and not mod.is_modpack then
@ -71,7 +71,7 @@ local function get_formspec(tabview, name, tabdata)
mods["load_mod_" .. mod.name] = nil mods["load_mod_" .. mod.name] = nil
end end
end end
-- Remove mods that are not present anymore -- Remove mods that are not present anymore
for key in pairs(mods) do for key in pairs(mods) do
if key:sub(1, 9) == "load_mod_" then if key:sub(1, 9) == "load_mod_" then
@ -205,30 +205,44 @@ local function get_formspec(tabview, name, tabdata)
return retval return retval
end end
--------------------------------------------------------------------------------
local function handle_doubleclick(pkg, pkg_name)
if pkg.type == "txp" then
if core.settings:get("texture_path") == pkg.path then
core.settings:set("texture_path", "")
else
core.settings:set("texture_path", pkg.path)
end
packages = nil
elseif pkg.is_clientside then
pkgmgr.enable_mod({data = {list = packages, selected_mod = pkg_name}})
packages = nil
end
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local function handle_buttons(tabview, fields, tabname, tabdata) local function handle_buttons(tabview, fields, tabname, tabdata)
if fields["pkglist"] ~= nil then if fields["pkglist"] ~= nil then
local event = core.explode_table_event(fields["pkglist"]) local event = core.explode_table_event(fields["pkglist"])
tabdata.selected_pkg = event.row tabdata.selected_pkg = event.row
local mod = packages:get_list()[tabdata.selected_pkg] if event.type == "DCL" then
handle_doubleclick(packages:get_list()[tabdata.selected_pkg], tabdata.selected_pkg)
if event.type == "DCL" and mod.is_clientside then
pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}})
packages = nil
end end
return true return true
end end
if fields.btn_mod_mgr_mp_enable ~= nil or if fields.btn_mod_mgr_mp_enable ~= nil or
fields.btn_mod_mgr_mp_disable ~= nil then fields.btn_mod_mgr_mp_disable ~= nil then
pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}}, fields.btn_mod_mgr_mp_enable ~= nil) pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}},
fields.btn_mod_mgr_mp_enable ~= nil)
packages = nil packages = nil
return true return true
end end
if fields.btn_mod_mgr_enable_mod ~= nil or if fields.btn_mod_mgr_enable_mod ~= nil or
fields.btn_mod_mgr_disable_mod ~= nil then fields.btn_mod_mgr_disable_mod ~= nil then
pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}}, fields.btn_mod_mgr_enable_mod ~= nil) pkgmgr.enable_mod({data = {list = packages, selected_mod = tabdata.selected_pkg}},
fields.btn_mod_mgr_enable_mod ~= nil)
packages = nil packages = nil
return true return true
end end

View File

@ -18,6 +18,7 @@
local enable_gamebar = PLATFORM ~= "Android" local enable_gamebar = PLATFORM ~= "Android"
local current_game, singleplayer_refresh_gamebar local current_game, singleplayer_refresh_gamebar
if enable_gamebar then if enable_gamebar then
function current_game() function current_game()
local last_game_id = core.settings:get("menu_last_game") local last_game_id = core.settings:get("menu_last_game")
@ -115,7 +116,7 @@ local function get_formspec(tabview, name, tabdata)
retval = retval .. retval = retval ..
"button[3.9,3.8;2.8,1;world_delete;".. fgettext("Delete") .. "]" .. "button[3.9,3.8;2.8,1;world_delete;".. fgettext("Delete") .. "]" ..
"button[6.55,3.8;2.8,1;world_configure;".. fgettext("Configure") .. "]" .. "button[6.55,3.8;2.8,1;world_configure;".. fgettext("Select Mods") .. "]" ..
"button[9.2,3.8;2.8,1;world_create;".. fgettext("New") .. "]" .. "button[9.2,3.8;2.8,1;world_create;".. fgettext("New") .. "]" ..
"label[3.9,-0.05;".. fgettext("Select World:") .. "]".. "label[3.9,-0.05;".. fgettext("Select World:") .. "]"..
"checkbox[0,-0.20;cb_creative_mode;".. fgettext("Creative Mode") .. ";" .. "checkbox[0,-0.20;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..

View File

@ -15,17 +15,50 @@
--with this program; if not, write to the Free Software Foundation, Inc., --with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-------------------------------------------------------------------------------- local function get_sorted_servers()
local servers = {
fav = {},
public = {},
incompatible = {}
}
local favs = serverlistmgr.get_favorites()
local taken_favs = {}
local result = menudata.search_result or serverlistmgr.servers
for _, server in ipairs(result) do
server.is_favorite = false
for index, fav in ipairs(favs) do
if server.address == fav.address and server.port == fav.port then
taken_favs[index] = true
server.is_favorite = true
break
end
end
server.is_compatible = is_server_protocol_compat(server.proto_min, server.proto_max)
if server.is_favorite then
table.insert(servers.fav, server)
elseif server.is_compatible then
table.insert(servers.public, server)
else
table.insert(servers.incompatible, server)
end
end
if not menudata.search_result then
for index, fav in ipairs(favs) do
if not taken_favs[index] then
table.insert(servers.fav, fav)
end
end
end
return servers
end
local function get_formspec(tabview, name, tabdata) local function get_formspec(tabview, name, tabdata)
-- Update the cached supported proto info, -- Update the cached supported proto info,
-- it may have changed after a change by the settings menu. -- it may have changed after a change by the settings menu.
common_update_cached_supp_proto() common_update_cached_supp_proto()
local fav_selected
if menudata.search_result then
fav_selected = menudata.search_result[tabdata.fav_selected]
else
fav_selected = menudata.favorites[tabdata.fav_selected]
end
if not tabdata.search_for then if not tabdata.search_for then
tabdata.search_for = "" tabdata.search_for = ""
@ -33,128 +66,221 @@ local function get_formspec(tabview, name, tabdata)
local retval = local retval =
-- Search -- Search
"field[0.15,0.075;5.91,1;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" .. "field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
"button[5.62,-0.25;1.5,1;btn_mp_search;" .. fgettext("Search") .. "]" .. "container[7.25,0.25]" ..
"image_button[6.97,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "refresh.png") "image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
.. ";btn_mp_refresh;]" .. "image_button[0.75,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" ..
"image_button[1.5,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "refresh.png") .. ";btn_mp_refresh;]" ..
"tooltip[btn_mp_clear;" .. fgettext("Clear") .. "]" ..
"tooltip[btn_mp_search;" .. fgettext("Search") .. "]" ..
"tooltip[btn_mp_refresh;" .. fgettext("Refresh") .. "]" ..
"container_end[]" ..
"container[9.75,0]" ..
"box[0,0;5.75,7;#666666]" ..
-- Address / Port -- Address / Port
"label[7.75,-0.25;" .. fgettext("Address / Port") .. "]" .. "label[0.25,0.35;" .. fgettext("Address") .. "]" ..
"field[8,0.65;3.25,0.5;te_address;;" .. "label[4.25,0.35;" .. fgettext("Port") .. "]" ..
"field[0.25,0.5;4,0.75;te_address;;" ..
core.formspec_escape(core.settings:get("address")) .. "]" .. core.formspec_escape(core.settings:get("address")) .. "]" ..
"field[11.1,0.65;1.4,0.5;te_port;;" .. "field[4.25,0.5;1.25,0.75;te_port;;" ..
core.formspec_escape(core.settings:get("remote_port")) .. "]" .. core.formspec_escape(core.settings:get("remote_port")) .. "]" ..
-- Name / Password -- Name / Password
"label[7.75,0.95;" .. fgettext("Name / Password") .. "]" .. "label[0.25,1.55;" .. fgettext("Name") .. "]" ..
"field[8,1.85;2.9,0.5;te_name;;" .. "label[3,1.55;" .. fgettext("Password") .. "]" ..
"field[0.25,1.75;2.75,0.75;te_name;;" ..
core.formspec_escape(core.settings:get("name")) .. "]" .. core.formspec_escape(core.settings:get("name")) .. "]" ..
"pwdfield[10.73,1.85;1.77,0.5;te_pwd;]" .. "pwdfield[3,1.75;2.5,0.75;te_pwd;]" ..
-- Description Background -- Description Background
"box[7.73,2.25;4.25,2.6;#999999]".. "label[0.25,2.75;" .. fgettext("Server Description") .. "]" ..
"box[0.25,3;5.25,2.75;#999999]"..
-- Connect -- Connect
"button[9.88,4.9;2.3,1;btn_mp_connect;" .. fgettext("Connect") .. "]" "button[3,6;2.5,0.75;btn_mp_connect;" .. fgettext("Connect") .. "]"
if tabdata.fav_selected and fav_selected then if tabdata.selected then
if gamedata.fav then if gamedata.fav then
retval = retval .. "button[7.73,4.9;2.3,1;btn_delete_favorite;" .. retval = retval .. "button[0.25,6;2.5,0.75;btn_delete_favorite;" ..
fgettext("Del. Favorite") .. "]" fgettext("Del. Favorite") .. "]"
end end
if fav_selected.description then if gamedata.serverdescription then
retval = retval .. "textarea[8.1,2.3;4.23,2.9;;;" .. retval = retval .. "textarea[0.25,3;5.25,2.75;;;" ..
core.formspec_escape((gamedata.serverdescription or ""), true) .. "]" core.formspec_escape(gamedata.serverdescription) .. "]"
end end
end end
--favourites retval = retval .. "container_end[]"
-- Table
retval = retval .. "tablecolumns[" .. retval = retval .. "tablecolumns[" ..
image_column(fgettext("Favorite"), "favorite") .. ";" .. "image,tooltip=" .. fgettext("Ping") .. "," ..
image_column(fgettext("Ping")) .. ",padding=0.25;" .. "0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
"color,span=3;" .. "1=" .. core.formspec_escape(defaulttexturedir .. "server_ping_4.png") .. "," ..
"text,align=right;" .. -- clients "2=" .. core.formspec_escape(defaulttexturedir .. "server_ping_3.png") .. "," ..
"text,align=center,padding=0.25;" .. -- "/" "3=" .. core.formspec_escape(defaulttexturedir .. "server_ping_2.png") .. "," ..
"text,align=right,padding=0.25;" .. -- clients_max "4=" .. core.formspec_escape(defaulttexturedir .. "server_ping_1.png") .. "," ..
image_column(fgettext("Creative mode"), "creative") .. ",padding=1;" .. "5=" .. core.formspec_escape(defaulttexturedir .. "server_favorite.png") .. "," ..
image_column(fgettext("Damage enabled"), "damage") .. ",padding=0.25;" .. "6=" .. core.formspec_escape(defaulttexturedir .. "server_public.png") .. "," ..
--~ PvP = Player versus Player "7=" .. core.formspec_escape(defaulttexturedir .. "server_incompatible.png") .. ";" ..
image_column(fgettext("PvP enabled"), "pvp") .. ",padding=0.25;" ..
"color,span=1;" .. "color,span=1;" ..
"text,padding=1]" .. "text,align=inline;"..
"table[-0.15,0.6;7.75,5.15;favourites;" "color,span=1;" ..
"text,align=inline,width=4.25;" ..
"image,tooltip=" .. fgettext("Creative mode") .. "," ..
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_creative.png") .. "," ..
"align=inline,padding=0.25,width=1.5;" ..
--~ PvP = Player versus Player
"image,tooltip=" .. fgettext("Damage / PvP") .. "," ..
"0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") .. "," ..
"1=" .. core.formspec_escape(defaulttexturedir .. "server_flags_damage.png") .. "," ..
"2=" .. core.formspec_escape(defaulttexturedir .. "server_flags_pvp.png") .. "," ..
"align=inline,padding=0.25,width=1.5;" ..
"color,align=inline,span=1;" ..
"text,align=inline,padding=1]" ..
"table[0.25,1;9.25,5.75;servers;"
if menudata.search_result then local servers = get_sorted_servers()
for i = 1, #menudata.search_result do
local favs = core.get_favorites("local")
local server = menudata.search_result[i]
for fav_id = 1, #favs do local dividers = {
if server.address == favs[fav_id].address and fav = "5,#ffff00," .. fgettext("Favorites") .. ",,,0,0,,",
server.port == favs[fav_id].port then public = "6,#4bdd42," .. fgettext("Public Servers") .. ",,,0,0,,",
server.is_favorite = true incompatible = "7,"..mt_color_grey.."," .. fgettext("Incompatible Servers") .. ",,,0,0,,"
end }
end local order = {"fav", "public", "incompatible"}
if i ~= 1 then tabdata.lookup = {} -- maps row number to server
retval = retval .. "," local rows = {}
for _, section in ipairs(order) do
local section_servers = servers[section]
if next(section_servers) ~= nil then
rows[#rows + 1] = dividers[section]
for _, server in ipairs(section_servers) do
tabdata.lookup[#rows + 1] = server
rows[#rows + 1] = render_serverlist_row(server)
end end
retval = retval .. render_serverlist_row(server, server.is_favorite)
end
elseif #menudata.favorites > 0 then
local favs = core.get_favorites("local")
if #favs > 0 then
for i = 1, #favs do
for j = 1, #menudata.favorites do
if menudata.favorites[j].address == favs[i].address and
menudata.favorites[j].port == favs[i].port then
table.insert(menudata.favorites, i, table.remove(menudata.favorites, j))
end
end
if favs[i].address ~= menudata.favorites[i].address then
table.insert(menudata.favorites, i, favs[i])
end
end
end
retval = retval .. render_serverlist_row(menudata.favorites[1], (#favs > 0))
for i = 2, #menudata.favorites do
retval = retval .. "," .. render_serverlist_row(menudata.favorites[i], (i <= #favs))
end end
end end
if tabdata.fav_selected then retval = retval .. table.concat(rows, ",")
retval = retval .. ";" .. tabdata.fav_selected .. "]"
if tabdata.selected then
retval = retval .. ";" .. tabdata.selected .. "]"
else else
retval = retval .. ";0]" retval = retval .. ";0]"
end end
return retval return retval, "size[15.5,7,false]real_coordinates[true]"
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local function main_button_handler(tabview, fields, name, tabdata)
local serverlist = menudata.search_result or menudata.favorites
local function search_server_list(input)
menudata.search_result = nil
if #serverlistmgr.servers < 2 then
return
end
-- setup the keyword list
local keywords = {}
for word in input:gmatch("%S+") do
word = word:gsub("(%W)", "%%%1")
table.insert(keywords, word)
end
if #keywords == 0 then
return
end
menudata.search_result = {}
-- Search the serverlist
local search_result = {}
for i = 1, #serverlistmgr.servers do
local server = serverlistmgr.servers[i]
local found = 0
for k = 1, #keywords do
local keyword = keywords[k]
if server.name then
local sername = server.name:lower()
local _, count = sername:gsub(keyword, keyword)
found = found + count * 4
end
if server.description then
local desc = server.description:lower()
local _, count = desc:gsub(keyword, keyword)
found = found + count * 2
end
end
if found > 0 then
local points = (#serverlistmgr.servers - i) / 5 + found
server.points = points
table.insert(search_result, server)
end
end
if #search_result == 0 then
return
end
table.sort(search_result, function(a, b)
return a.points > b.points
end)
menudata.search_result = search_result
end
local function set_selected_server(tabdata, idx, server)
-- reset selection
if idx == nil or server == nil then
tabdata.selected = nil
core.settings:set("address", "")
core.settings:set("remote_port", "30000")
return
end
local address = server.address
local port = server.port
gamedata.serverdescription = server.description
gamedata.fav = false
for _, fav in ipairs(serverlistmgr.get_favorites()) do
if address == fav.address and port == fav.port then
gamedata.fav = true
break
end
end
if address and port then
core.settings:set("address", address)
core.settings:set("remote_port", port)
end
tabdata.selected = idx
end
local function main_button_handler(tabview, fields, name, tabdata)
if fields.te_name then if fields.te_name then
gamedata.playername = fields.te_name gamedata.playername = fields.te_name
core.settings:set("name", fields.te_name) core.settings:set("name", fields.te_name)
end end
if fields.favourites then if fields.servers then
local event = core.explode_table_event(fields.favourites) local event = core.explode_table_event(fields.servers)
local fav = serverlist[event.row] local server = tabdata.lookup[event.row]
if event.type == "DCL" then if server then
if event.row <= #serverlist then if event.type == "DCL" then
if menudata.favorites_is_public and if not is_server_protocol_compat_or_error(
not is_server_protocol_compat_or_error( server.proto_min, server.proto_max) then
fav.proto_min, fav.proto_max) then
return true return true
end end
gamedata.address = fav.address gamedata.address = server.address
gamedata.port = fav.port gamedata.port = server.port
gamedata.playername = fields.te_name gamedata.playername = fields.te_name
gamedata.selected_world = 0 gamedata.selected_world = 0
@ -162,150 +288,54 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.password = fields.te_pwd gamedata.password = fields.te_pwd
end end
gamedata.servername = fav.name gamedata.servername = server.name
gamedata.serverdescription = fav.description gamedata.serverdescription = server.description
if gamedata.address and gamedata.port then if gamedata.address and gamedata.port then
core.settings:set("address", gamedata.address) core.settings:set("address", gamedata.address)
core.settings:set("remote_port", gamedata.port) core.settings:set("remote_port", gamedata.port)
core.start() core.start()
end end
return true
end end
return true if event.type == "CHG" then
end set_selected_server(tabdata, event.row, server)
return true
if event.type == "CHG" then
if event.row <= #serverlist then
gamedata.fav = false
local favs = core.get_favorites("local")
local address = fav.address
local port = fav.port
gamedata.serverdescription = fav.description
for i = 1, #favs do
if fav.address == favs[i].address and
fav.port == favs[i].port then
gamedata.fav = true
end
end
if address and port then
core.settings:set("address", address)
core.settings:set("remote_port", port)
end
tabdata.fav_selected = event.row
end end
return true
end end
end end
if fields.key_up or fields.key_down then
local fav_idx = core.get_table_index("favourites")
local fav = serverlist[fav_idx]
if fav_idx then
if fields.key_up and fav_idx > 1 then
fav_idx = fav_idx - 1
elseif fields.key_down and fav_idx < #menudata.favorites then
fav_idx = fav_idx + 1
end
else
fav_idx = 1
end
if not menudata.favorites or not fav then
tabdata.fav_selected = 0
return true
end
local address = fav.address
local port = fav.port
gamedata.serverdescription = fav.description
if address and port then
core.settings:set("address", address)
core.settings:set("remote_port", port)
end
tabdata.fav_selected = fav_idx
return true
end
if fields.btn_delete_favorite then if fields.btn_delete_favorite then
local current_favourite = core.get_table_index("favourites") local idx = core.get_table_index("servers")
if not current_favourite then return end if not idx then return end
local server = tabdata.lookup[idx]
if not server then return end
core.delete_favorite(current_favourite) serverlistmgr.delete_favorite(server)
asyncOnlineFavourites() -- the server at [idx+1] will be at idx once list is refreshed
tabdata.fav_selected = nil set_selected_server(tabdata, idx, tabdata.lookup[idx+1])
return true
end
core.settings:set("address", "") if fields.btn_mp_clear then
core.settings:set("remote_port", "30000") tabdata.search_for = ""
menudata.search_result = nil
return true return true
end end
if fields.btn_mp_search or fields.key_enter_field == "te_search" then if fields.btn_mp_search or fields.key_enter_field == "te_search" then
tabdata.fav_selected = 1
local input = fields.te_search:lower()
tabdata.search_for = fields.te_search tabdata.search_for = fields.te_search
search_server_list(fields.te_search:lower())
if #menudata.favorites < 2 then if menudata.search_result then
return true -- first server in row 2 due to header
set_selected_server(tabdata, 2, menudata.search_result[1])
end end
menudata.search_result = {}
-- setup the keyword list
local keywords = {}
for word in input:gmatch("%S+") do
word = word:gsub("(%W)", "%%%1")
table.insert(keywords, word)
end
if #keywords == 0 then
menudata.search_result = nil
return true
end
-- Search the serverlist
local search_result = {}
for i = 1, #menudata.favorites do
local server = menudata.favorites[i]
local found = 0
for k = 1, #keywords do
local keyword = keywords[k]
if server.name then
local sername = server.name:lower()
local _, count = sername:gsub(keyword, keyword)
found = found + count * 4
end
if server.description then
local desc = server.description:lower()
local _, count = desc:gsub(keyword, keyword)
found = found + count * 2
end
end
if found > 0 then
local points = (#menudata.favorites - i) / 5 + found
server.points = points
table.insert(search_result, server)
end
end
if #search_result > 0 then
table.sort(search_result, function(a, b)
return a.points > b.points
end)
menudata.search_result = search_result
local first_server = search_result[1]
core.settings:set("address", first_server.address)
core.settings:set("remote_port", first_server.port)
gamedata.serverdescription = first_server.description
end
return true return true
end end
if fields.btn_mp_refresh then if fields.btn_mp_refresh then
asyncOnlineFavourites() serverlistmgr.sync()
return true return true
end end
@ -314,43 +344,51 @@ local function main_button_handler(tabview, fields, name, tabdata)
gamedata.playername = fields.te_name gamedata.playername = fields.te_name
gamedata.password = fields.te_pwd gamedata.password = fields.te_pwd
gamedata.address = fields.te_address gamedata.address = fields.te_address
gamedata.port = fields.te_port gamedata.port = tonumber(fields.te_port)
gamedata.selected_world = 0 gamedata.selected_world = 0
local fav_idx = core.get_table_index("favourites")
local fav = serverlist[fav_idx]
if fav_idx and fav_idx <= #serverlist and local idx = core.get_table_index("servers")
fav.address == fields.te_address and local server = idx and tabdata.lookup[idx]
fav.port == fields.te_port then
gamedata.servername = fav.name set_selected_server(tabdata)
gamedata.serverdescription = fav.description
if menudata.favorites_is_public and if server and server.address == gamedata.address and
not is_server_protocol_compat_or_error( server.port == gamedata.port then
fav.proto_min, fav.proto_max) then
serverlistmgr.add_favorite(server)
gamedata.servername = server.name
gamedata.serverdescription = server.description
if not is_server_protocol_compat_or_error(
server.proto_min, server.proto_max) then
return true return true
end end
else else
gamedata.servername = "" gamedata.servername = ""
gamedata.serverdescription = "" gamedata.serverdescription = ""
serverlistmgr.add_favorite({
address = gamedata.address,
port = gamedata.port,
})
end end
core.settings:set("address", fields.te_address) core.settings:set("address", gamedata.address)
core.settings:set("remote_port", fields.te_port) core.settings:set("remote_port", gamedata.port)
core.start() core.start()
return true return true
end end
return false return false
end end
local function on_change(type, old_tab, new_tab) local function on_change(type, old_tab, new_tab)
if type == "LEAVE" then return end if type == "LEAVE" then return end
asyncOnlineFavourites() serverlistmgr.sync()
end end
--------------------------------------------------------------------------------
return { return {
name = "online", name = "online",
caption = fgettext("Join Game"), caption = fgettext("Join Game"),

View File

@ -0,0 +1,29 @@
[server]
127.0.0.1
30000
[server]
localhost
30000
[server]
vps.rubenwardy.com
30001
[server]
gundul.ddnss.de
39155
[server]
VanessaE's Dreambuilder creative Server
daconcepts.com
30000
VanessaE's Dreambuilder creative-mode server. Lots of mods, whitelisted buckets.

View File

@ -0,0 +1,36 @@
_G.core = {}
_G.unpack = table.unpack
_G.serverlistmgr = {}
dofile("builtin/common/misc_helpers.lua")
dofile("builtin/mainmenu/serverlistmgr.lua")
local base = "builtin/mainmenu/tests/"
describe("legacy favorites", function()
it("loads well-formed correctly", function()
local favs = serverlistmgr.read_legacy_favorites(base .. "favorites_wellformed.txt")
local expected = {
{
address = "127.0.0.1",
port = 30000,
},
{ address = "localhost", port = 30000 },
{ address = "vps.rubenwardy.com", port = 30001 },
{ address = "gundul.ddnss.de", port = 39155 },
{
address = "daconcepts.com",
port = 30000,
name = "VanessaE's Dreambuilder creative Server",
description = "VanessaE's Dreambuilder creative-mode server. Lots of mods, whitelisted buckets."
},
}
assert.same(expected, favs)
end)
end)

View File

@ -15,6 +15,8 @@
--with this program; if not, write to the Free Software Foundation, Inc., --with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local S = core.get_translator("__builtin")
local function get_bool_default(name, default) local function get_bool_default(name, default)
local val = core.settings:get_bool(name) local val = core.settings:get_bool(name)
if val == nil then if val == nil then
@ -40,9 +42,9 @@ function profiler.init_chatcommand()
instrumentation.init_chatcommand() instrumentation.init_chatcommand()
end end
local param_usage = "print [filter] | dump [filter] | save [format [filter]] | reset" local param_usage = S("print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset")
core.register_chatcommand("profiler", { core.register_chatcommand("profiler", {
description = "handle the profiler and profiling data", description = S("Handle the profiler and profiling data"),
params = param_usage, params = param_usage,
privs = { server=true }, privs = { server=true },
func = function(name, param) func = function(name, param)
@ -51,21 +53,19 @@ function profiler.init_chatcommand()
if command == "dump" then if command == "dump" then
core.log("action", reporter.print(sampler.profile, arg0)) core.log("action", reporter.print(sampler.profile, arg0))
return true, "Statistics written to action log" return true, S("Statistics written to action log.")
elseif command == "print" then elseif command == "print" then
return true, reporter.print(sampler.profile, arg0) return true, reporter.print(sampler.profile, arg0)
elseif command == "save" then elseif command == "save" then
return reporter.save(sampler.profile, args[1] or "txt", args[2]) return reporter.save(sampler.profile, args[1] or "txt", args[2])
elseif command == "reset" then elseif command == "reset" then
sampler.reset() sampler.reset()
return true, "Statistics were reset" return true, S("Statistics were reset.")
end end
return false, string.format( return false,
"Usage: %s\n" .. S("Usage: @1", param_usage) .. "\n" ..
"Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).", S("Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).")
param_usage
)
end end
}) })

View File

@ -160,6 +160,7 @@ local function init()
-- Simple iteration would ignore lookup via __index. -- Simple iteration would ignore lookup via __index.
local entity_instrumentation = { local entity_instrumentation = {
"on_activate", "on_activate",
"on_deactivate",
"on_step", "on_step",
"on_punch", "on_punch",
"on_rightclick", "on_rightclick",

View File

@ -15,6 +15,10 @@
--with this program; if not, write to the Free Software Foundation, Inc., --with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local S = core.get_translator("__builtin")
-- Note: In this file, only messages are translated
-- but not the table itself, to keep it simple.
local DIR_DELIM, LINE_DELIM = DIR_DELIM, "\n" local DIR_DELIM, LINE_DELIM = DIR_DELIM, "\n"
local table, unpack, string, pairs, io, os = table, unpack, string, pairs, io, os local table, unpack, string, pairs, io, os = table, unpack, string, pairs, io, os
local rep, sprintf, tonumber = string.rep, string.format, tonumber local rep, sprintf, tonumber = string.rep, string.format, tonumber
@ -104,11 +108,11 @@ local TxtFormatter = Formatter:new {
end, end,
format = function(self, filter) format = function(self, filter)
local profile = self.profile local profile = self.profile
self:print("Values below show absolute/relative times spend per server step by the instrumented function.") self:print(S("Values below show absolute/relative times spend per server step by the instrumented function."))
self:print("A total of %d samples were taken", profile.stats_total.samples) self:print(S("A total of @1 sample(s) were taken.", profile.stats_total.samples))
if filter then if filter then
self:print("The output is limited to '%s'", filter) self:print(S("The output is limited to '@1'.", filter))
end end
self:print() self:print()
@ -259,19 +263,18 @@ function reporter.save(profile, format, filter)
local output, io_err = io.open(path, "w") local output, io_err = io.open(path, "w")
if not output then if not output then
return false, "Saving of profile failed with: " .. io_err return false, S("Saving of profile failed: @1", io_err)
end end
local content, err = serialize_profile(profile, format, filter) local content, err = serialize_profile(profile, format, filter)
if not content then if not content then
output:close() output:close()
return false, "Saving of profile failed with: " .. err return false, S("Saving of profile failed: @1", err)
end end
output:write(content) output:write(content)
output:close() output:close()
local logmessage = "Profile saved to " .. path core.log("action", "Profile saved to " .. path)
core.log("action", logmessage) return true, S("Profile saved to @1", path)
return true, logmessage
end end
return reporter return reporter

View File

@ -75,7 +75,7 @@ free_move (Flying) bool false
# If enabled, makes move directions relative to the player's pitch when flying or swimming. # If enabled, makes move directions relative to the player's pitch when flying or swimming.
pitch_move (Pitch move mode) bool false pitch_move (Pitch move mode) bool false
# Fast movement (via the "special" key). # Fast movement (via the "Aux1" key).
# This requires the "fast" privilege on the server. # This requires the "fast" privilege on the server.
fast_move (Fast movement) bool false fast_move (Fast movement) bool false
@ -99,14 +99,14 @@ invert_mouse (Invert mouse) bool false
# Mouse sensitivity multiplier. # Mouse sensitivity multiplier.
mouse_sensitivity (Mouse sensitivity) float 0.2 mouse_sensitivity (Mouse sensitivity) float 0.2
# If enabled, "special" key instead of "sneak" key is used for climbing down and # If enabled, "Aux1" key instead of "Sneak" key is used for climbing down and
# descending. # descending.
aux1_descends (Special key for climbing/descending) bool false aux1_descends (Aux1 key for climbing/descending) bool false
# Double-tapping the jump key toggles fly mode. # Double-tapping the jump key toggles fly mode.
doubletap_jump (Double tap jump for fly) bool false doubletap_jump (Double tap jump for fly) bool false
# If disabled, "special" key is used to fly fast if both fly and fast mode are # If disabled, "Aux1" key is used to fly fast if both fly and fast mode are
# enabled. # enabled.
always_fly_fast (Always fly and fast) bool true always_fly_fast (Always fly and fast) bool true
@ -135,9 +135,9 @@ touchscreen_threshold (Touch screen threshold) int 20 0 100
# If disabled, virtual joystick will center to first-touch's position. # If disabled, virtual joystick will center to first-touch's position.
fixed_virtual_joystick (Fixed virtual joystick) bool false fixed_virtual_joystick (Fixed virtual joystick) bool false
# (Android) Use virtual joystick to trigger "aux" button. # (Android) Use virtual joystick to trigger "Aux1" button.
# If enabled, virtual joystick will also tap "aux" button when out of main circle. # If enabled, virtual joystick will also tap "Aux1" button when out of main circle.
virtual_joystick_triggers_aux (Virtual joystick triggers aux button) bool false virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
# Enable joysticks # Enable joysticks
enable_joysticks (Enable joysticks) bool false enable_joysticks (Enable joysticks) bool false
@ -152,6 +152,9 @@ joystick_type (Joystick type) enum auto auto,generic,xbox
# when holding down a joystick button combination. # when holding down a joystick button combination.
repeat_joystick_button_time (Joystick button repetition interval) float 0.17 0.001 repeat_joystick_button_time (Joystick button repetition interval) float 0.17 0.001
# The deadzone of the joystick
joystick_deadzone (Joystick deadzone) int 2048
# The sensitivity of the joystick axes for moving the # The sensitivity of the joystick axes for moving the
# ingame view frustum around. # ingame view frustum around.
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170 joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170
@ -200,7 +203,7 @@ keymap_special_inventory (Special inventory key) key KEY_KEY_O
# Key for moving fast in fast mode. # Key for moving fast in fast mode.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3 # See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
keymap_special1 (Special key) key KEY_KEY_E keymap_aux1 (Aux1 key) key KEY_KEY_E
# Key for opening the chat window. # Key for opening the chat window.
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3 # See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
@ -460,6 +463,10 @@ keymap_decrease_viewing_range_min (View range decrease key) key -
[**Basic] [**Basic]
# Whether nametag backgrounds should be shown by default.
# Mods may still set a background.
show_nametag_backgrounds (Show nametag backgrounds by default) bool true
# Enable vertex buffer objects. # Enable vertex buffer objects.
# This should greatly improve graphics performance. # This should greatly improve graphics performance.
enable_vbo (VBO) bool true enable_vbo (VBO) bool true
@ -509,18 +516,17 @@ bilinear_filter (Bilinear filtering) bool false
trilinear_filter (Trilinear filtering) bool false trilinear_filter (Trilinear filtering) bool false
# Filtered textures can blend RGB values with fully-transparent neighbors, # Filtered textures can blend RGB values with fully-transparent neighbors,
# which PNG optimizers usually discard, sometimes resulting in a dark or # which PNG optimizers usually discard, often resulting in dark or
# light edge to transparent textures. Apply this filter to clean that up # light edges to transparent textures. Apply a filter to clean that up
# at texture load time. # at texture load time. This is automatically enabled if mipmapping is enabled.
texture_clean_transparent (Clean transparent textures) bool false texture_clean_transparent (Clean transparent textures) bool false
# When using bilinear/trilinear/anisotropic filters, low-resolution textures # When using bilinear/trilinear/anisotropic filters, low-resolution textures
# can be blurred, so automatically upscale them with nearest-neighbor # can be blurred, so automatically upscale them with nearest-neighbor
# interpolation to preserve crisp pixels. This sets the minimum texture size # interpolation to preserve crisp pixels. This sets the minimum texture size
# for the upscaled textures; higher values look sharper, but require more # for the upscaled textures; higher values look sharper, but require more
# memory. Powers of 2 are recommended. Setting this higher than 1 may not # memory. Powers of 2 are recommended. This setting is ONLY applies if
# have a visible effect unless bilinear/trilinear/anisotropic filtering is # bilinear/trilinear/anisotropic filtering is enabled.
# enabled.
# This is also used as the base node texture size for world-aligned # This is also used as the base node texture size for world-aligned
# texture autoscaling. # texture autoscaling.
texture_min_size (Minimum texture size) int 64 texture_min_size (Minimum texture size) int 64
@ -529,8 +535,8 @@ texture_min_size (Minimum texture size) int 64
# This algorithm smooths out the 3D viewport while keeping the image sharp, # This algorithm smooths out the 3D viewport while keeping the image sharp,
# but it doesn't affect the insides of textures # but it doesn't affect the insides of textures
# (which is especially noticeable with transparent textures). # (which is especially noticeable with transparent textures).
# This option is experimental and might cause visible spaces between blocks # Visible spaces appear between nodes when shaders are disabled.
# when set above 0. # If set to 0, MSAA is disabled.
# A restart is required after changing this option. # A restart is required after changing this option.
fsaa (FSAA) enum 0 0,1,2,4,8,16 fsaa (FSAA) enum 0 0,1,2,4,8,16
@ -667,7 +673,7 @@ lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
# Path to texture directory. All textures are first searched from here. # Path to texture directory. All textures are first searched from here.
texture_path (Texture path) path texture_path (Texture path) path
# The rendering back-end for Irrlicht. # The rendering back-end.
# A restart is required after changing this. # A restart is required after changing this.
# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise. # Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
# On other platforms, OpenGL is recommended. # On other platforms, OpenGL is recommended.
@ -759,7 +765,7 @@ mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50
# Size of the MapBlock cache of the mesh generator. Increasing this will # Size of the MapBlock cache of the mesh generator. Increasing this will
# increase the cache hit %, reducing the data being copied from the main # increase the cache hit %, reducing the data being copied from the main
# thread, thus reducing jitter. # thread, thus reducing jitter.
meshgen_block_cache_size (Mapblock mesh generator's MapBlock cache size in MB) int 40 0 1000 meshgen_block_cache_size (Mapblock mesh generator's MapBlock cache size in MB) int 20 0 1000
# Enables minimap. # Enables minimap.
enable_minimap (Minimap) bool true enable_minimap (Minimap) bool true
@ -864,7 +870,7 @@ font_path (Regular font path) filepath fonts/Arimo-Regular.ttf
font_path_bold (Bold font path) filepath fonts/Arimo-Bold.ttf font_path_bold (Bold font path) filepath fonts/Arimo-Bold.ttf
font_path_italic (Italic font path) filepath fonts/Arimo-Italic.ttf font_path_italic (Italic font path) filepath fonts/Arimo-Italic.ttf
font_path_bolditalic (Bold and italic font path) filepath fonts/Arimo-BoldItalic.ttf font_path_bold_italic (Bold and italic font path) filepath fonts/Arimo-BoldItalic.ttf
# Font size of the monospace font in point (pt). # Font size of the monospace font in point (pt).
mono_font_size (Monospace font size) int 15 1 mono_font_size (Monospace font size) int 15 1
@ -877,16 +883,7 @@ mono_font_path (Monospace font path) filepath fonts/Cousine-Regular.ttf
mono_font_path_bold (Bold monospace font path) filepath fonts/Cousine-Bold.ttf mono_font_path_bold (Bold monospace font path) filepath fonts/Cousine-Bold.ttf
mono_font_path_italic (Italic monospace font path) filepath fonts/Cousine-Italic.ttf mono_font_path_italic (Italic monospace font path) filepath fonts/Cousine-Italic.ttf
mono_font_path_bolditalic (Bold and italic monospace font path) filepath fonts/Cousine-BoldItalic.ttf mono_font_path_bold_italic (Bold and italic monospace font path) filepath fonts/Cousine-BoldItalic.ttf
# Font size of the fallback font in point (pt).
fallback_font_size (Fallback font size) int 15 1
# Shadow offset (in pixels) of the fallback font. If 0, then shadow will not be drawn.
fallback_font_shadow (Fallback font shadow) int 1
# Opaqueness (alpha) of the shadow behind the fallback font, between 0 and 255.
fallback_font_shadow_alpha (Fallback font shadow alpha) int 128 0 255
# Path of the fallback font. # Path of the fallback font.
# If “freetype” setting is enabled: Must be a TrueType font. # If “freetype” setting is enabled: Must be a TrueType font.
@ -973,7 +970,7 @@ serverlist_url (Serverlist URL) string servers.minetest.net
# File in client/serverlist/ that contains your favorite servers displayed in the # File in client/serverlist/ that contains your favorite servers displayed in the
# Multiplayer Tab. # Multiplayer Tab.
serverlist_file (Serverlist file) string favoriteservers.txt serverlist_file (Serverlist file) string favoriteservers.json
# Maximum size of the out chat queue. # Maximum size of the out 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.
@ -1049,7 +1046,7 @@ ipv6_server (IPv6 server) bool false
# Maximum number of blocks that are simultaneously sent per client. # Maximum number of blocks that are simultaneously sent per client.
# The maximum total count is calculated dynamically: # The maximum total count is calculated dynamically:
# max_total = ceil((#clients + max_users) * per_client / 4) # max_total = ceil((#clients + max_users) * per_client / 4)
max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) int 128 max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) int 40
# To reduce lag, block transfers are slowed down when a player is building something. # To reduce lag, block transfers are slowed down when a player is building something.
# This determines how long they are slowed down after placing or removing a node. # This determines how long they are slowed down after placing or removing a node.
@ -1060,6 +1057,13 @@ full_block_send_enable_min_time_from_building (Delay in sending blocks after bui
# client number. # client number.
max_packets_per_iteration (Max. packets per iteration) int 1024 max_packets_per_iteration (Max. packets per iteration) int 1024
# ZLib compression level to use when sending mapblocks to the client.
# -1 - Zlib's default compression level
# 0 - no compresson, fastest
# 9 - best compression, slowest
# (levels 1-3 use Zlib's "fast" method, 4-9 use the normal method)
map_compression_level_net (Map Compression Level for Network Transfer) int -1 -1 9
[*Game] [*Game]
# Default game when creating a new world. # Default game when creating a new world.
@ -1087,7 +1091,7 @@ default_stack_max (Default stack size) int 99
# Enable players getting damage and dying. # Enable players getting damage and dying.
enable_damage (Damage) bool false enable_damage (Damage) bool false
# Enable creative mode for new created maps. # Enable creative mode for all players
creative_mode (Creative) bool false creative_mode (Creative) bool false
# A chosen map seed for a new map, leave empty for random. # A chosen map seed for a new map, leave empty for random.
@ -1134,6 +1138,10 @@ enable_rollback_recording (Rollback recording) bool false
# @name, @message, @timestamp (optional) # @name, @message, @timestamp (optional)
chat_message_format (Chat message format) string <@name> @message chat_message_format (Chat message format) string <@name> @message
# If the execution of a chat command takes longer than this specified time in
# seconds, add the time information to the chat command message
chatcommand_msg_time_threshold (Chat command time message threshold) float 0.1
# A message to be displayed to all clients when the server shuts down. # A message to be displayed to all clients when the server shuts down.
kick_msg_shutdown (Shutdown message) string Server shutting down. kick_msg_shutdown (Shutdown message) string Server shutting down.
@ -1255,6 +1263,13 @@ max_objects_per_block (Maximum objects per block) int 64
# See https://www.sqlite.org/pragma.html#pragma_synchronous # See https://www.sqlite.org/pragma.html#pragma_synchronous
sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2 sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
# ZLib compression level to use when saving mapblocks to disk.
# -1 - Zlib's default compression level
# 0 - no compresson, fastest
# 9 - best compression, slowest
# (levels 1-3 use Zlib's "fast" method, 4-9 use the normal method)
map_compression_level_disk (Map Compression Level for Disk Storage) int 3 -1 9
# Length of a server tick and the interval at which objects are generally updated over # Length of a server tick and the interval at which objects are generally updated over
# network. # network.
dedicated_server_step (Dedicated server step) float 0.09 dedicated_server_step (Dedicated server step) float 0.09
@ -1385,7 +1400,7 @@ name (Player name) string
# Set the language. Leave empty to use the system language. # Set the language. Leave empty to use the system language.
# A restart is required after changing this. # A restart is required after changing this.
language (Language) enum ,ar,ca,cs,da,de,dv,el,en,eo,es,et,eu,fil,fr,hu,id,it,ja,ja_KS,jbo,kk,kn,lo,lt,ms,my,nb,nl,nn,pl,pt,pt_BR,ro,ru,sl,sr_Cyrl,sv,sw,th,tr,uk,vi language (Language) enum ,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
# Level of logging to be written to debug.txt: # Level of logging to be written to debug.txt:
# - <nothing> (no logging) # - <nothing> (no logging)
@ -1412,9 +1427,8 @@ enable_ipv6 (IPv6) bool true
[*Advanced] [*Advanced]
# Default timeout for cURL, stated in milliseconds. # Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
# Only has an effect if compiled with cURL. curl_timeout (cURL interactive timeout) int 20000
curl_timeout (cURL timeout) int 5000
# Limits number of parallel HTTP requests. Affects: # Limits number of parallel HTTP requests. Affects:
# - Media fetch if server uses remote_media setting. # - Media fetch if server uses remote_media setting.
@ -1423,7 +1437,7 @@ curl_timeout (cURL timeout) int 5000
# Only has an effect if compiled with cURL. # Only has an effect if compiled with cURL.
curl_parallel_limit (cURL parallel limit) int 8 curl_parallel_limit (cURL parallel limit) int 8
# Maximum time in ms a file download (e.g. a mod download) may take. # Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.
curl_file_download_timeout (cURL file download timeout) int 300000 curl_file_download_timeout (cURL file download timeout) int 300000
# Makes DirectX work with LuaJIT. Disable if it causes troubles. # Makes DirectX work with LuaJIT. Disable if it causes troubles.
@ -2203,6 +2217,7 @@ contentdb_url (ContentDB URL) string https://content.minetest.net
contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default
# Maximum number of concurrent downloads. Downloads exceeding this limit will be queued. # Maximum number of concurrent downloads. Downloads exceeding this limit will be queued.
# This should be lower than curl_parallel_limit.
contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3
[Cheat Menu] [Cheat Menu]
@ -2230,6 +2245,12 @@ cheat_menu_selected_font_color (Selected font color) v3f 255, 252, 88
cheat_menu_selected_font_color_alpha (Selected font color alpha) int 255 cheat_menu_selected_font_color_alpha (Selected font color alpha) int 255
cheat_menu_head_height (Head height) int 50
cheat_menu_entry_height (Entry height) int 40
cheat_menu_entry_width (Entry width) int 200
[Cheats] [Cheats]
fullbright (Fullbright) bool false fullbright (Fullbright) bool false
@ -2252,19 +2273,13 @@ prevent_natural_damage (NoFallDamage) bool true
freecam (Freecam) bool false freecam (Freecam) bool false
killaura (Killaura) bool false
no_hurt_cam (NoHurtCam) bool false no_hurt_cam (NoHurtCam) bool false
increase_tool_range (IncreasedRange) bool true
increase_tool_range_plus (IncreasedRangePlus) bool true
hud_flags_bypass (HUDBypass) bool true hud_flags_bypass (HUDBypass) bool true
antiknockback (AntiKnockback) bool false antiknockback (AntiKnockback) bool false
entity_speed (GodMode) bool false entity_speed (EntitySpeed) bool false
jesus (Jesus) bool false jesus (Jesus) bool false
@ -2276,78 +2291,16 @@ coords (Coords) bool false
point_liquids (PointLiquids) bool false point_liquids (PointLiquids) bool false
log_particles (ParticleExploit) bool false
spamclick (FastHit) bool false spamclick (FastHit) bool false
no_force_rotate (NoForceRotate) bool false no_force_rotate (NoForceRotate) bool false
no_slow (NoSlow) bool false no_slow (NoSlow) bool false
ignore_status_messages (IgnoreStatus) bool true
mark_deathmessages (Deathmessages) bool true
autosneak (AutoSneak) bool false
autoeject (AutoEject) bool false
eject_items (AutoEject Items) string
autotool (AutoTool) bool false
autorespawn (AutoRespawn) bool false
scaffold (Scaffold) bool false
scaffold_plus (ScaffoldPlus) bool false
block_water (BlockWater) bool false
autotnt (PlaceOnTop) bool false
replace (Replace) bool false
crystal_pvp (CrystalPvP) bool false
autototem (AutoTotem) bool false
dont_point_nodes (ThroughWalls) bool false
strip (Strip) bool false
autorefill (AutoRefill) bool false
nuke (Nuke) bool false
chat_color (Chat Color) string rainbow
use_chat_color (ColoredChat) bool false
chat_reverse (ReversedChat) bool false
forcefield (Forcefield) bool false
friendlist (Killaura / Forcefield Friendlist) string
cheat_hud (CheatHUD) bool true cheat_hud (CheatHUD) bool true
node_esp_nodes (NodeESP Nodes) string node_esp_nodes (NodeESP Nodes) string
autosprint (AutoSprint) bool false
override_speed (SpeedOverride) bool false
override_jump (JumpOverride) bool false
override_gravity (GravityOverride) bool false
override_speed_factor (SpeedOverride Factor) float 1.2
override_jump_factor (JumpOverride Factor) float 2.0
override_gravity_factor (GravityOverride) float 0.8
jetpack (JetPack) bool false jetpack (JetPack) bool false
autohit (AutoHit) bool false autohit (AutoHit) bool false
@ -2370,4 +2323,6 @@ entity_esp_color (EntityESP Color) v3f 255, 255, 255
player_esp_color (PlayerESP Color) v3f 0, 255, 0 player_esp_color (PlayerESP Color) v3f 0, 255, 0
noweather (NoWeather) bool false tool_range (Additional Tool Range) int 2
reach (Reach) bool false

View File

@ -6,7 +6,7 @@ uniform sampler2D textureFlags;
#define rightImage normalTexture #define rightImage normalTexture
#define maskImage textureFlags #define maskImage textureFlags
varying mediump vec2 varTexCoord; varying mediump vec4 varTexCoord;
void main(void) void main(void)
{ {

View File

@ -1,4 +1,4 @@
varying mediump vec2 varTexCoord; varying mediump vec4 varTexCoord;
void main(void) void main(void)
{ {

View File

@ -3,5 +3,9 @@ varying lowp vec4 varColor;
void main(void) void main(void)
{ {
gl_Position = mWorldViewProj * inVertexPosition; gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -7,5 +7,9 @@ void main(void)
{ {
varTexCoord = inTexCoord0.st; varTexCoord = inTexCoord0.st;
gl_Position = mWorldViewProj * inVertexPosition; gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -16,13 +16,17 @@ varying vec3 vPosition;
// precision must be considered). // precision must be considered).
varying vec3 worldPosition; varying vec3 worldPosition;
varying lowp vec4 varColor; varying lowp vec4 varColor;
#ifdef GL_ES
varying mediump vec2 varTexCoord; varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec; varying vec3 eyeVec;
const float fogStart = FOG_START; const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart); const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
#ifdef ENABLE_TONE_MAPPING #if ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters /* Hable's UC2 Tone mapping parameters
A = 0.22; A = 0.22;
@ -46,7 +50,7 @@ vec4 applyToneMapping(vec4 color)
const float gamma = 1.6; const float gamma = 1.6;
const float exposureBias = 5.5; const float exposureBias = 5.5;
color.rgb = uncharted2Tonemap(exposureBias * color.rgb); color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
// Precalculated white_scale from // Precalculated white_scale from
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W)); //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
vec3 whiteScale = vec3(1.036015346); vec3 whiteScale = vec3(1.036015346);
color.rgb *= whiteScale; color.rgb *= whiteScale;
@ -72,8 +76,8 @@ void main(void)
color = base.rgb; color = base.rgb;
vec4 col = vec4(color.rgb * varColor.rgb, 1.0); vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
#ifdef ENABLE_TONE_MAPPING #if ENABLE_TONE_MAPPING
col = applyToneMapping(col); col = applyToneMapping(col);
#endif #endif

View File

@ -16,7 +16,14 @@ varying vec3 vPosition;
// precision must be considered). // precision must be considered).
varying vec3 worldPosition; varying vec3 worldPosition;
varying lowp vec4 varColor; varying lowp vec4 varColor;
// The centroid keyword ensures that after interpolation the texture coordinates
// lie within the same bounds when MSAA is en- and disabled.
// This fixes the stripes problem with nearest-neighbour textures and MSAA.
#ifdef GL_ES
varying mediump vec2 varTexCoord; varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec; varying vec3 eyeVec;
// Color of the light emitted by the light sources. // Color of the light emitted by the light sources.
@ -139,10 +146,14 @@ void main(void)
// the brightness, so now we have to multiply these // the brightness, so now we have to multiply these
// colors with the color of the incoming light. // colors with the color of the incoming light.
// The pre-baked colors are halved to prevent overflow. // The pre-baked colors are halved to prevent overflow.
vec4 color; #ifdef GL_ES
vec4 color = inVertexColor.bgra;
#else
vec4 color = inVertexColor;
#endif
// The alpha gives the ratio of sunlight in the incoming light. // The alpha gives the ratio of sunlight in the incoming light.
float nightRatio = 1.0 - inVertexColor.a; float nightRatio = 1.0 - color.a;
color.rgb = inVertexColor.rgb * (inVertexColor.a * dayLight.rgb + color.rgb = color.rgb * (color.a * dayLight.rgb +
nightRatio * artificialLight.rgb) * 2.0; nightRatio * artificialLight.rgb) * 2.0;
color.a = 1.0; color.a = 1.0;

View File

@ -9,7 +9,11 @@ varying vec3 vNormal;
varying vec3 vPosition; varying vec3 vPosition;
varying vec3 worldPosition; varying vec3 worldPosition;
varying lowp vec4 varColor; varying lowp vec4 varColor;
#ifdef GL_ES
varying mediump vec2 varTexCoord; varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec; varying vec3 eyeVec;
varying float vIDiff; varying float vIDiff;
@ -19,7 +23,7 @@ const float BS = 10.0;
const float fogStart = FOG_START; const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / (1.0 - fogStart); const float fogShadingParameter = 1.0 / (1.0 - fogStart);
#ifdef ENABLE_TONE_MAPPING #if ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters /* Hable's UC2 Tone mapping parameters
A = 0.22; A = 0.22;
@ -43,7 +47,7 @@ vec4 applyToneMapping(vec4 color)
const float gamma = 1.6; const float gamma = 1.6;
const float exposureBias = 5.5; const float exposureBias = 5.5;
color.rgb = uncharted2Tonemap(exposureBias * color.rgb); color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
// Precalculated white_scale from // Precalculated white_scale from
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W)); //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
vec3 whiteScale = vec3(1.036015346); vec3 whiteScale = vec3(1.036015346);
color.rgb *= whiteScale; color.rgb *= whiteScale;
@ -75,7 +79,7 @@ void main(void)
col.rgb *= emissiveColor.rgb * vIDiff; col.rgb *= emissiveColor.rgb * vIDiff;
#ifdef ENABLE_TONE_MAPPING #if ENABLE_TONE_MAPPING
col = applyToneMapping(col); col = applyToneMapping(col);
#endif #endif

View File

@ -7,7 +7,11 @@ varying vec3 vNormal;
varying vec3 vPosition; varying vec3 vPosition;
varying vec3 worldPosition; varying vec3 worldPosition;
varying lowp vec4 varColor; varying lowp vec4 varColor;
#ifdef GL_ES
varying mediump vec2 varTexCoord; varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec; varying vec3 eyeVec;
varying float vIDiff; varying float vIDiff;
@ -45,5 +49,9 @@ void main(void)
: directional_ambient(normalize(inVertexNormal)); : directional_ambient(normalize(inVertexNormal));
#endif #endif
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -6,5 +6,9 @@ void main(void)
varTexCoord = inTexCoord0.st; varTexCoord = inTexCoord0.st;
gl_Position = mWorldViewProj * inVertexPosition; gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -33,7 +33,7 @@ minetest.register_chatcommand("place", {
minetest.register_chatcommand("screenshot", { minetest.register_chatcommand("screenshot", {
description = "asdf", description = "asdf",
func = function() func = function()
minetest.take_screenshot() minetest.make_screenshot()
end, end,
}) })

View File

@ -0,0 +1 @@
name = preview

View File

@ -31,7 +31,7 @@ minetest.register_globalstep(function()
minetest.after("15.0",function() minetest.after("15.0",function()
minetest.hide_huds() minetest.hide_huds()
--minetest.display_chat_message("\n\n\n\n\n\n\n\n\n") --minetest.display_chat_message("\n\n\n\n\n\n\n\n\n")
minetest.after("0.05",minetest.take_screenshot) minetest.after("0.05",minetest.make_screenshot)
minetest.after("0.1",function() minetest.after("0.1",function()
minetest.show_huds() minetest.show_huds()
end) end)

View File

@ -12,8 +12,6 @@ if(ENABLE_SYSTEM_GMP)
else() else()
message (STATUS "Detecting GMP from system failed.") message (STATUS "Detecting GMP from system failed.")
endif() endif()
else()
message (STATUS "Detecting GMP from system disabled! (ENABLE_SYSTEM_GMP=0)")
endif() endif()
if(NOT USE_SYSTEM_GMP) if(NOT USE_SYSTEM_GMP)

View File

@ -42,15 +42,6 @@ if(WIN32)
NAMES ${GETTEXT_LIB_NAMES} NAMES ${GETTEXT_LIB_NAMES}
PATHS "${CUSTOM_GETTEXT_PATH}/lib" PATHS "${CUSTOM_GETTEXT_PATH}/lib"
DOC "GetText library") DOC "GetText library")
find_file(GETTEXT_DLL
NAMES libintl.dll intl.dll libintl3.dll intl3.dll
PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *intl*.dll")
find_file(GETTEXT_ICONV_DLL
NAMES libiconv2.dll
PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
DOC "gettext *iconv*.lib")
set(GETTEXT_REQUIRED_VARS ${GETTEXT_REQUIRED_VARS} GETTEXT_DLL GETTEXT_ICONV_DLL)
endif(WIN32) endif(WIN32)

View File

@ -1,73 +1,57 @@
mark_as_advanced(IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR IRRLICHT_DLL) mark_as_advanced(IRRLICHT_DLL)
set(IRRLICHT_SOURCE_DIR "" CACHE PATH "Path to irrlicht source directory (optional)")
# Find include directory and libraries
# Find include directory # find our fork first, then upstream (TODO: remove this?)
foreach(libname IN ITEMS IrrlichtMt Irrlicht)
if(NOT IRRLICHT_SOURCE_DIR STREQUAL "") string(TOLOWER "${libname}" libname2)
set(IRRLICHT_SOURCE_DIR_INCLUDE
"${IRRLICHT_SOURCE_DIR}/include"
)
set(IRRLICHT_LIBRARY_NAMES libIrrlicht.a Irrlicht Irrlicht.lib)
if(WIN32)
if(MSVC)
set(IRRLICHT_SOURCE_DIR_LIBS "${IRRLICHT_SOURCE_DIR}/lib/Win32-visualstudio")
set(IRRLICHT_LIBRARY_NAMES Irrlicht.lib)
else()
set(IRRLICHT_SOURCE_DIR_LIBS "${IRRLICHT_SOURCE_DIR}/lib/Win32-gcc")
set(IRRLICHT_LIBRARY_NAMES libIrrlicht.a libIrrlicht.dll.a)
endif()
else()
set(IRRLICHT_SOURCE_DIR_LIBS "${IRRLICHT_SOURCE_DIR}/lib/Linux")
set(IRRLICHT_LIBRARY_NAMES libIrrlicht.a)
endif()
find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
DOC "Path to the directory with IrrlichtMt includes"
PATHS PATHS
${IRRLICHT_SOURCE_DIR_INCLUDE} /usr/local/include/${libname2}
NO_DEFAULT_PATH /usr/include/${libname2}
/system/develop/headers/${libname2} #Haiku
PATH_SUFFIXES "include/${libname2}"
) )
find_library(IRRLICHT_LIBRARY NAMES ${IRRLICHT_LIBRARY_NAMES} find_library(IRRLICHT_LIBRARY NAMES lib${libname} ${libname}
PATHS DOC "Path to the IrrlichtMt library file"
${IRRLICHT_SOURCE_DIR_LIBS}
NO_DEFAULT_PATH
)
else()
find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
PATHS
/usr/local/include/irrlicht
/usr/include/irrlicht
/system/develop/headers/irrlicht #Haiku
PATH_SUFFIXES "include/irrlicht"
)
find_library(IRRLICHT_LIBRARY NAMES libIrrlicht.so libIrrlicht.a Irrlicht
PATHS PATHS
/usr/local/lib /usr/local/lib
/usr/lib /usr/lib
/system/develop/lib # Haiku /system/develop/lib # Haiku
) )
endif()
if(IRRLICHT_INCLUDE_DIR OR IRRLICHT_LIBRARY)
break()
endif()
endforeach()
# Handholding for users
if(IRRLICHT_INCLUDE_DIR AND (NOT IS_DIRECTORY "${IRRLICHT_INCLUDE_DIR}" OR
NOT EXISTS "${IRRLICHT_INCLUDE_DIR}/irrlicht.h"))
message(WARNING "IRRLICHT_INCLUDE_DIR was set to ${IRRLICHT_INCLUDE_DIR} "
"but irrlicht.h does not exist inside. The path will not be used.")
unset(IRRLICHT_INCLUDE_DIR CACHE)
endif()
if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR APPLE)
# (only on systems where we're sure how a valid library looks like)
if(IRRLICHT_LIBRARY AND (IS_DIRECTORY "${IRRLICHT_LIBRARY}" OR
NOT IRRLICHT_LIBRARY MATCHES "\\.(a|so|dylib|lib)([.0-9]+)?$"))
message(WARNING "IRRLICHT_LIBRARY was set to ${IRRLICHT_LIBRARY} "
"but is not a valid library file. The path will not be used.")
unset(IRRLICHT_LIBRARY CACHE)
endif()
endif()
# On Windows, find the DLL for installation # On Windows, find the DLL for installation
if(WIN32) if(WIN32)
# If VCPKG_APPLOCAL_DEPS is ON, dll's are automatically handled by VCPKG # If VCPKG_APPLOCAL_DEPS is ON, dll's are automatically handled by VCPKG
if(NOT VCPKG_APPLOCAL_DEPS) if(NOT VCPKG_APPLOCAL_DEPS)
if(MSVC) find_file(IRRLICHT_DLL NAMES IrrlichtMt.dll
set(IRRLICHT_COMPILER "VisualStudio") DOC "Path of the IrrlichtMt dll (for installation)"
else()
set(IRRLICHT_COMPILER "gcc")
endif()
find_file(IRRLICHT_DLL NAMES Irrlicht.dll
PATHS
"${IRRLICHT_SOURCE_DIR}/bin/Win32-${IRRLICHT_COMPILER}"
DOC "Path of the Irrlicht dll (for installation)"
) )
endif() endif()
endif(WIN32) endif(WIN32)

View File

@ -1,26 +1,25 @@
# Look for JSONCPP if asked to. # Look for JsonCpp, with fallback to bundeled version
# We use a bundled version by default because some distros ship versions of
# JSONCPP that cause segfaults and other memory errors when we link with them.
# See https://github.com/minetest/minetest/issues/1793
mark_as_advanced(JSON_LIBRARY JSON_INCLUDE_DIR) mark_as_advanced(JSON_LIBRARY JSON_INCLUDE_DIR)
option(ENABLE_SYSTEM_JSONCPP "Enable using a system-wide JSONCPP. May cause segfaults and other memory errors!" FALSE) option(ENABLE_SYSTEM_JSONCPP "Enable using a system-wide JsonCpp" TRUE)
set(USE_SYSTEM_JSONCPP FALSE)
if(ENABLE_SYSTEM_JSONCPP) if(ENABLE_SYSTEM_JSONCPP)
find_library(JSON_LIBRARY NAMES jsoncpp) find_library(JSON_LIBRARY NAMES jsoncpp)
find_path(JSON_INCLUDE_DIR json/allocator.h PATH_SUFFIXES jsoncpp) find_path(JSON_INCLUDE_DIR json/allocator.h PATH_SUFFIXES jsoncpp)
include(FindPackageHandleStandardArgs) if(JSON_LIBRARY AND JSON_INCLUDE_DIR)
find_package_handle_standard_args(Json DEFAULT_MSG JSON_LIBRARY JSON_INCLUDE_DIR) message(STATUS "Using JsonCpp provided by system.")
set(USE_SYSTEM_JSONCPP TRUE)
if(JSON_FOUND)
message(STATUS "Using system JSONCPP library.")
endif() endif()
endif() endif()
if(NOT JSON_FOUND) if(NOT USE_SYSTEM_JSONCPP)
message(STATUS "Using bundled JSONCPP library.") message(STATUS "Using bundled JsonCpp library.")
set(JSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/jsoncpp) set(JSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/jsoncpp)
set(JSON_LIBRARY jsoncpp) set(JSON_LIBRARY jsoncpp)
add_subdirectory(lib/jsoncpp) add_subdirectory(lib/jsoncpp)
endif() endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Json DEFAULT_MSG JSON_LIBRARY JSON_INCLUDE_DIR)

View File

@ -42,7 +42,7 @@ else()
) )
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OPENGLES2 DEFAULT_MSG OPENGLES2_LIBRARY OPENGLES2_INCLUDE_DIR) find_package_handle_standard_args(OpenGLES2 DEFAULT_MSG OPENGLES2_LIBRARY OPENGLES2_INCLUDE_DIR)
find_path(EGL_INCLUDE_DIR EGL/egl.h find_path(EGL_INCLUDE_DIR EGL/egl.h
PATHS /usr/openwin/share/include PATHS /usr/openwin/share/include
@ -59,7 +59,6 @@ else()
/usr/lib /usr/lib
) )
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR) find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR)
endif() endif()

View File

@ -1,4 +1,4 @@
Minetest Lua Client Modding API Reference 5.4.0 Minetest Lua Client Modding API Reference 5.5.0
================================================ ================================================
* More information at <http://www.minetest.net/> * More information at <http://www.minetest.net/>
* Developer Wiki: <http://dev.minetest.net/> * Developer Wiki: <http://dev.minetest.net/>
@ -627,7 +627,7 @@ Helper functions
* `minetest.is_yes(arg)` * `minetest.is_yes(arg)`
* returns whether `arg` can be interpreted as yes * returns whether `arg` can be interpreted as yes
* `minetest.is_nan(arg)` * `minetest.is_nan(arg)`
* returns true true when the passed number represents NaN. * returns true when the passed number represents NaN.
* `table.copy(table)`: returns a table * `table.copy(table)`: returns a table
* returns a deep copy of `table` * returns a deep copy of `table`
@ -658,6 +658,9 @@ Minetest namespace reference
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data * `minetest.sha1(data, [raw])`: returns the sha1 hash of data
* `data`: string of data to hash * `data`: string of data to hash
* `raw`: return raw bytes instead of hex digits, default: false * `raw`: return raw bytes instead of hex digits, default: false
* `minetest.colorspec_to_colorstring(colorspec)`: Converts a ColorSpec to a
ColorString. If the ColorSpec is invalid, returns `nil`.
* `colorspec`: The ColorSpec to convert
* `minetest.get_csm_restrictions()`: returns a table of `Flags` indicating the * `minetest.get_csm_restrictions()`: returns a table of `Flags` indicating the
restrictions applied to the current mod. restrictions applied to the current mod.
* If a flag in this table is set to true, the feature is RESTRICTED. * If a flag in this table is set to true, the feature is RESTRICTED.
@ -674,6 +677,11 @@ Minetest namespace reference
### Global callback registration functions ### Global callback registration functions
Call these functions only at load time! Call these functions only at load time!
* `minetest.get_send_speed(speed)`
* This function is called every time the player's speed is sent to server
* The `speed` argument is the actual speed of the player
* If you define it, you can return a modified `speed`. This speed will be
sent to server instead.
* `minetest.open_enderchest()` * `minetest.open_enderchest()`
* This function is called if the client uses the Keybind for it (by default "O") * This function is called if the client uses the Keybind for it (by default "O")
* You can override it * You can override it
@ -700,7 +708,7 @@ Call these functions only at load time!
* Registers a chatcommand `command` to manage a list that takes the args `del | add | list <param>` * Registers a chatcommand `command` to manage a list that takes the args `del | add | list <param>`
* The list is stored comma-seperated in `setting` * The list is stored comma-seperated in `setting`
* `desc` is the description * `desc` is the description
* `add` adds something to the list * `add` adds something to the list
* `del` del removes something from the list * `del` del removes something from the list
* `list` lists all items on the list * `list` lists all items on the list
* `minetest.register_on_chatcommand(function(command, params))` * `minetest.register_on_chatcommand(function(command, params))`
@ -762,7 +770,14 @@ Call these functions only at load time!
* `minetest.register_on_spawn_partice(function(particle definition))` * `minetest.register_on_spawn_partice(function(particle definition))`
* Called when recieving a spawn particle command from server * Called when recieving a spawn particle command from server
* Newest functions are called first * Newest functions are called first
* If any function returns true, the particel does not spawn * If any function returns true, the particle does not spawn
* `minetest.register_on_object_add(function(obj))`
* Called every time an object is added
* `minetest.register_on_object_properties_change(function(obj))`
* Called every time the properties of an object are changed server-side
* May modify the object's properties without the fear of infinite recursion
* `minetest.register_on_object_hp_change(function(obj))`
* Called every time the hp of an object are changes server-side
### Setting-related ### Setting-related
* `minetest.settings`: Settings object containing all of the settings from the * `minetest.settings`: Settings object containing all of the settings from the
@ -793,6 +808,16 @@ Call these functions only at load time!
* Returns the time of day: `0` for midnight, `0.5` for midday * Returns the time of day: `0` for midnight, `0.5` for midday
### Map ### Map
* `minetest.interact(action, pointed_thing)`
* Sends an interaction to the server
* `pointed_thing` is a pointed_thing
* `action` is one of
* "start_digging": Use to punch nodes / objects
* "stop_digging": Use to abort digging a "start_digging" command
* "digging_completed": Use to finish a "start_digging" command or dig a node instantly
* "place": Use to rightclick nodes and objects
* "use": Use to leftclick an item in air (pointed_thing.type is usually "nothing")
* "activate": Same as "use", but rightclick
* `minetest.place_node(pos)` * `minetest.place_node(pos)`
* Places the wielded node/item of the player at pos. * Places the wielded node/item of the player at pos.
* `minetest.dig_node(pos)` * `minetest.dig_node(pos)`
@ -919,11 +944,15 @@ Call these functions only at load time!
* Convert between two privilege representations * Convert between two privilege representations
### Client Environment ### Client Environment
* `minetest.object_refs`
* Map of object references, indexed by active object id
* `minetest.get_player_names()` * `minetest.get_player_names()`
* Returns list of player names on server (nil if CSM_RF_READ_PLAYERINFO is enabled by server) * Returns list of player names on server (nil if CSM_RF_READ_PLAYERINFO is enabled by server)
* `minetest.get_objects_inside_radius(pos, radius)`: returns a list of * `minetest.get_objects_inside_radius(pos, radius)`: returns a list of
ClientObjectRefs. ClientObjectRefs.
* `radius`: using an euclidean metric * `radius`: using an euclidean metric
* `minetest.get_nearby_objects(radius)`
* alias for minetest.get_objects_inside_radius(minetest.localplayer:get_pos(), radius)
* `minetest.disconnect()` * `minetest.disconnect()`
* Disconnect from the server and exit to main menu. * Disconnect from the server and exit to main menu.
* Returns `false` if the client is already disconnecting otherwise returns `true`. * Returns `false` if the client is already disconnecting otherwise returns `true`.
@ -934,13 +963,21 @@ Call these functions only at load time!
### HTTP Requests ### HTTP Requests
* `minetest.get_http_api()` * `minetest.request_http_api()`:
* returns `HTTPApiTable` containing http functions. * returns `HTTPApiTable` containing http functions if the calling mod has
* The returned table contains the functions `fetch_sync`, `fetch_async` and been granted access by being listed in the `secure.http_mods` or
`secure.trusted_mods` setting, otherwise returns `nil`.
* The returned table contains the functions `fetch`, `fetch_async` and
`fetch_async_get` described below. `fetch_async_get` described below.
* Only works at init time and must be called from the mod's main scope
(not from a function).
* Function only exists if minetest server was built with cURL support. * Function only exists if minetest server was built with cURL support.
* `HTTPApiTable.fetch_sync(HTTPRequest req)`: returns HTTPRequestResult * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN
* Performs given request synchronously A LOCAL VARIABLE!**
* `HTTPApiTable.fetch(HTTPRequest req, callback)`
* Performs given request asynchronously and calls callback upon completion
* callback: `function(HTTPRequestResult res)`
* Use this HTTP function if you are unsure, the others are for advanced use
* `HTTPApiTable.fetch_async(HTTPRequest req)`: returns handle * `HTTPApiTable.fetch_async(HTTPRequest req)`: returns handle
* Performs given request asynchronously and returns handle for * Performs given request asynchronously and returns handle for
`HTTPApiTable.fetch_async_get` `HTTPApiTable.fetch_async_get`
@ -1102,6 +1139,14 @@ Passed to `HTTPApiTable.fetch` callback. Returned by
* Checks if a global variable has been set, without triggering a warning. * Checks if a global variable has been set, without triggering a warning.
* `minetest.make_screenshot()` * `minetest.make_screenshot()`
* Triggers the MT makeScreenshot functionality * Triggers the MT makeScreenshot functionality
* `minetest.request_insecure_environment()`: returns an environment containing
insecure functions if the calling mod has been listed as trusted in the
`secure.trusted_mods` setting or security is disabled, otherwise returns
`nil`.
* Only works at init time and must be called from the mod's main scope
(ie: the init.lua of the mod, not from another Lua file or within a function).
* **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED ENVIRONMENT, STORE
IT IN A LOCAL VARIABLE!**
### UI ### UI
* `minetest.ui.minimap` * `minetest.ui.minimap`
@ -1191,6 +1236,7 @@ Please do not try to access the reference until the camera is initialized, other
### LocalPlayer ### LocalPlayer
An interface to retrieve information about the player. An interface to retrieve information about the player.
This object will only be available after the client is initialized. Earlier accesses will yield a `nil` value.
Methods: Methods:
@ -1382,12 +1428,16 @@ This is basically a reference to a C++ `GenericCAO`.
* `is_player()`: returns true if the object is a player * `is_player()`: returns true if the object is a player
* `is_local_player()`: returns true if the object is the local player * `is_local_player()`: returns true if the object is the local player
* `get_attach()`: returns parent or nil if it isn't attached. * `get_attach()`: returns parent or nil if it isn't attached.
* `get_nametag()`: returns the nametag (string) * `get_nametag()`: returns the nametag (deprecated, use get_properties().nametag instead)
* `get_item_textures()`: returns the textures * `get_item_textures()`: returns the textures (deprecated, use get_properties().textures instead)
* `get_max_hp()`: returns the maximum heath * `get_max_hp()`: returns the maximum heath (deprecated, use get_properties().hp_max instead)
* `set_properties(object property table)`
* `get_properties()`: returns object property table
* `punch()`: punches the object * `punch()`: punches the object
* `rightclick()`: rightclicks the object * `rightclick()`: rightclicks the object
* `remove()`: removes the object permanently
* `set_nametag_images(images)`: Provides a list of images to be drawn below the nametag
### `Raycast` ### `Raycast`
A raycast on the map. It works with selection boxes. A raycast on the map. It works with selection boxes.
@ -1416,6 +1466,8 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
----------------- -----------------
### Definitions ### Definitions
* `minetest.inventorycube(img1, img2, img3)`
* Returns a string for making an image of a cube (useful as an item image)
* `minetest.get_node_def(nodename)` * `minetest.get_node_def(nodename)`
* Returns [node definition](#node-definition) table of `nodename` * Returns [node definition](#node-definition) table of `nodename`
* `minetest.get_item_def(itemstring)` * `minetest.get_item_def(itemstring)`
@ -1427,10 +1479,67 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
{light_source=minetest.LIGHT_MAX})` {light_source=minetest.LIGHT_MAX})`
* Doesnt really work yet an causes strange bugs, I'm working to make is better * Doesnt really work yet an causes strange bugs, I'm working to make is better
#### Tile definition
* `"image.png"`
* `{name="image.png", animation={Tile Animation definition}}`
* `{name="image.png", backface_culling=bool, align_style="node"/"world"/"user", scale=int}`
* backface culling enabled by default for most nodes
* align style determines whether the texture will be rotated with the node
or kept aligned with its surroundings. "user" means that client
setting will be used, similar to `glasslike_framed_optional`.
Note: supported by solid nodes and nodeboxes only.
* scale is used to make texture span several (exactly `scale`) nodes,
instead of just one, in each direction. Works for world-aligned
textures only.
Note that as the effect is applied on per-mapblock basis, `16` should
be equally divisible by `scale` or you may get wrong results.
* `{name="image.png", color=ColorSpec}`
* the texture's color will be multiplied with this color.
* the tile's color overrides the owning node's color in all cases.
##### Tile definition
{
type = "vertical_frames",
aspect_w = 16,
-- Width of a frame in pixels
aspect_h = 16,
-- Height of a frame in pixels
length = 3.0,
-- Full loop length
}
{
type = "sheet_2d",
frames_w = 5,
-- Width in number of frames
frames_h = 3,
-- Height in number of frames
frame_length = 0.5,
-- Length of a single frame
}
#### Node Definition #### Node Definition
```lua ```lua
{ {
tiles = {tile definition 1, def2, def3, def4, def5, def6},
-- Textures of node; +Y, -Y, +X, -X, +Z, -Z
overlay_tiles = {tile definition 1, def2, def3, def4, def5, def6},
-- Same as `tiles`, but these textures are drawn on top of the base
-- tiles. This is used to colorize only specific parts of the
-- texture. If the texture name is an empty string, that overlay is not
-- drawn
special_tiles = {tile definition 1, Tile definition 2},
-- Special textures of node; used rarely.
has_on_construct = bool, -- Whether the node has the on_construct callback defined has_on_construct = bool, -- Whether the node has the on_construct callback defined
has_on_destruct = bool, -- Whether the node has the on_destruct callback defined has_on_destruct = bool, -- Whether the node has the on_destruct callback defined
has_after_destruct = bool, -- Whether the node has the after_destruct callback defined has_after_destruct = bool, -- Whether the node has the after_destruct callback defined
@ -1592,9 +1701,8 @@ The following functions provide escape sequences:
Named colors are also supported and are equivalent to Named colors are also supported and are equivalent to
[CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors). [CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors).
To specify the value of the alpha channel, append `#AA` to the end of the color name To specify the value of the alpha channel, append `#A` or `#AA` to the end of
(e.g. `colorname#08`). For named colors the hexadecimal string representing the alpha the color name (e.g. `colorname#08`).
value must (always) be two hexadecimal digits.
`Color` `Color`
------------- -------------
@ -1779,7 +1887,7 @@ A reference to a C++ InventoryAction. You can move, drop and craft items in all
* it specifies how many items to drop / craft / move * it specifies how many items to drop / craft / move
* `0` means move all items * `0` means move all items
* default count: `0` * default count: `0`
#### example #### example
`local move_act = InventoryAction("move") `local move_act = InventoryAction("move")
move_act:from("current_player", "main", 1) move_act:from("current_player", "main", 1)
@ -1794,7 +1902,7 @@ A reference to a C++ InventoryAction. You can move, drop and craft items in all
drop_act:apply() drop_act:apply()
` `
* e.g. In first hotbar slot there are tree logs: Move one to craft field, then craft wood out of it and immediately drop it * e.g. In first hotbar slot there are tree logs: Move one to craft field, then craft wood out of it and immediately drop it

View File

@ -256,6 +256,9 @@ Subfolders with names starting with `_` or `.` are ignored.
If a subfolder contains a media file with the same name as a media file If a subfolder contains a media file with the same name as a media file
in one of its parents, the parent's file is used. in one of its parents, the parent's file is used.
Although it is discouraged, a mod can overwrite a media file of any mod that it
depends on by supplying a file with an equal name.
Naming conventions Naming conventions
------------------ ------------------
@ -1014,7 +1017,9 @@ The function of `param2` is determined by `paramtype2` in node definition.
* `paramtype2 = "flowingliquid"` * `paramtype2 = "flowingliquid"`
* Used by `drawtype = "flowingliquid"` and `liquidtype = "flowing"` * Used by `drawtype = "flowingliquid"` and `liquidtype = "flowing"`
* The liquid level and a flag of the liquid are stored in `param2` * The liquid level and a flag of the liquid are stored in `param2`
* Bits 0-2: Liquid level (0-7). The higher, the more liquid is in this node * Bits 0-2: Liquid level (0-7). The higher, the more liquid is in this node;
see `minetest.get_node_level`, `minetest.set_node_level` and `minetest.add_node_level`
to access/manipulate the content of this field
* Bit 3: If set, liquid is flowing downwards (no graphical effect) * Bit 3: If set, liquid is flowing downwards (no graphical effect)
* `paramtype2 = "wallmounted"` * `paramtype2 = "wallmounted"`
* Supported drawtypes: "torchlike", "signlike", "normal", "nodebox", "mesh" * Supported drawtypes: "torchlike", "signlike", "normal", "nodebox", "mesh"
@ -1043,9 +1048,9 @@ The function of `param2` is determined by `paramtype2` in node definition.
* The height of the 'plantlike' section is stored in `param2`. * The height of the 'plantlike' section is stored in `param2`.
* The height is (`param2` / 16) nodes. * The height is (`param2` / 16) nodes.
* `paramtype2 = "degrotate"` * `paramtype2 = "degrotate"`
* Only valid for "plantlike" drawtype. The rotation of the node is stored in * Valid for `plantlike` and `mesh` drawtypes. The rotation of the node is
`param2`. stored in `param2`.
* Values range 0 - 179. The value stored in `param2` is multiplied by two to * Values range 0239. The value stored in `param2` is multiplied by 1.5 to
get the actual rotation in degrees of the node. get the actual rotation in degrees of the node.
* `paramtype2 = "meshoptions"` * `paramtype2 = "meshoptions"`
* Only valid for "plantlike" drawtype. `param2` encodes the shape and * Only valid for "plantlike" drawtype. `param2` encodes the shape and
@ -1083,6 +1088,11 @@ The function of `param2` is determined by `paramtype2` in node definition.
* `param2` values 0-63 define 64 levels of internal liquid, 0 being empty * `param2` values 0-63 define 64 levels of internal liquid, 0 being empty
and 63 being full. and 63 being full.
* Liquid texture is defined using `special_tiles = {"modname_tilename.png"}` * Liquid texture is defined using `special_tiles = {"modname_tilename.png"}`
* `paramtype2 = "colordegrotate"`
* Same as `degrotate`, but with colors.
* The first (most-significant) three bits of `param2` tells which color
is picked from the palette. The palette should have 8 pixels.
* Remaining 5 bits store rotation in range 023 (i.e. in 15° steps)
* `paramtype2 = "none"` * `paramtype2 = "none"`
* `param2` will not be used by the engine and can be used to store * `param2` will not be used by the engine and can be used to store
an arbitrary value an arbitrary value
@ -1102,8 +1112,20 @@ Look for examples in `games/devtest` or `games/minetest_game`.
* Invisible, uses no texture. * Invisible, uses no texture.
* `liquid` * `liquid`
* The cubic source node for a liquid. * The cubic source node for a liquid.
* Faces bordering to the same node are never rendered.
* Connects to node specified in `liquid_alternative_flowing`.
* Use `backface_culling = false` for the tiles you want to make
visible when inside the node.
* `flowingliquid` * `flowingliquid`
* The flowing version of a liquid, appears with various heights and slopes. * The flowing version of a liquid, appears with various heights and slopes.
* Faces bordering to the same node are never rendered.
* Connects to node specified in `liquid_alternative_source`.
* Node textures are defined with `special_tiles` where the first tile
is for the top and bottom faces and the second tile is for the side
faces.
* `tiles` is used for the item/inventory/wield image rendering.
* Use `backface_culling = false` for the special tiles you want to make
visible when inside the node
* `glasslike` * `glasslike`
* Often used for partially-transparent nodes. * Often used for partially-transparent nodes.
* Only external sides of textures are visible. * Only external sides of textures are visible.
@ -1130,14 +1152,20 @@ Look for examples in `games/devtest` or `games/minetest_game`.
used to compensate for how `glasslike` reduces visual thickness. used to compensate for how `glasslike` reduces visual thickness.
* `torchlike` * `torchlike`
* A single vertical texture. * A single vertical texture.
* If placed on top of a node, uses the first texture specified in `tiles`. * If `paramtype2="[color]wallmounted":
* If placed against the underside of a node, uses the second texture * If placed on top of a node, uses the first texture specified in `tiles`.
specified in `tiles`. * If placed against the underside of a node, uses the second texture
* If placed on the side of a node, uses the third texture specified in specified in `tiles`.
`tiles` and is perpendicular to that node. * If placed on the side of a node, uses the third texture specified in
`tiles` and is perpendicular to that node.
* If `paramtype2="none"`:
* Will be rendered as if placed on top of a node (see
above) and only the first texture is used.
* `signlike` * `signlike`
* A single texture parallel to, and mounted against, the top, underside or * A single texture parallel to, and mounted against, the top, underside or
side of a node. side of a node.
* If `paramtype2="[color]wallmounted", it rotates according to `param2`
* If `paramtype2="none"`, it will always be on the floor.
* `plantlike` * `plantlike`
* Two vertical and diagonal textures at right-angles to each other. * Two vertical and diagonal textures at right-angles to each other.
* See `paramtype2 = "meshoptions"` above for other options. * See `paramtype2 = "meshoptions"` above for other options.
@ -1245,6 +1273,9 @@ A box of a regular node would look like:
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
To avoid collision issues, keep each value within the range of +/- 1.45.
This also applies to leveled nodeboxes, where the final height shall not
exceed this soft limit.
@ -1717,7 +1748,15 @@ to games.
* `3`: the node always gets the digging time 0 seconds (torch) * `3`: the node always gets the digging time 0 seconds (torch)
* `disable_jump`: Player (and possibly other things) cannot jump from node * `disable_jump`: Player (and possibly other things) cannot jump from node
or if their feet are in the node. Note: not supported for `new_move = false` or if their feet are in the node. Note: not supported for `new_move = false`
* `fall_damage_add_percent`: damage speed = `speed * (1 + value/100)` * `fall_damage_add_percent`: modifies the fall damage suffered when hitting
the top of this node. There's also an armor group with the same name.
The final player damage is determined by the following formula:
damage =
collision speed
* ((node_fall_damage_add_percent + 100) / 100) -- node group
* ((player_fall_damage_add_percent + 100) / 100) -- player armor group
- (14) -- constant tolerance
Negative damage values are discarded as no damage.
* `falling_node`: if there is no walkable block under the node it will fall * `falling_node`: if there is no walkable block under the node it will fall
* `float`: the node will not fall through liquids * `float`: the node will not fall through liquids
* `level`: Can be used to give an additional sense of progression in the game. * `level`: Can be used to give an additional sense of progression in the game.
@ -1737,11 +1776,15 @@ to games.
`"toolrepair"` crafting recipe `"toolrepair"` crafting recipe
### `ObjectRef` groups ### `ObjectRef` armor groups
* `immortal`: Skips all damage and breath handling for an object. This group * `immortal`: Skips all damage and breath handling for an object. This group
will also hide the integrated HUD status bars for players, and is will also hide the integrated HUD status bars for players. It is
automatically set to all players when damage is disabled on the server. automatically set to all players when damage is disabled on the server and
cannot be reset (subject to change).
* `fall_damage_add_percent`: Modifies the fall damage suffered by players
when they hit the ground. It is analog to the node group with the same
name. See the node group above for the exact calculation.
* `punch_operable`: For entities; disables the regular damage mechanism for * `punch_operable`: For entities; disables the regular damage mechanism for
players punching it by hand or a non-tool item, so that it can do something players punching it by hand or a non-tool item, so that it can do something
else than take damage. else than take damage.
@ -2109,6 +2152,22 @@ Examples
list[current_player;craft;3,0;3,3;] list[current_player;craft;3,0;3,3;]
list[current_player;craftpreview;7,1;1,1;] list[current_player;craftpreview;7,1;1,1;]
Version History
---------------
* FORMSPEC VERSION 1:
* (too much)
* FORMSPEC VERSION 2:
* Forced real coordinates
* background9[]: 9-slice scaling parameters
* FORMSPEC VERSION 3:
* Formspec elements are drawn in the order of definition
* bgcolor[]: use 3 parameters (bgcolor, formspec (now an enum), fbgcolor)
* box[] and image[] elements enable clipping by default
* new element: scroll_container[]
* FORMSPEC VERSION 4:
* Allow dropdown indexing events
Elements Elements
-------- --------
@ -2120,6 +2179,7 @@ Elements
* Clients older than this version can neither show newer elements nor display * Clients older than this version can neither show newer elements nor display
elements with new arguments correctly. elements with new arguments correctly.
* Available since feature `formspec_version_element`. * Available since feature `formspec_version_element`.
* See also: [Version History]
### `size[<W>,<H>,<fixed_size>]` ### `size[<W>,<H>,<fixed_size>]`
@ -2204,7 +2264,8 @@ Elements
* Show an inventory list if it has been sent to the client. Nothing will * Show an inventory list if it has been sent to the client. Nothing will
be shown if the inventory list is of size 0. be shown if the inventory list is of size 0.
* **Note**: With the new coordinate system, the spacing between inventory * **Note**: With the new coordinate system, the spacing between inventory
slots is one-fourth the size of an inventory slot. slots is one-fourth the size of an inventory slot by default. Also see
[Styling Formspecs] for changing the size of slots and spacing.
### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]` ### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
@ -2272,7 +2333,7 @@ Elements
* `frame duration`: Milliseconds between each frame. `0` means the frames don't advance. * `frame duration`: Milliseconds between each frame. `0` means the frames don't advance.
* `frame start` (Optional): The index of the frame to start on. Default `1`. * `frame start` (Optional): The index of the frame to start on. Default `1`.
### `model[<X>,<Y>;<W>,<H>;<name>;<mesh>;<textures>;<rotation X,Y>;<continuous>;<mouse control>]` ### `model[<X>,<Y>;<W>,<H>;<name>;<mesh>;<textures>;<rotation X,Y>;<continuous>;<mouse control>;<frame loop range>;<animation speed>]`
* Show a mesh model. * Show a mesh model.
* `name`: Element name that can be used for styling * `name`: Element name that can be used for styling
@ -2283,6 +2344,10 @@ Elements
The axes are euler angles in degrees. The axes are euler angles in degrees.
* `continuous` (Optional): Whether the rotation is continuous. Default `false`. * `continuous` (Optional): Whether the rotation is continuous. Default `false`.
* `mouse control` (Optional): Whether the model can be controlled with the mouse. Default `true`. * `mouse control` (Optional): Whether the model can be controlled with the mouse. Default `true`.
* `frame loop range` (Optional): Range of the animation frames.
* Defaults to the full range of all available frames.
* Syntax: `<begin>,<end>`
* `animation speed` (Optional): Sets the animation speed. Default 0 FPS.
### `item_image[<X>,<Y>;<W>,<H>;<item name>]` ### `item_image[<X>,<Y>;<W>,<H>;<item name>]`
@ -2648,7 +2713,7 @@ Elements
* `span=<value>`: number of following columns to affect * `span=<value>`: number of following columns to affect
(default: infinite). (default: infinite).
### `style[<selector 1>,<selector 2>;<prop1>;<prop2>;...]` ### `style[<selector 1>,<selector 2>,...;<prop1>;<prop2>;...]`
* Set the style for the element(s) matching `selector` by name. * Set the style for the element(s) matching `selector` by name.
* `selector` can be one of: * `selector` can be one of:
@ -2661,7 +2726,7 @@ Elements
* See [Styling Formspecs]. * See [Styling Formspecs].
### `style_type[<selector 1>,<selector 2>;<prop1>;<prop2>;...]` ### `style_type[<selector 1>,<selector 2>,...;<prop1>;<prop2>;...]`
* Set the style for the element(s) matching `selector` by type. * Set the style for the element(s) matching `selector` by type.
* `selector` can be one of: * `selector` can be one of:
@ -2734,10 +2799,10 @@ Styling Formspecs
Formspec elements can be themed using the style elements: Formspec elements can be themed using the style elements:
style[<name 1>,<name 2>;<prop1>;<prop2>;...] style[<name 1>,<name 2>,...;<prop1>;<prop2>;...]
style[<name 1>:<state>,<name 2>:<state>;<prop1>;<prop2>;...] style[<name 1>:<state>,<name 2>:<state>,...;<prop1>;<prop2>;...]
style_type[<type 1>,<type 2>;<prop1>;<prop2>;...] style_type[<type 1>,<type 2>,...;<prop1>;<prop2>;...]
style_type[<type 1>:<state>,<type 2>:<state>;<prop1>;<prop2>;...] style_type[<type 1>:<state>,<type 2>:<state>,...;<prop1>;<prop2>;...]
Where a prop is: Where a prop is:
@ -2784,6 +2849,8 @@ Some types may inherit styles from parent types.
* image_button * image_button
* item_image_button * item_image_button
* label * label
* list
* model
* pwdfield, inherits from field * pwdfield, inherits from field
* scrollbar * scrollbar
* tabheader * tabheader
@ -2843,14 +2910,14 @@ Some types may inherit styles from parent types.
* noclip - boolean, set to true to allow the element to exceed formspec bounds. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* padding - rect, adds space between the edges of the button and the content. This value is * padding - rect, adds space between the edges of the button and the content. This value is
relative to bgimg_middle. relative to bgimg_middle.
* sound - a sound to be played when clicked. * sound - a sound to be played when triggered.
* textcolor - color, default white. * textcolor - color, default white.
* checkbox * checkbox
* noclip - boolean, set to true to allow the element to exceed formspec bounds. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* sound - a sound to be played when clicked. * sound - a sound to be played when triggered.
* dropdown * dropdown
* noclip - boolean, set to true to allow the element to exceed formspec bounds. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* sound - a sound to be played when clicked. * sound - a sound to be played when the entry is changed.
* field, pwdfield, textarea * field, pwdfield, textarea
* border - set to false to hide the textbox background and border. Default true. * border - set to false to hide the textbox background and border. Default true.
* font - Sets font type. See button `font` property for more information. * font - Sets font type. See button `font` property for more information.
@ -2870,6 +2937,10 @@ Some types may inherit styles from parent types.
* font - Sets font type. See button `font` property for more information. * font - Sets font type. See button `font` property for more information.
* font_size - Sets font size. See button `font_size` property for more information. * font_size - Sets font size. See button `font_size` property for more information.
* noclip - boolean, set to true to allow the element to exceed formspec bounds. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* list
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* size - 2d vector, sets the size of inventory slots in coordinates.
* spacing - 2d vector, sets the space between inventory slots in coordinates.
* image_button (additional properties) * image_button (additional properties)
* fgimg - standard image. Defaults to none. * fgimg - standard image. Defaults to none.
* fgimg_hovered - image when hovered. Defaults to fgimg when not provided. * fgimg_hovered - image when hovered. Defaults to fgimg when not provided.
@ -2877,12 +2948,12 @@ Some types may inherit styles from parent types.
* fgimg_pressed - image when pressed. Defaults to fgimg when not provided. * fgimg_pressed - image when pressed. Defaults to fgimg when not provided.
* This is deprecated, use states instead. * This is deprecated, use states instead.
* NOTE: The parameters of any given image_button will take precedence over fgimg/fgimg_pressed * NOTE: The parameters of any given image_button will take precedence over fgimg/fgimg_pressed
* sound - a sound to be played when clicked. * sound - a sound to be played when triggered.
* scrollbar * scrollbar
* noclip - boolean, set to true to allow the element to exceed formspec bounds. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* tabheader * tabheader
* noclip - boolean, set to true to allow the element to exceed formspec bounds. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* sound - a sound to be played when clicked. * sound - a sound to be played when a different tab is selected.
* textcolor - color. Default white. * textcolor - color. Default white.
* table, textlist * table, textlist
* font - Sets font type. See button `font` property for more information. * font - Sets font type. See button `font` property for more information.
@ -3041,9 +3112,8 @@ Colors
Named colors are also supported and are equivalent to Named colors are also supported and are equivalent to
[CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors). [CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors).
To specify the value of the alpha channel, append `#AA` to the end of the color To specify the value of the alpha channel, append `#A` or `#AA` to the end of
name (e.g. `colorname#08`). For named colors the hexadecimal string the color name (e.g. `colorname#08`).
representing the alpha value must (always) be two hexadecimal digits.
`ColorSpec` `ColorSpec`
----------- -----------
@ -3109,6 +3179,16 @@ For the following functions, `v`, `v1`, `v2` are vectors,
* Returns a vector. * Returns a vector.
* A copy of `a` if `a` is a vector. * A copy of `a` if `a` is a vector.
* `{x = a, y = b, z = c}`, if all of `a`, `b`, `c` are defined numbers. * `{x = a, y = b, z = c}`, if all of `a`, `b`, `c` are defined numbers.
* `vector.from_string(s[, init])`:
* Returns `v, np`, where `v` is a vector read from the given string `s` and
`np` is the next position in the string after the vector.
* Returns `nil` on failure.
* `s`: Has to begin with a substring of the form `"(x, y, z)"`. Additional
spaces, leaving away commas and adding an additional comma to the end
is allowed.
* `init`: If given starts looking for the vector at this string index.
* `vector.to_string(v)`:
* Returns a string of the form `"(x, y, z)"`.
* `vector.direction(p1, p2)`: * `vector.direction(p1, p2)`:
* Returns a vector of length 1 with direction `p1` to `p2`. * Returns a vector of length 1 with direction `p1` to `p2`.
* If `p1` and `p2` are identical, returns `{x = 0, y = 0, z = 0}`. * If `p1` and `p2` are identical, returns `{x = 0, y = 0, z = 0}`.
@ -3123,6 +3203,7 @@ For the following functions, `v`, `v1`, `v2` are vectors,
* Returns a vector, each dimension rounded down. * Returns a vector, each dimension rounded down.
* `vector.round(v)`: * `vector.round(v)`:
* Returns a vector, each dimension rounded to nearest integer. * Returns a vector, each dimension rounded to nearest integer.
* At a multiple of 0.5, rounds away from zero.
* `vector.apply(v, func)`: * `vector.apply(v, func)`:
* Returns a vector where the function `func` has been applied to each * Returns a vector where the function `func` has been applied to each
component. component.
@ -3197,6 +3278,8 @@ Helper functions
* If the absolute value of `x` is within the `tolerance` or `x` is NaN, * If the absolute value of `x` is within the `tolerance` or `x` is NaN,
`0` is returned. `0` is returned.
* `math.factorial(x)`: returns the factorial of `x` * `math.factorial(x)`: returns the factorial of `x`
* `math.round(x)`: Returns `x` rounded to the nearest integer.
* At a multiple of 0.5, rounds away from zero.
* `string.split(str, separator, include_empty, max_splits, sep_is_pattern)` * `string.split(str, separator, include_empty, max_splits, sep_is_pattern)`
* `separator`: string, default: `","` * `separator`: string, default: `","`
* `include_empty`: boolean, default: `false` * `include_empty`: boolean, default: `false`
@ -3244,7 +3327,8 @@ Helper functions
* Appends all values in `other_table` to `table` - uses `#table + 1` to * Appends all values in `other_table` to `table` - uses `#table + 1` to
find new indices. find new indices.
* `table.key_value_swap(t)`: returns a table with keys and values swapped * `table.key_value_swap(t)`: returns a table with keys and values swapped
* If multiple keys in `t` map to the same value, the result is undefined. * If multiple keys in `t` map to the same value, it is unspecified which
value maps to that key.
* `table.shuffle(table, [from], [to], [random_func])`: * `table.shuffle(table, [from], [to], [random_func])`:
* Shuffles elements `from` to `to` in `table` in place * Shuffles elements `from` to `to` in `table` in place
* `from` defaults to `1` * `from` defaults to `1`
@ -4182,6 +4266,8 @@ Callbacks:
* Called when the object is instantiated. * Called when the object is instantiated.
* `dtime_s` is the time passed since the object was unloaded, which can be * `dtime_s` is the time passed since the object was unloaded, which can be
used for updating the entity state. used for updating the entity state.
* `on_deactivate(self)
* Called when the object is about to get removed or unloaded.
* `on_step(self, dtime)` * `on_step(self, dtime)`
* Called on every server tick, after movement and collision processing. * Called on every server tick, after movement and collision processing.
`dtime` is usually 0.1 seconds, as per the `dedicated_server_step` setting `dtime` is usually 0.1 seconds, as per the `dedicated_server_step` setting
@ -4302,11 +4388,14 @@ Utilities
* `minetest.get_current_modname()`: returns the currently loading mod's name, * `minetest.get_current_modname()`: returns the currently loading mod's name,
when loading a mod. when loading a mod.
* `minetest.get_modpath(modname)`: returns e.g. * `minetest.get_modpath(modname)`: returns the directory path for a mod,
`"/home/user/.minetest/usermods/modname"`. e.g. `"/home/user/.minetest/usermods/modname"`.
* Useful for loading additional `.lua` modules or static data from mod * Returns nil if the mod is not enabled or does not exist (not installed).
* `minetest.get_modnames()`: returns a list of installed mods * Works regardless of whether the mod has been loaded yet.
* Return a list of installed mods, sorted alphabetically * Useful for loading additional `.lua` modules or static data from a mod,
or checking if a mod is enabled.
* `minetest.get_modnames()`: returns a list of enabled mods, sorted alphabetically.
* Does not include disabled mods, even if they are installed.
* `minetest.get_worldpath()`: returns e.g. `"/home/user/.minetest/world"` * `minetest.get_worldpath()`: returns e.g. `"/home/user/.minetest/world"`
* Useful for storing custom data * Useful for storing custom data
* `minetest.is_singleplayer()` * `minetest.is_singleplayer()`
@ -4349,6 +4438,11 @@ Utilities
object_step_has_moveresult = true, object_step_has_moveresult = true,
-- Whether get_velocity() and add_velocity() can be used on players (5.4.0) -- Whether get_velocity() and add_velocity() can be used on players (5.4.0)
direct_velocity_on_players = true, direct_velocity_on_players = true,
-- nodedef's use_texture_alpha accepts new string modes (5.4.0)
use_texture_alpha_string_modes = true,
-- degrotate param2 rotates in units of 1.5° instead of 2°
-- thus changing the range of values from 0-179 to 0-240 (5.5.0)
degrotate_240_steps = true,
} }
* `minetest.has_feature(arg)`: returns `boolean, missing_features` * `minetest.has_feature(arg)`: returns `boolean, missing_features`
@ -4408,6 +4502,9 @@ Utilities
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data * `minetest.sha1(data, [raw])`: returns the sha1 hash of data
* `data`: string of data to hash * `data`: string of data to hash
* `raw`: return raw bytes instead of hex digits, default: false * `raw`: return raw bytes instead of hex digits, default: false
* `minetest.colorspec_to_colorstring(colorspec)`: Converts a ColorSpec to a
ColorString. If the ColorSpec is invalid, returns `nil`.
* `colorspec`: The ColorSpec to convert
Logging Logging
------- -------
@ -4557,6 +4654,10 @@ Call these functions only at load time!
the puncher to the punched. the puncher to the punched.
* `damage`: Number that represents the damage calculated by the engine * `damage`: Number that represents the damage calculated by the engine
* should return `true` to prevent the default damage mechanism * should return `true` to prevent the default damage mechanism
* `minetest.register_on_rightclickplayer(function(player, clicker))`
* Called when a player is right-clicked
* `player`: ObjectRef - Player that was right-clicked
* `clicker`: ObjectRef - Object that right-clicked, may or may not be a player
* `minetest.register_on_player_hpchange(function(player, hp_change, reason), modifier)` * `minetest.register_on_player_hpchange(function(player, hp_change, reason), modifier)`
* Called when the player gets damaged or healed * Called when the player gets damaged or healed
* `player`: ObjectRef of the player * `player`: ObjectRef of the player
@ -4607,6 +4708,7 @@ Call these functions only at load time!
* `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of: * `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of:
* `moved_too_fast` * `moved_too_fast`
* `interacted_too_far` * `interacted_too_far`
* `interacted_with_self`
* `interacted_while_dead` * `interacted_while_dead`
* `finished_unknown_dig` * `finished_unknown_dig`
* `dug_unbreakable` * `dug_unbreakable`
@ -4847,7 +4949,7 @@ Environment access
* Punch node with the same effects that a player would cause * Punch node with the same effects that a player would cause
* `minetest.spawn_falling_node(pos)` * `minetest.spawn_falling_node(pos)`
* Change node into falling node * Change node into falling node
* Returns `true` if successful, `false` on failure * Returns `true` and the ObjectRef of the spawned entity if successful, `false` on failure
* `minetest.find_nodes_with_meta(pos1, pos2)` * `minetest.find_nodes_with_meta(pos1, pos2)`
* Get a table of positions of nodes that have metadata within a region * Get a table of positions of nodes that have metadata within a region
@ -4866,6 +4968,9 @@ Environment access
* `minetest.get_objects_inside_radius(pos, radius)`: returns a list of * `minetest.get_objects_inside_radius(pos, radius)`: returns a list of
ObjectRefs. ObjectRefs.
* `radius`: using an euclidean metric * `radius`: using an euclidean metric
* `minetest.get_objects_in_area(pos1, pos2)`: returns a list of
ObjectRefs.
* `pos1` and `pos2` are the min and max positions of the area to search.
* `minetest.set_timeofday(val)` * `minetest.set_timeofday(val)`
* `val` is between `0` and `1`; `0` for midnight, `0.5` for midday * `val` is between `0` and `1`; `0` for midnight, `0.5` for midday
* `minetest.get_timeofday()` * `minetest.get_timeofday()`
@ -5399,20 +5504,22 @@ Server
* Returns a code (0: successful, 1: no such player, 2: player is connected) * Returns a code (0: successful, 1: no such player, 2: player is connected)
* `minetest.remove_player_auth(name)`: remove player authentication data * `minetest.remove_player_auth(name)`: remove player authentication data
* Returns boolean indicating success (false if player nonexistant) * Returns boolean indicating success (false if player nonexistant)
* `minetest.dynamic_add_media(filepath)` * `minetest.dynamic_add_media(filepath, callback)`
* Adds the file at the given path to the media sent to clients by the server * `filepath`: path to a media file on the filesystem
on startup and also pushes this file to already connected clients. * `callback`: function with arguments `name`, where name is a player name
(previously there was no callback argument; omitting it is deprecated)
* Adds the file to the media sent to clients by the server on startup
and also pushes this file to already connected clients.
The file must be a supported image, sound or model format. It must not be The file must be a supported image, sound or model format. It must not be
modified, deleted, moved or renamed after calling this function. modified, deleted, moved or renamed after calling this function.
The list of dynamically added media is not persisted. The list of dynamically added media is not persisted.
* Returns boolean indicating success (duplicate files count as error) * Returns false on error, true if the request was accepted
* The media will be ready to use (in e.g. entity textures, sound_play) * The given callback will be called for every player as soon as the
immediately after calling this function. media is available on the client.
Old clients that lack support for this feature will not see the media Old clients that lack support for this feature will not see the media
unless they reconnect to the server. unless they reconnect to the server. (callback won't be called)
* Since media transferred this way does not use client caching or HTTP * Since media transferred this way currently does not use client caching
transfers, dynamic media should not be used with big files or performance or HTTP transfers, dynamic media should not be used with big files.
will suffer.
Bans Bans
---- ----
@ -5549,72 +5656,28 @@ Schematics
HTTP Requests HTTP Requests
------------- -------------
* `minetest.get_http_api()`
* returns `HTTPApiTable` containing http functions. * `minetest.request_http_api()`:
* The returned table contains the functions `fetch_sync`, `fetch_async` and * returns `HTTPApiTable` containing http functions if the calling mod has
been granted access by being listed in the `secure.http_mods` or
`secure.trusted_mods` setting, otherwise returns `nil`.
* The returned table contains the functions `fetch`, `fetch_async` and
`fetch_async_get` described below. `fetch_async_get` described below.
* Only works at init time and must be called from the mod's main scope
(not from a function).
* Function only exists if minetest server was built with cURL support. * Function only exists if minetest server was built with cURL support.
* `HTTPApiTable.fetch_sync(HTTPRequest req)`: returns HTTPRequestResult * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN
* Performs given request synchronously A LOCAL VARIABLE!**
* `HTTPApiTable.fetch(HTTPRequest req, callback)`
* Performs given request asynchronously and calls callback upon completion
* callback: `function(HTTPRequestResult res)`
* Use this HTTP function if you are unsure, the others are for advanced use
* `HTTPApiTable.fetch_async(HTTPRequest req)`: returns handle * `HTTPApiTable.fetch_async(HTTPRequest req)`: returns handle
* Performs given request asynchronously and returns handle for * Performs given request asynchronously and returns handle for
`HTTPApiTable.fetch_async_get` `HTTPApiTable.fetch_async_get`
* `HTTPApiTable.fetch_async_get(handle)`: returns HTTPRequestResult * `HTTPApiTable.fetch_async_get(handle)`: returns HTTPRequestResult
* Return response data for given asynchronous HTTP request * Return response data for given asynchronous HTTP request
### `HTTPRequest` definition
Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
{
url = "http://example.org",
timeout = 10,
-- Timeout for connection in seconds. Default is 3 seconds.
post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"},
-- Optional, if specified a POST request with post_data is performed.
-- Accepts both a string and a table. If a table is specified, encodes
-- table as x-www-form-urlencoded key-value pairs.
-- If post_data is not specified, a GET request is performed instead.
user_agent = "ExampleUserAgent",
-- Optional, if specified replaces the default minetest user agent with
-- given string
extra_headers = { "Accept-Language: en-us", "Accept-Charset: utf-8" },
-- Optional, if specified adds additional headers to the HTTP request.
-- You must make sure that the header strings follow HTTP specification
-- ("Key: Value").
multipart = boolean
-- Optional, if true performs a multipart HTTP request.
-- Default is false.
}
### `HTTPRequestResult` definition
Passed to `HTTPApiTable.fetch` callback. Returned by
`HTTPApiTable.fetch_async_get`.
{
completed = true,
-- If true, the request has finished (either succeeded, failed or timed
-- out)
succeeded = true,
-- If true, the request was successful
timeout = false,
-- If true, the request timed out
code = 200,
-- HTTP status code
data = "response"
}
Storage API Storage API
----------- -----------
@ -6034,18 +6097,18 @@ an itemstring, a table or `nil`.
stack). stack).
* `set_metadata(metadata)`: (DEPRECATED) Returns true. * `set_metadata(metadata)`: (DEPRECATED) Returns true.
* `get_description()`: returns the description shown in inventory list tooltips. * `get_description()`: returns the description shown in inventory list tooltips.
* The engine uses the same as this function for item descriptions. * The engine uses this when showing item descriptions in tooltips.
* Fields for finding the description, in order: * Fields for finding the description, in order:
* `description` in item metadata (See [Item Metadata].) * `description` in item metadata (See [Item Metadata].)
* `description` in item definition * `description` in item definition
* item name * item name
* `get_short_description()`: returns the short description. * `get_short_description()`: returns the short description or nil.
* Unlike the description, this does not include new lines. * Unlike the description, this does not include new lines.
* The engine uses the same as this function for short item descriptions.
* Fields for finding the short description, in order: * Fields for finding the short description, in order:
* `short_description` in item metadata (See [Item Metadata].) * `short_description` in item metadata (See [Item Metadata].)
* `short_description` in item definition * `short_description` in item definition
* first line of the description (See `get_description()`.) * first line of the description (From item meta or def, see `get_description()`.)
* Returns nil if none of the above are set
* `clear()`: removes all items from the stack, making it empty. * `clear()`: removes all items from the stack, making it empty.
* `replace(item)`: replace the contents of this stack. * `replace(item)`: replace the contents of this stack.
* `item` can also be an itemstring or table. * `item` can also be an itemstring or table.
@ -6222,8 +6285,8 @@ object you are working with still exists.
* `time_from_last_punch` = time since last punch action of the puncher * `time_from_last_punch` = time since last punch action of the puncher
* `direction`: can be `nil` * `direction`: can be `nil`
* `right_click(clicker)`; `clicker` is another `ObjectRef` * `right_click(clicker)`; `clicker` is another `ObjectRef`
* `get_hp()`: returns number of hitpoints (2 * number of hearts) * `get_hp()`: returns number of health points
* `set_hp(hp, reason)`: set number of hitpoints (2 * number of hearts). * `set_hp(hp, reason)`: set number of health points
* See reason in register_on_player_hpchange * See reason in register_on_player_hpchange
* Is limited to the range of 0 ... 65535 (2^16 - 1) * Is limited to the range of 0 ... 65535 (2^16 - 1)
* For players: HP are also limited by `hp_max` specified in the player's * For players: HP are also limited by `hp_max` specified in the player's
@ -6246,21 +6309,22 @@ object you are working with still exists.
`frame_loop`. `frame_loop`.
* `set_animation_frame_speed(frame_speed)` * `set_animation_frame_speed(frame_speed)`
* `frame_speed`: number, default: `15.0` * `frame_speed`: number, default: `15.0`
* `set_attach(parent, bone, position, rotation, forced_visible)` * `set_attach(parent[, bone, position, rotation, forced_visible])`
* `bone`: string * `bone`: string. Default is `""`, the root bone
* `position`: `{x=num, y=num, z=num}` (relative) * `position`: `{x=num, y=num, z=num}`, relative, default `{x=0, y=0, z=0}`
* `rotation`: `{x=num, y=num, z=num}` = Rotation on each axis, in degrees * `rotation`: `{x=num, y=num, z=num}` = Rotation on each axis, in degrees.
Default `{x=0, y=0, z=0}`
* `forced_visible`: Boolean to control whether the attached entity * `forced_visible`: Boolean to control whether the attached entity
should appear in first person. should appear in first person. Default `false`.
* `get_attach()`: returns parent, bone, position, rotation, forced_visible, * `get_attach()`: returns parent, bone, position, rotation, forced_visible,
or nil if it isn't attached. or nil if it isn't attached.
* `get_children()`: returns a list of ObjectRefs that are attached to the * `get_children()`: returns a list of ObjectRefs that are attached to the
object. object.
* `set_detach()` * `set_detach()`
* `set_bone_position(bone, position, rotation)` * `set_bone_position([bone, position, rotation])`
* `bone`: string * `bone`: string. Default is `""`, the root bone
* `position`: `{x=num, y=num, z=num}` (relative) * `position`: `{x=num, y=num, z=num}`, relative, `default {x=0, y=0, z=0}`
* `rotation`: `{x=num, y=num, z=num}` * `rotation`: `{x=num, y=num, z=num}`, default `{x=0, y=0, z=0}`
* `get_bone_position(bone)`: returns position and rotation of the bone * `get_bone_position(bone)`: returns position and rotation of the bone
* `set_properties(object property table)` * `set_properties(object property table)`
* `get_properties()`: returns object property table * `get_properties()`: returns object property table
@ -6268,15 +6332,21 @@ object you are working with still exists.
* `get_nametag_attributes()` * `get_nametag_attributes()`
* returns a table with the attributes of the nametag of an object * returns a table with the attributes of the nametag of an object
* { * {
color = {a=0..255, r=0..255, g=0..255, b=0..255},
text = "", text = "",
color = {a=0..255, r=0..255, g=0..255, b=0..255},
bgcolor = {a=0..255, r=0..255, g=0..255, b=0..255},
} }
* `set_nametag_attributes(attributes)` * `set_nametag_attributes(attributes)`
* sets the attributes of the nametag of an object * sets the attributes of the nametag of an object
* `attributes`: * `attributes`:
{ {
color = ColorSpec,
text = "My Nametag", text = "My Nametag",
color = ColorSpec,
-- ^ Text color
bgcolor = ColorSpec or false,
-- ^ Sets background color of nametag
-- `false` will cause the background to be set automatically based on user settings
-- Default: false
} }
#### Lua entity only (no-op for other objects) #### Lua entity only (no-op for other objects)
@ -6469,6 +6539,8 @@ object you are working with still exists.
* `selected_mode` is the mode index to be selected after modes have been changed * `selected_mode` is the mode index to be selected after modes have been changed
(0 is the first mode). (0 is the first mode).
* `set_sky(sky_parameters)` * `set_sky(sky_parameters)`
* The presence of the function `set_sun`, `set_moon` or `set_stars` indicates
whether `set_sky` accepts this format. Check the legacy format otherwise.
* `sky_parameters` is a table with the following optional fields: * `sky_parameters` is a table with the following optional fields:
* `base_color`: ColorSpec, changes fog in "skybox" and "plain". * `base_color`: ColorSpec, changes fog in "skybox" and "plain".
* `type`: Available types: * `type`: Available types:
@ -6510,6 +6582,15 @@ object you are working with still exists.
abides by, `"custom"` uses `sun_tint` and `moon_tint`, while abides by, `"custom"` uses `sun_tint` and `moon_tint`, while
`"default"` uses the classic Minetest sun and moon tinting. `"default"` uses the classic Minetest sun and moon tinting.
Will use tonemaps, if set to `"default"`. (default: `"default"`) Will use tonemaps, if set to `"default"`. (default: `"default"`)
* `set_sky(base_color, type, {texture names}, clouds)`
* Deprecated. Use `set_sky(sky_parameters)`
* `base_color`: ColorSpec, defaults to white
* `type`: Available types:
* `"regular"`: Uses 0 textures, `bgcolor` ignored
* `"skybox"`: Uses 6 textures, `bgcolor` used
* `"plain"`: Uses 0 textures, `bgcolor` used
* `clouds`: Boolean for whether clouds appear in front of `"skybox"` or
`"plain"` custom skyboxes (default: `true`)
* `get_sky()`: returns base_color, type, table of textures, clouds. * `get_sky()`: returns base_color, type, table of textures, clouds.
* `get_sky_color()`: returns a table with the `sky_color` parameters as in * `get_sky_color()`: returns a table with the `sky_color` parameters as in
`set_sky`. `set_sky`.
@ -6577,8 +6658,8 @@ object you are working with still exists.
* `frame_speed` sets the animations frame speed. Default is 30. * `frame_speed` sets the animations frame speed. Default is 30.
* `get_local_animation()`: returns idle, walk, dig, walk_while_dig tables and * `get_local_animation()`: returns idle, walk, dig, walk_while_dig tables and
`frame_speed`. `frame_speed`.
* `set_eye_offset(firstperson, thirdperson)`: defines offset vectors for camera * `set_eye_offset([firstperson, thirdperson])`: defines offset vectors for
per player. camera per player. An argument defaults to `{x=0, y=0, z=0}` if unspecified.
* in first person view * in first person view
* in third person view (max. values `{x=-10/10,y=-10,15,z=-5/5}`) * in third person view (max. values `{x=-10/10,y=-10,15,z=-5/5}`)
* `get_eye_offset()`: returns first and third person offsets. * `get_eye_offset()`: returns first and third person offsets.
@ -6934,10 +7015,18 @@ Player properties need to be saved manually.
-- in mods. -- in mods.
nametag = "", nametag = "",
-- By default empty, for players their name is shown if empty -- The name to display on the head of the object. By default empty.
-- If the object is a player, a nil or empty nametag is replaced by the player's name.
-- For all other objects, a nil or empty string removes the nametag.
-- To hide a nametag, set its color alpha to zero. That will disable it entirely.
nametag_color = <ColorSpec>, nametag_color = <ColorSpec>,
-- Sets color of nametag -- Sets text color of nametag
nametag_bgcolor = <ColorSpec>,
-- Sets background color of nametag
-- `false` will cause the background to be set automatically based on user settings.
-- Default: false
infotext = "", infotext = "",
-- By default empty, text to be shown when pointed at object -- By default empty, text to be shown when pointed at object
@ -7150,8 +7239,9 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
short_description = "Steel Axe", short_description = "Steel Axe",
-- Must not contain new lines. -- Must not contain new lines.
-- Defaults to the first line of description. -- Defaults to nil.
-- See also: `get_short_description` in [`ItemStack`] -- Use an [`ItemStack`] to get the short description, eg:
-- ItemStack(itemname):get_short_description()
groups = {}, groups = {},
-- key = name, value = rating; rating = 1..3. -- key = name, value = rating; rating = 1..3.
@ -7324,10 +7414,18 @@ Used by `minetest.register_node`.
-- If the node has a palette, then this setting only has an effect in -- If the node has a palette, then this setting only has an effect in
-- the inventory and on the wield item. -- the inventory and on the wield item.
use_texture_alpha = false, use_texture_alpha = ...,
-- Use texture's alpha channel -- Specifies how the texture's alpha channel will be used for rendering.
-- If this is set to false, the node will be rendered fully opaque -- possible values:
-- regardless of any texture transparency. -- * "opaque": Node is rendered opaque regardless of alpha channel
-- * "clip": A given pixel is either fully see-through or opaque
-- depending on the alpha channel being below/above 50% in value
-- * "blend": The alpha channel specifies how transparent a given pixel
-- of the rendered node is
-- The default is "opaque" for drawtypes normal, liquid and flowingliquid;
-- "clip" otherwise.
-- If set to a boolean value (deprecated): true either sets it to blend
-- or clip, false sets it to clip or opaque mode depending on the drawtype.
palette = "palette.png", palette = "palette.png",
-- The node's `param2` is used to select a pixel from the image. -- The node's `param2` is used to select a pixel from the image.
@ -7369,7 +7467,16 @@ Used by `minetest.register_node`.
-- If true, liquids flow into and replace this node. -- If true, liquids flow into and replace this node.
-- Warning: making a liquid node 'floodable' will cause problems. -- Warning: making a liquid node 'floodable' will cause problems.
liquidtype = "none", -- "none" / "source" / "flowing" liquidtype = "none", -- specifies liquid physics
-- * "none": no liquid physics
-- * "source": spawns flowing liquid nodes at all 4 sides and below;
-- recommended drawtype: "liquid".
-- * "flowing": spawned from source, spawns more flowing liquid nodes
-- around it until `liquid_range` is reached;
-- will drain out without a source;
-- recommended drawtype: "flowingliquid".
-- If it's "source" or "flowing" and `liquid_range > 0`, then
-- both `liquid_alternative_*` fields must be specified
liquid_alternative_flowing = "", -- Flowing version of source liquid liquid_alternative_flowing = "", -- Flowing version of source liquid
@ -7390,8 +7497,12 @@ Used by `minetest.register_node`.
leveled_max = 127, leveled_max = 127,
-- Maximum value for `leveled` (0-127), enforced in -- Maximum value for `leveled` (0-127), enforced in
-- `minetest.set_node_level` and `minetest.add_node_level`. -- `minetest.set_node_level` and `minetest.add_node_level`.
-- Values above 124 might causes collision detection issues.
liquid_range = 8, -- Number of flowing nodes around source (max. 8) liquid_range = 8,
-- Maximum distance that flowing liquid nodes can spread around
-- source on flat land;
-- maximum = 8; set to 0 to disable liquid flow
drowning = 0, drowning = 0,
-- Player will take this amount of damage if no bubbles are left -- Player will take this amount of damage if no bubbles are left
@ -7417,6 +7528,7 @@ Used by `minetest.register_node`.
type = "fixed", type = "fixed",
fixed = { fixed = {
{-2 / 16, -0.5, -2 / 16, 2 / 16, 3 / 16, 2 / 16}, {-2 / 16, -0.5, -2 / 16, 2 / 16, 3 / 16, 2 / 16},
-- Node box format: see [Node boxes]
}, },
}, },
-- Custom selection box definition. Multiple boxes can be defined. -- Custom selection box definition. Multiple boxes can be defined.
@ -7427,13 +7539,12 @@ Used by `minetest.register_node`.
type = "fixed", type = "fixed",
fixed = { fixed = {
{-2 / 16, -0.5, -2 / 16, 2 / 16, 3 / 16, 2 / 16}, {-2 / 16, -0.5, -2 / 16, 2 / 16, 3 / 16, 2 / 16},
-- Node box format: see [Node boxes]
}, },
}, },
-- Custom collision box definition. Multiple boxes can be defined. -- Custom collision box definition. Multiple boxes can be defined.
-- If "nodebox" drawtype is used and collision_box is nil, then node_box -- If "nodebox" drawtype is used and collision_box is nil, then node_box
-- definition is used for the collision box. -- definition is used for the collision box.
-- Both of the boxes above are defined as:
-- {xmin, ymin, zmin, xmax, ymax, zmax} in nodes from node center.
-- Support maps made in and before January 2012 -- Support maps made in and before January 2012
legacy_facedir_simple = false, legacy_facedir_simple = false,
@ -7601,6 +7712,8 @@ Used by `minetest.register_node`.
on_dig = function(pos, node, digger), on_dig = function(pos, node, digger),
-- default: minetest.node_dig -- default: minetest.node_dig
-- By default checks privileges, wears out tool and removes node. -- By default checks privileges, wears out tool and removes node.
-- return true if the node was dug successfully, false otherwise.
-- Deprecated: returning nil is the same as returning true.
on_timer = function(pos, elapsed), on_timer = function(pos, elapsed),
-- default: nil -- default: nil
@ -7640,6 +7753,13 @@ Used by `minetest.register_node`.
-- intensity: 1.0 = mid range of regular TNT. -- intensity: 1.0 = mid range of regular TNT.
-- If defined, called when an explosion touches the node, instead of -- If defined, called when an explosion touches the node, instead of
-- removing the node. -- removing the node.
mod_origin = "modname",
-- stores which mod actually registered a node
-- if it can not find a source, returns "??"
-- useful for getting what mod truly registered something
-- example: if a node is registered as ":othermodname:nodename",
-- nodename will show "othermodname", but mod_orgin will say "modname"
} }
Crafting recipes Crafting recipes
@ -8329,7 +8449,7 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
url = "http://example.org", url = "http://example.org",
timeout = 10, timeout = 10,
-- Timeout for connection in seconds. Default is 3 seconds. -- Timeout for request to be completed in seconds. Default depends on engine settings.
method = "GET", "POST", "PUT" or "DELETE" method = "GET", "POST", "PUT" or "DELETE"
-- The http method to use. Defaults to "GET". -- The http method to use. Defaults to "GET".

View File

@ -1,4 +1,4 @@
Minetest Lua Mainmenu API Reference 5.4.0 Minetest Lua Mainmenu API Reference 5.5.0
========================================= =========================================
Introduction Introduction
@ -43,10 +43,14 @@ core.get_max_supp_proto()
core.open_url(url) core.open_url(url)
^ opens the URL in a web browser, returns false on failure. ^ opens the URL in a web browser, returns false on failure.
^ Must begin with http:// or https:// ^ Must begin with http:// or https://
core.open_dir(path)
^ opens the path in the system file browser/explorer, returns false on failure.
^ Must be an existing directory.
core.get_version() (possible in async calls) core.get_version() (possible in async calls)
^ returns current core version ^ returns current core version
Filesystem Filesystem
---------- ----------
@ -63,6 +67,8 @@ core.copy_dir(source,destination,keep_soure) (possible in async calls)
^ destination folder ^ destination folder
^ keep_source DEFAULT true --> if set to false source is deleted after copying ^ keep_source DEFAULT true --> if set to false source is deleted after copying
^ returns true/false ^ returns true/false
core.is_dir(path) (possible in async calls)
^ returns true if path is a valid dir
core.extract_zip(zipfile,destination) [unzip within path required] core.extract_zip(zipfile,destination) [unzip within path required]
^ zipfile to extract ^ zipfile to extract
^ destination folder to extract to ^ destination folder to extract to
@ -79,6 +85,7 @@ core.get_video_drivers()
core.get_mapgen_names([include_hidden=false]) -> table of map generator algorithms core.get_mapgen_names([include_hidden=false]) -> table of map generator algorithms
registered in the core (possible in async calls) registered in the core (possible in async calls)
core.get_cache_path() -> path of cache core.get_cache_path() -> path of cache
core.get_temp_path() -> path of temp folder
HTTP Requests HTTP Requests
@ -197,7 +204,8 @@ core.get_screen_info()
display_width = <width of display>, display_width = <width of display>,
display_height = <height of display>, display_height = <height of display>,
window_width = <current window width>, window_width = <current window width>,
window_height = <current window height> window_height = <current window height>,
render_info = <active render information>
} }
@ -207,6 +215,9 @@ Content and Packages
Content - an installed mod, modpack, game, or texture pack (txt) Content - an installed mod, modpack, game, or texture pack (txt)
Package - content which is downloadable from the content db, may or may not be installed. Package - content which is downloadable from the content db, may or may not be installed.
* core.get_user_path() (possible in async calls)
* returns path to global user data,
the directory that contains user-provided mods, worlds, games, and texture packs.
* core.get_modpath() (possible in async calls) * core.get_modpath() (possible in async calls)
* returns path to global modpath * returns path to global modpath
* core.get_clientmodpath() (possible in async calls) * core.get_clientmodpath() (possible in async calls)
@ -244,32 +255,6 @@ Package - content which is downloadable from the content db, may or may not be i
} }
Favorites
---------
core.get_favorites(location) -> list of favorites (possible in async calls)
^ location: "local" or "online"
^ returns {
[1] = {
clients = <number of clients/nil>,
clients_max = <maximum number of clients/nil>,
version = <server version/nil>,
password = <true/nil>,
creative = <true/nil>,
damage = <true/nil>,
pvp = <true/nil>,
description = <server description/nil>,
name = <server name/nil>,
address = <address of server/nil>,
port = <port>
clients_list = <array of clients/nil>
mods = <array of mods/nil>
},
...
}
core.delete_favorite(id, location) -> success
Logging Logging
------- -------

View File

@ -493,19 +493,8 @@ Static objects are persistent freely moving objects in the world.
Object types: Object types:
1: Test object 1: Test object
2: Item
3: Rat (obsolete)
4: Oerkki (obsolete)
5: Firefly (obsolete)
6: MobV2 (obsolete)
7: LuaEntity 7: LuaEntity
1: Item:
u8 version
version 0:
u16 len
u8[len] itemstring
7: LuaEntity: 7: LuaEntity:
u8 compatibility_byte (always 1) u8 compatibility_byte (always 1)
u16 len u16 len

View File

@ -1,4 +1,4 @@
local WATER_ALPHA = 160 local WATER_ALPHA = "^[opacity:" .. 160
local WATER_VISC = 1 local WATER_VISC = 1
local LAVA_VISC = 7 local LAVA_VISC = 7
@ -128,12 +128,12 @@ minetest.register_node("basenodes:water_source", {
"Drowning damage: 1", "Drowning damage: 1",
drawtype = "liquid", drawtype = "liquid",
waving = 3, waving = 3,
tiles = {"default_water.png"}, tiles = {"default_water.png"..WATER_ALPHA},
special_tiles = { special_tiles = {
{name = "default_water.png", backface_culling = false}, {name = "default_water.png"..WATER_ALPHA, backface_culling = false},
{name = "default_water.png", backface_culling = true}, {name = "default_water.png"..WATER_ALPHA, backface_culling = true},
}, },
alpha = WATER_ALPHA, use_texture_alpha = "blend",
paramtype = "light", paramtype = "light",
walkable = false, walkable = false,
pointable = false, pointable = false,
@ -156,10 +156,12 @@ minetest.register_node("basenodes:water_flowing", {
waving = 3, waving = 3,
tiles = {"default_water_flowing.png"}, tiles = {"default_water_flowing.png"},
special_tiles = { special_tiles = {
{name = "default_water_flowing.png", backface_culling = false}, {name = "default_water_flowing.png"..WATER_ALPHA,
{name = "default_water_flowing.png", backface_culling = false}, backface_culling = false},
{name = "default_water_flowing.png"..WATER_ALPHA,
backface_culling = false},
}, },
alpha = WATER_ALPHA, use_texture_alpha = "blend",
paramtype = "light", paramtype = "light",
paramtype2 = "flowingliquid", paramtype2 = "flowingliquid",
walkable = false, walkable = false,
@ -181,12 +183,12 @@ minetest.register_node("basenodes:river_water_source", {
"Drowning damage: 1", "Drowning damage: 1",
drawtype = "liquid", drawtype = "liquid",
waving = 3, waving = 3,
tiles = { "default_river_water.png" }, tiles = { "default_river_water.png"..WATER_ALPHA },
special_tiles = { special_tiles = {
{name = "default_river_water.png", backface_culling = false}, {name = "default_river_water.png"..WATER_ALPHA, backface_culling = false},
{name = "default_river_water.png", backface_culling = true}, {name = "default_river_water.png"..WATER_ALPHA, backface_culling = true},
}, },
alpha = WATER_ALPHA, use_texture_alpha = "blend",
paramtype = "light", paramtype = "light",
walkable = false, walkable = false,
pointable = false, pointable = false,
@ -209,12 +211,14 @@ minetest.register_node("basenodes:river_water_flowing", {
"Drowning damage: 1", "Drowning damage: 1",
drawtype = "flowingliquid", drawtype = "flowingliquid",
waving = 3, waving = 3,
tiles = {"default_river_water_flowing.png"}, tiles = {"default_river_water_flowing.png"..WATER_ALPHA},
special_tiles = { special_tiles = {
{name = "default_river_water_flowing.png", backface_culling = false}, {name = "default_river_water_flowing.png"..WATER_ALPHA,
{name = "default_river_water_flowing.png", backface_culling = false}, backface_culling = false},
{name = "default_river_water_flowing.png"..WATER_ALPHA,
backface_culling = false},
}, },
alpha = WATER_ALPHA, use_texture_alpha = "blend",
paramtype = "light", paramtype = "light",
paramtype2 = "flowingliquid", paramtype2 = "flowingliquid",
walkable = false, walkable = false,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,3 +0,0 @@
This is for testing loading textures from subfolders.
If it works correctly, the default_grass_side.png file in this folder is used but
default_grass.png is not overwritten by the file in this folder.

View File

@ -0,0 +1,7 @@
The dirt_with_grass folder is for testing loading textures from subfolders.
If it works correctly, the default_grass_side.png file in the folder is used but
default_grass.png is not overwritten by the file in the folder.
default_dirt.png should be overwritten by the default_dirt.png in the unittests
mod which depends on basenodes.

View File

@ -23,6 +23,18 @@ minetest.register_node("chest:chest", {
local inv = meta:get_inventory() local inv = meta:get_inventory()
return inv:is_empty("main") return inv:is_empty("main")
end, end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
minetest.chat_send_player(player:get_player_name(), "Allow put: " .. stack:to_string())
return stack:get_count()
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
minetest.chat_send_player(player:get_player_name(), "Allow take: " .. stack:to_string())
return stack:get_count()
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
minetest.chat_send_player(player:get_player_name(), "On put: " .. stack:to_string())
end,
on_metadata_inventory_take = function(pos, listname, index, stack, player)
minetest.chat_send_player(player:get_player_name(), "On take: " .. stack:to_string())
end,
}) })

View File

@ -131,10 +131,11 @@ local function place_nodes(param)
p2_max = 63 p2_max = 63
elseif def.paramtype2 == "leveled" then elseif def.paramtype2 == "leveled" then
p2_max = 127 p2_max = 127
elseif def.paramtype2 == "degrotate" and def.drawtype == "plantlike" then elseif def.paramtype2 == "degrotate" and (def.drawtype == "plantlike" or def.drawtype == "mesh") then
p2_max = 179 p2_max = 239
elseif def.paramtype2 == "colorfacedir" or elseif def.paramtype2 == "colorfacedir" or
def.paramtype2 == "colorwallmounted" or def.paramtype2 == "colorwallmounted" or
def.paramtype2 == "colordegrotate" or
def.paramtype2 == "color" then def.paramtype2 == "color" then
p2_max = 255 p2_max = 255
end end
@ -143,7 +144,8 @@ local function place_nodes(param)
-- Skip undefined param2 values -- Skip undefined param2 values
if not ((def.paramtype2 == "meshoptions" and p2 % 8 > 4) or if not ((def.paramtype2 == "meshoptions" and p2 % 8 > 4) or
(def.paramtype2 == "colorwallmounted" and p2 % 8 > 5) or (def.paramtype2 == "colorwallmounted" and p2 % 8 > 5) or
(def.paramtype2 == "colorfacedir" and p2 % 32 > 23)) then ((def.paramtype2 == "colorfacedir" or def.paramtype2 == "colordegrotate")
and p2 % 32 > 23)) then
minetest.set_node(pos, { name = itemstring, param2 = p2 }) minetest.set_node(pos, { name = itemstring, param2 = p2 })
nodes_placed = nodes_placed + 1 nodes_placed = nodes_placed + 1
@ -215,5 +217,5 @@ minetest.register_chatcommand("test_place_nodes", {
}) })
core.register_on_chatcommand(function(name, command, params) core.register_on_chatcommand(function(name, command, params)
minetest.log("caught command '"..command.."', issued by '"..name.."'. Parameters: '"..params.."'") minetest.log("action", "caught command '"..command.."', issued by '"..name.."'. Parameters: '"..params.."'")
end) end)

View File

@ -60,11 +60,13 @@ minetest.register_node("soundstuff:footstep_liquid", {
description = "Liquid Footstep Sound Node", description = "Liquid Footstep Sound Node",
drawtype = "liquid", drawtype = "liquid",
tiles = { tiles = {
"soundstuff_node_sound.png^[colorize:#0000FF:127", "soundstuff_node_sound.png^[colorize:#0000FF:127^[opacity:190",
}, },
special_tiles = { special_tiles = {
{name = "soundstuff_node_sound.png^[colorize:#0000FF:127", backface_culling = false}, {name = "soundstuff_node_sound.png^[colorize:#0000FF:127^[opacity:190",
{name = "soundstuff_node_sound.png^[colorize:#0000FF:127", backface_culling = true}, backface_culling = false},
{name = "soundstuff_node_sound.png^[colorize:#0000FF:127^[opacity:190",
backface_culling = true},
}, },
liquids_pointable = true, liquids_pointable = true,
liquidtype = "source", liquidtype = "source",
@ -73,7 +75,7 @@ minetest.register_node("soundstuff:footstep_liquid", {
liquid_renewable = false, liquid_renewable = false,
liquid_range = 0, liquid_range = 0,
liquid_viscosity = 0, liquid_viscosity = 0,
alpha = 190, use_texture_alpha = "blend",
paramtype = "light", paramtype = "light",
walkable = false, walkable = false,
pointable = false, pointable = false,
@ -92,7 +94,6 @@ minetest.register_node("soundstuff:footstep_climbable", {
tiles = { tiles = {
"soundstuff_node_climbable.png", "soundstuff_node_climbable.png",
}, },
alpha = 120,
paramtype = "light", paramtype = "light",
sunlight_propagates = true, sunlight_propagates = true,
walkable = false, walkable = false,

View File

@ -31,6 +31,9 @@ minetest.register_entity("testentities:callback", {
on_activate = function(self, staticdata, dtime_s) on_activate = function(self, staticdata, dtime_s)
message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s) message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s)
end, end,
on_deactivate = function(self)
message("Callback entity: on_deactivate! pos="..spos(self))
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
local name = get_object_name(puncher) local name = get_object_name(puncher)
message( message(

View File

@ -94,3 +94,44 @@ minetest.register_entity("testentities:upright_animated", {
self.object:set_sprite({x=0, y=0}, 4, 1.0, false) self.object:set_sprite({x=0, y=0}, 4, 1.0, false)
end, end,
}) })
minetest.register_entity("testentities:nametag", {
initial_properties = {
visual = "sprite",
textures = { "testentities_sprite.png" },
},
on_activate = function(self, staticdata)
if staticdata ~= "" then
local data = minetest.deserialize(staticdata)
self.color = data.color
self.bgcolor = data.bgcolor
else
self.color = {
r = math.random(0, 255),
g = math.random(0, 255),
b = math.random(0, 255),
}
if math.random(0, 10) > 5 then
self.bgcolor = {
r = math.random(0, 255),
g = math.random(0, 255),
b = math.random(0, 255),
a = math.random(0, 255),
}
end
end
assert(self.color)
self.object:set_properties({
nametag = tostring(math.random(1000, 10000)),
nametag_color = self.color,
nametag_bgcolor = self.bgcolor,
})
end,
get_staticdata = function(self)
return minetest.serialize({ color = self.color, bgcolor = self.bgcolor })
end,
})

View File

@ -22,3 +22,10 @@ minetest.register_craftitem("testfood:bad5", {
on_use = minetest.item_eat(-5), on_use = minetest.item_eat(-5),
}) })
minetest.register_craftitem("testfood:replace1", {
description = S("Replacing Food (+1)").."\n"..
S("Replaced with 'Good Food (+1)' when eaten"),
inventory_image = "testfood_replace.png",
on_use = minetest.item_eat(1, "testfood:good1"),
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

View File

@ -33,6 +33,34 @@ local tabheaders_fs = [[
tabheader[8,6;10,1.5;tabs_size2;Height=1.5;1;false;false] tabheader[8,6;10,1.5;tabs_size2;Height=1.5;1;false;false]
]] ]]
local inv_style_fs = [[
style_type[list;noclip=true]
list[current_player;main;-0.75,0.75;2,2]
real_coordinates[false]
list[current_player;main;1.5,0;3,2]
real_coordinates[true]
real_coordinates[false]
style_type[list;size=1.1;spacing=0.1]
list[current_player;main;5,0;3,2]
real_coordinates[true]
style_type[list;size=.001;spacing=0]
list[current_player;main;7,3.5;8,4]
box[3,3.5;1,1;#000000]
box[5,3.5;1,1;#000000]
box[4,4.5;1,1;#000000]
box[3,5.5;1,1;#000000]
box[5,5.5;1,1;#000000]
style_type[list;spacing=.25,.125;size=.75,.875]
list[current_player;main;3,3.5;3,3]
style_type[list;spacing=0;size=1.1]
list[current_player;main;.5,7;8,4]
]]
local hypertext_basic = [[ local hypertext_basic = [[
<bigger>Normal test</bigger> <bigger>Normal test</bigger>
This is a normal text. This is a normal text.
@ -199,6 +227,7 @@ local scroll_fs =
"box[1,1;8,6;#00aa]".. "box[1,1;8,6;#00aa]"..
"scroll_container[1,1;8,6;scrbar;vertical]".. "scroll_container[1,1;8,6;scrbar;vertical]"..
"button[0,1;1,1;lorem;Lorem]".. "button[0,1;1,1;lorem;Lorem]"..
"animated_image[0,1;4.5,1;clip_animated_image;testformspec_animation.png;4;100]" ..
"button[0,10;1,1;ipsum;Ipsum]".. "button[0,10;1,1;ipsum;Ipsum]"..
"pwdfield[2,2;1,1;lorem2;Lorem]".. "pwdfield[2,2;1,1;lorem2;Lorem]"..
"list[current_player;main;4,4;1,5;]".. "list[current_player;main;4,4;1,5;]"..
@ -211,6 +240,8 @@ local scroll_fs =
"tooltip[0,11;3,2;Buz;#f00;#000]".. "tooltip[0,11;3,2;Buz;#f00;#000]"..
"box[0,11;3,2;#00ff00]".. "box[0,11;3,2;#00ff00]"..
"hypertext[3,13;3,3;;" .. hypertext_basic .. "]" .. "hypertext[3,13;3,3;;" .. hypertext_basic .. "]" ..
"hypertext[3,17;3,3;;Hypertext with no scrollbar\\; the scroll container should scroll.]" ..
"textarea[3,21;3,1;textarea;;More scroll within scroll]" ..
"container[0,18]".. "container[0,18]"..
"box[1,2;3,2;#0a0a]".. "box[1,2;3,2;#0a0a]"..
"scroll_container[1,2;3,2;scrbar2;horizontal;0.06]".. "scroll_container[1,2;3,2;scrbar2;horizontal;0.06]"..
@ -310,6 +341,9 @@ local pages = {
"size[12,13]real_coordinates[true]" .. "size[12,13]real_coordinates[true]" ..
"container[0.5,1.5]" .. tabheaders_fs .. "container_end[]", "container[0.5,1.5]" .. tabheaders_fs .. "container_end[]",
-- Inv
"size[12,13]real_coordinates[true]" .. inv_style_fs,
-- Animation -- Animation
[[ [[
formspec_version[3] formspec_version[3]
@ -328,20 +362,51 @@ Number]
animated_image[5.5,0.5;5,2;;testformspec_animation.png;4;100] animated_image[5.5,0.5;5,2;;testformspec_animation.png;4;100]
animated_image[5.5,2.75;5,2;;testformspec_animation.jpg;4;100] animated_image[5.5,2.75;5,2;;testformspec_animation.jpg;4;100]
]],
-- Model
[[
formspec_version[3]
size[12,13]
style[m1;bgcolor=black] style[m1;bgcolor=black]
model[0.5,6;4,4;m1;testformspec_character.b3d;testformspec_character.png] style[m2;bgcolor=black]
model[5,6;4,4;m2;testformspec_chest.obj;default_chest_top.png,default_chest_top.png,default_chest_side.png,default_chest_side.png,default_chest_front.png,default_chest_inside.png;30,1;true;true] label[5,1;all defaults]
label[5,5.1;angle = 0, 180
continuous = false
mouse control = false
frame loop range = 0,30]
label[5,9.2;continuous = true
mouse control = true]
model[0.5,0.1;4,4;m1;testformspec_character.b3d;testformspec_character.png]
model[0.5,4.2;4,4;m2;testformspec_character.b3d;testformspec_character.png;0,180;false;false;0,30]
model[0.5,8.3;4,4;m3;testformspec_chest.obj;default_chest_top.png,default_chest_top.png,default_chest_side.png,default_chest_side.png,default_chest_front.png,default_chest_inside.png;30,1;true;true]
]], ]],
-- Scroll containers -- Scroll containers
"formspec_version[3]size[12,13]" .. "formspec_version[3]size[12,13]" ..
scroll_fs, scroll_fs,
-- Sound
[[
formspec_version[3]
size[12,13]
style[snd_btn;sound=soundstuff_mono]
style[snd_ibtn;sound=soundstuff_mono]
style[snd_drp;sound=soundstuff_mono]
style[snd_chk;sound=soundstuff_mono]
style[snd_tab;sound=soundstuff_mono]
button[0.5,0.5;2,1;snd_btn;Sound]
image_button[0.5,2;2,1;testformspec_item.png;snd_ibtn;Sound]
dropdown[0.5,4;4;snd_drp;Sound,Two,Three;]
checkbox[0.5,5.5.5;snd_chk;Sound;]
tabheader[0.5,7;8,0.65;snd_tab;Soundtab1,Soundtab2,Soundtab3;1;false;false]
]],
} }
local function show_test_formspec(pname, page_id) local function show_test_formspec(pname, page_id)
page_id = page_id or 2 page_id = page_id or 2
local fs = pages[page_id] .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Anim,ScrollC;" .. page_id .. ";false;false]" local fs = pages[page_id] .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Invs,Anim,Model,ScrollC,Sound;" .. page_id .. ";false;false]"
minetest.show_formspec(pname, "testformspec:formspec", fs) minetest.show_formspec(pname, "testformspec:formspec", fs)
end end

View File

@ -15,22 +15,6 @@ testing this node easier and more convenient.
local S = minetest.get_translator("testnodes") local S = minetest.get_translator("testnodes")
-- If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
-- This is due to <https://github.com/minetest/minetest/issues/9209>.
-- This is only added to make the items more visible to avoid confusion, but you will no longer see
-- the default inventory images for these items. When you want to test the default inventory image of drawtypes,
-- this should be turned off.
-- TODO: Remove support for fallback inventory image as soon #9209 is fixed.
local SHOW_FALLBACK_IMAGE = minetest.settings:get_bool("testnodes_show_fallback_image", false)
local fallback_image = function(img)
if SHOW_FALLBACK_IMAGE then
return img
else
return nil
end
end
-- A regular cube -- A regular cube
minetest.register_node("testnodes:normal", { minetest.register_node("testnodes:normal", {
description = S("Normal Drawtype Test Node"), description = S("Normal Drawtype Test Node"),
@ -145,20 +129,15 @@ minetest.register_node("testnodes:fencelike", {
}) })
minetest.register_node("testnodes:torchlike", { minetest.register_node("testnodes:torchlike", {
description = S("Torchlike Drawtype Test Node"), description = S("Floor Torchlike Drawtype Test Node"),
drawtype = "torchlike", drawtype = "torchlike",
paramtype = "light", paramtype = "light",
tiles = { tiles = { "testnodes_torchlike_floor.png^[colorize:#FF0000:64" },
"testnodes_torchlike_floor.png",
"testnodes_torchlike_ceiling.png",
"testnodes_torchlike_wall.png",
},
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
inventory_image = fallback_image("testnodes_torchlike_floor.png"),
}) })
minetest.register_node("testnodes:torchlike_wallmounted", { minetest.register_node("testnodes:torchlike_wallmounted", {
@ -176,12 +155,22 @@ minetest.register_node("testnodes:torchlike_wallmounted", {
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
inventory_image = fallback_image("testnodes_torchlike_floor.png"), })
minetest.register_node("testnodes:signlike", {
description = S("Floor Signlike Drawtype Test Node"),
drawtype = "signlike",
paramtype = "light",
tiles = { "testnodes_signlike.png^[colorize:#FF0000:64" },
walkable = false,
groups = { dig_immediate = 3 },
sunlight_propagates = true,
}) })
minetest.register_node("testnodes:signlike_wallmounted", {
minetest.register_node("testnodes:signlike", {
description = S("Wallmounted Signlike Drawtype Test Node"), description = S("Wallmounted Signlike Drawtype Test Node"),
drawtype = "signlike", drawtype = "signlike",
paramtype = "light", paramtype = "light",
@ -192,7 +181,6 @@ minetest.register_node("testnodes:signlike", {
walkable = false, walkable = false,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
sunlight_propagates = true, sunlight_propagates = true,
inventory_image = fallback_image("testnodes_signlike.png"),
}) })
minetest.register_node("testnodes:plantlike", { minetest.register_node("testnodes:plantlike", {
@ -223,6 +211,30 @@ minetest.register_node("testnodes:plantlike_waving", {
-- param2 will rotate -- param2 will rotate
local function rotate_on_rightclick(pos, node, clicker)
local def = minetest.registered_nodes[node.name]
local aux1 = clicker:get_player_control().aux1
local deg, deg_max
local color, color_mult = 0, 0
if def.paramtype2 == "degrotate" then
deg = node.param2
deg_max = 240
elseif def.paramtype2 == "colordegrotate" then
-- MSB [3x color, 5x rotation] LSB
deg = node.param2 % 2^5
deg_max = 24
color_mult = 2^5
color = math.floor(node.param2 / color_mult)
end
deg = (deg + (aux1 and 10 or 1)) % deg_max
node.param2 = color * color_mult + deg
minetest.swap_node(pos, node)
minetest.chat_send_player(clicker:get_player_name(),
"Rotation is now " .. deg .. " / " .. deg_max)
end
minetest.register_node("testnodes:plantlike_degrotate", { minetest.register_node("testnodes:plantlike_degrotate", {
description = S("Degrotate Plantlike Drawtype Test Node"), description = S("Degrotate Plantlike Drawtype Test Node"),
drawtype = "plantlike", drawtype = "plantlike",
@ -230,12 +242,43 @@ minetest.register_node("testnodes:plantlike_degrotate", {
paramtype2 = "degrotate", paramtype2 = "degrotate",
tiles = { "testnodes_plantlike_degrotate.png" }, tiles = { "testnodes_plantlike_degrotate.png" },
on_rightclick = rotate_on_rightclick,
place_param2 = 7,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
}) })
minetest.register_node("testnodes:mesh_degrotate", {
description = S("Degrotate Mesh Drawtype Test Node"),
drawtype = "mesh",
paramtype = "light",
paramtype2 = "degrotate",
mesh = "testnodes_ocorner.obj",
tiles = { "testnodes_mesh_stripes2.png" },
on_rightclick = rotate_on_rightclick,
place_param2 = 10, -- 15°
sunlight_propagates = true,
groups = { dig_immediate = 3 },
})
minetest.register_node("testnodes:mesh_colordegrotate", {
description = S("Color Degrotate Mesh Drawtype Test Node"),
drawtype = "mesh",
paramtype = "light",
paramtype2 = "colordegrotate",
palette = "testnodes_palette_facedir.png",
mesh = "testnodes_ocorner.obj",
tiles = { "testnodes_mesh_stripes3.png" },
on_rightclick = rotate_on_rightclick,
-- color index 1, 1 step (=15°) rotated
place_param2 = 1 * 2^5 + 1,
sunlight_propagates = true,
groups = { dig_immediate = 3 },
})
-- param2 will change height -- param2 will change height
minetest.register_node("testnodes:plantlike_leveled", { minetest.register_node("testnodes:plantlike_leveled", {
description = S("Leveled Plantlike Drawtype Test Node"), description = S("Leveled Plantlike Drawtype Test Node"),
@ -350,68 +393,72 @@ minetest.register_node("testnodes:plantlike_rooted_degrotate", {
}) })
-- Demonstrative liquid nodes, source and flowing form. -- Demonstrative liquid nodes, source and flowing form.
minetest.register_node("testnodes:liquid", { -- DRAWTYPE ONLY, NO LIQUID PHYSICS!
description = S("Source Liquid Drawtype Test Node"), -- Liquid ranges 0 to 8
drawtype = "liquid", for r = 0, 8 do
paramtype = "light", minetest.register_node("testnodes:liquid_"..r, {
tiles = { description = S("Source Liquid Drawtype Test Node, Range @1", r),
"testnodes_liquidsource.png", drawtype = "liquid",
}, paramtype = "light",
special_tiles = { tiles = {
{name="testnodes_liquidsource.png", backface_culling=false}, "testnodes_liquidsource_r"..r..".png^[colorize:#FFFFFF:100",
{name="testnodes_liquidsource.png", backface_culling=true}, },
}, special_tiles = {
use_texture_alpha = true, {name="testnodes_liquidsource_r"..r..".png^[colorize:#FFFFFF:100", backface_culling=false},
{name="testnodes_liquidsource_r"..r..".png^[colorize:#FFFFFF:100", backface_culling=true},
},
use_texture_alpha = "blend",
walkable = false, walkable = false,
liquidtype = "source", liquid_range = r,
liquid_range = 1, liquid_viscosity = 0,
liquid_viscosity = 0, liquid_alternative_flowing = "testnodes:liquid_flowing_"..r,
liquid_alternative_flowing = "testnodes:liquid_flowing", liquid_alternative_source = "testnodes:liquid_"..r,
liquid_alternative_source = "testnodes:liquid", groups = { dig_immediate = 3 },
groups = { dig_immediate = 3 }, })
}) minetest.register_node("testnodes:liquid_flowing_"..r, {
minetest.register_node("testnodes:liquid_flowing", { description = S("Flowing Liquid Drawtype Test Node, Range @1", r),
description = S("Flowing Liquid Drawtype Test Node"), drawtype = "flowingliquid",
drawtype = "flowingliquid", paramtype = "light",
paramtype = "light", paramtype2 = "flowingliquid",
paramtype2 = "flowingliquid", tiles = {
tiles = { "testnodes_liquidflowing_r"..r..".png^[colorize:#FFFFFF:100",
"testnodes_liquidflowing.png", },
}, special_tiles = {
special_tiles = { {name="testnodes_liquidflowing_r"..r..".png^[colorize:#FFFFFF:100", backface_culling=false},
{name="testnodes_liquidflowing.png", backface_culling=false}, {name="testnodes_liquidflowing_r"..r..".png^[colorize:#FFFFFF:100", backface_culling=false},
{name="testnodes_liquidflowing.png", backface_culling=false}, },
}, use_texture_alpha = "blend",
use_texture_alpha = true,
walkable = false, walkable = false,
liquidtype = "flowing", liquid_range = r,
liquid_range = 1, liquid_viscosity = 0,
liquid_viscosity = 0, liquid_alternative_flowing = "testnodes:liquid_flowing_"..r,
liquid_alternative_flowing = "testnodes:liquid_flowing", liquid_alternative_source = "testnodes:liquid_"..r,
liquid_alternative_source = "testnodes:liquid", groups = { dig_immediate = 3 },
groups = { dig_immediate = 3 }, })
})
end
-- Waving liquid test (drawtype only)
minetest.register_node("testnodes:liquid_waving", { minetest.register_node("testnodes:liquid_waving", {
description = S("Waving Source Liquid Drawtype Test Node"), description = S("Waving Source Liquid Drawtype Test Node"),
drawtype = "liquid", drawtype = "liquid",
paramtype = "light", paramtype = "light",
tiles = { tiles = {
"testnodes_liquidsource.png^[brighten", "testnodes_liquidsource.png^[colorize:#0000FF:127",
}, },
special_tiles = { special_tiles = {
{name="testnodes_liquidsource.png^[brighten", backface_culling=false}, {name="testnodes_liquidsource.png^[colorize:#0000FF:127", backface_culling=false},
{name="testnodes_liquidsource.png^[brighten", backface_culling=true}, {name="testnodes_liquidsource.png^[colorize:#0000FF:127", backface_culling=true},
}, },
use_texture_alpha = true, use_texture_alpha = "blend",
waving = 3, waving = 3,
walkable = false, walkable = false,
liquidtype = "source",
liquid_range = 1, liquid_range = 1,
liquid_viscosity = 0, liquid_viscosity = 0,
liquid_alternative_flowing = "testnodes:liquid_flowing_waving", liquid_alternative_flowing = "testnodes:liquid_flowing_waving",
@ -424,18 +471,17 @@ minetest.register_node("testnodes:liquid_flowing_waving", {
paramtype = "light", paramtype = "light",
paramtype2 = "flowingliquid", paramtype2 = "flowingliquid",
tiles = { tiles = {
"testnodes_liquidflowing.png^[brighten", "testnodes_liquidflowing.png^[colorize:#0000FF:127",
}, },
special_tiles = { special_tiles = {
{name="testnodes_liquidflowing.png^[brighten", backface_culling=false}, {name="testnodes_liquidflowing.png^[colorize:#0000FF:127", backface_culling=false},
{name="testnodes_liquidflowing.png^[brighten", backface_culling=false}, {name="testnodes_liquidflowing.png^[colorize:#0000FF:127", backface_culling=false},
}, },
use_texture_alpha = true, use_texture_alpha = "blend",
waving = 3, waving = 3,
walkable = false, walkable = false,
liquidtype = "flowing",
liquid_range = 1, liquid_range = 1,
liquid_viscosity = 0, liquid_viscosity = 0,
liquid_alternative_flowing = "testnodes:liquid_flowing_waving", liquid_alternative_flowing = "testnodes:liquid_flowing_waving",
@ -443,8 +489,6 @@ minetest.register_node("testnodes:liquid_flowing_waving", {
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
}) })
-- Invisible node -- Invisible node
minetest.register_node("testnodes:airlike", { minetest.register_node("testnodes:airlike", {
description = S("Airlike Drawtype Test Node"), description = S("Airlike Drawtype Test Node"),
@ -455,7 +499,6 @@ minetest.register_node("testnodes:airlike", {
walkable = false, walkable = false,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
sunlight_propagates = true, sunlight_propagates = true,
inventory_image = fallback_image("testnodes_airlike.png"),
}) })
-- param2 changes liquid height -- param2 changes liquid height
@ -548,7 +591,7 @@ scale("plantlike",
scale("torchlike_wallmounted", scale("torchlike_wallmounted",
S("Double-sized Wallmounted Torchlike Drawtype Test Node"), S("Double-sized Wallmounted Torchlike Drawtype Test Node"),
S("Half-sized Wallmounted Torchlike Drawtype Test Node")) S("Half-sized Wallmounted Torchlike Drawtype Test Node"))
scale("signlike", scale("signlike_wallmounted",
S("Double-sized Wallmounted Signlike Drawtype Test Node"), S("Double-sized Wallmounted Signlike Drawtype Test Node"),
S("Half-sized Wallmounted Signlike Drawtype Test Node")) S("Half-sized Wallmounted Signlike Drawtype Test Node"))
scale("firelike", scale("firelike",

Some files were not shown because too many files have changed in this diff Show More