aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml25
-rw-r--r--.gitlab-ci.yml131
-rw-r--r--CMakeLists.txt19
-rw-r--r--LICENSE.txt13
-rw-r--r--build/android/app/src/main/java/net/minetest/minetest/GameActivity.java4
-rw-r--r--builtin/common/misc_helpers.lua4
-rw-r--r--builtin/game/falling.lua40
-rw-r--r--builtin/mainmenu/dlg_contentstore.lua444
-rw-r--r--builtin/mainmenu/dlg_create_world.lua2
-rw-r--r--builtin/mainmenu/init.lua11
-rw-r--r--builtin/mainmenu/tab_credits.lua20
-rw-r--r--builtin/mainmenu/tab_local.lua1
-rw-r--r--builtin/mainmenu/tab_online.lua9
-rw-r--r--builtin/profiler/instrumentation.lua1
-rw-r--r--builtin/settingtypes.txt18
-rw-r--r--client/shaders/nodes_shader/opengl_fragment.glsl10
-rw-r--r--client/shaders/nodes_shader/opengl_vertex.glsl6
-rw-r--r--client/shaders/object_shader/opengl_fragment.glsl10
-rw-r--r--client/shaders/object_shader/opengl_vertex.glsl6
-rw-r--r--doc/lua_api.txt48
-rw-r--r--doc/menu_lua_api.txt9
-rw-r--r--games/devtest/mods/testentities/callbacks.lua3
-rw-r--r--games/devtest/mods/testentities/visuals.lua29
-rw-r--r--games/devtest/mods/testfood/init.lua7
-rw-r--r--games/devtest/mods/testfood/textures/testfood_replace.pngbin0 -> 135 bytes
-rw-r--r--lib/lua/CMakeLists.txt13
-rw-r--r--minetest.conf.example3
-rw-r--r--misc/debpkg-control4
-rw-r--r--src/CMakeLists.txt23
-rw-r--r--src/client/camera.cpp27
-rw-r--r--src/client/clientenvironment.cpp6
-rw-r--r--src/client/clientmap.cpp3
-rw-r--r--src/client/content_cao.cpp4
-rw-r--r--src/client/game.cpp53
-rw-r--r--src/client/game.h15
-rw-r--r--src/client/hud.cpp8
-rw-r--r--src/client/inputhandler.h2
-rw-r--r--src/client/joystick_controller.cpp50
-rw-r--r--src/client/joystick_controller.h38
-rw-r--r--src/client/mapblock_mesh.cpp4
-rw-r--r--src/client/minimap.cpp2
-rw-r--r--src/client/render/interlaced.cpp2
-rw-r--r--src/client/shader.cpp493
-rw-r--r--src/client/shader.h21
-rw-r--r--src/client/sky.cpp2
-rw-r--r--src/client/tile.cpp7
-rw-r--r--src/defaultsettings.cpp5
-rw-r--r--src/filesys.cpp22
-rw-r--r--src/gui/CMakeLists.txt1
-rw-r--r--src/gui/guiEditBox.cpp95
-rw-r--r--src/gui/guiEditBox.h103
-rw-r--r--src/gui/guiEditBoxWithScrollbar.cpp113
-rw-r--r--src/gui/guiEditBoxWithScrollbar.h66
-rw-r--r--src/gui/guiFormSpecMenu.cpp26
-rw-r--r--src/gui/guiScene.cpp9
-rw-r--r--src/gui/guiScene.h1
-rw-r--r--src/gui/intlGUIEditBox.cpp216
-rw-r--r--src/gui/intlGUIEditBox.h63
-rw-r--r--src/gui/touchscreengui.cpp3
-rw-r--r--src/irrlicht_changes/CGUITTFont.h2
-rw-r--r--src/irrlicht_changes/irrUString.h4
-rw-r--r--src/map.cpp8
-rw-r--r--src/map.h3
-rw-r--r--src/mapblock.cpp10
-rw-r--r--src/mapblock.h2
-rw-r--r--src/mapgen/mapgen_v7.cpp2
-rw-r--r--src/mapgen/mg_schematic.cpp4
-rw-r--r--src/mapgen/treegen.cpp3
-rw-r--r--src/mapnode.cpp34
-rw-r--r--src/mapnode.h4
-rw-r--r--src/network/networkprotocol.h17
-rw-r--r--src/network/serverpackethandler.cpp2
-rw-r--r--src/nodedef.cpp8
-rw-r--r--src/porting.cpp35
-rw-r--r--src/porting.h20
-rw-r--r--src/porting_android.cpp6
-rw-r--r--src/porting_android.h2
-rw-r--r--src/profiler.cpp2
-rw-r--r--src/script/cpp_api/s_entity.cpp26
-rw-r--r--src/script/cpp_api/s_entity.h1
-rw-r--r--src/script/cpp_api/s_security.cpp7
-rw-r--r--src/script/lua_api/l_env.cpp26
-rw-r--r--src/script/lua_api/l_env.h3
-rw-r--r--src/script/lua_api/l_mainmenu.cpp32
-rw-r--r--src/script/lua_api/l_mainmenu.h6
-rw-r--r--src/script/lua_api/l_object.cpp6
-rw-r--r--src/script/lua_api/l_util.cpp15
-rw-r--r--src/script/lua_api/l_util.h3
-rw-r--r--src/server.cpp4
-rw-r--r--src/server/activeobjectmgr.cpp15
-rw-r--r--src/server/activeobjectmgr.h3
-rw-r--r--src/server/luaentity_sao.cpp13
-rw-r--r--src/server/luaentity_sao.h5
-rw-r--r--src/server/player_sao.cpp2
-rw-r--r--src/server/serveractiveobject.cpp16
-rw-r--r--src/server/serveractiveobject.h50
-rw-r--r--src/serverenvironment.cpp12
-rw-r--r--src/serverenvironment.h7
-rw-r--r--src/util/srp.cpp4
-rw-r--r--src/util/string.cpp2
-rw-r--r--textures/base/pack/cdb_add.pngbin0 -> 147 bytes
-rw-r--r--textures/base/pack/cdb_clear.pngbin0 -> 182 bytes
-rw-r--r--textures/base/pack/cdb_downloading.pngbin0 -> 201 bytes
-rw-r--r--textures/base/pack/cdb_queued.pngbin0 -> 210 bytes
-rw-r--r--textures/base/pack/cdb_update.pngbin0 -> 173 bytes
-rw-r--r--textures/base/pack/cdb_viewonline.pngbin0 -> 191 bytes
-rw-r--r--textures/base/pack/clear.pngbin0 -> 708 bytes
-rw-r--r--textures/base/pack/search.pngbin0 -> 1908 bytes
-rw-r--r--util/ci/common.sh6
109 files changed, 1552 insertions, 1253 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 71fdf3652..a3cc92a8e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -33,9 +33,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install deps
run: |
- sudo apt-get install g++-6 gcc-6 -qyy
source ./util/ci/common.sh
- install_linux_deps
+ install_linux_deps g++-6
- name: Build
run: |
@@ -55,9 +54,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install deps
run: |
- sudo apt-get install g++-8 gcc-8 -qyy
source ./util/ci/common.sh
- install_linux_deps
+ install_linux_deps g++-8
- name: Build
run: |
@@ -77,9 +75,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install deps
run: |
- sudo apt-get install clang-3.9 -qyy
source ./util/ci/common.sh
- install_linux_deps
+ install_linux_deps clang-3.9
- name: Build
run: |
@@ -99,11 +96,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install deps
run: |
- sudo apt-get install clang-9 valgrind -qyy
source ./util/ci/common.sh
- install_linux_deps
- env:
- WITH_LUAJIT: 1
+ install_linux_deps clang-9 valgrind libluajit-5.1-dev
- name: Build
run: |
@@ -111,6 +105,7 @@ jobs:
env:
CC: clang-9
CXX: clang++-9
+ CMAKE_FLAGS: "-DREQUIRE_LUAJIT=1"
- name: Test
run: |
@@ -128,9 +123,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install deps
run: |
- sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh
- install_linux_deps
+ install_linux_deps clang-9
- name: Build prometheus-cpp
run: |
@@ -156,9 +150,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install deps
run: |
- sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh
- install_linux_deps
+ install_linux_deps clang-9
- name: Build
run: |
@@ -188,7 +181,7 @@ jobs:
- uses: actions/checkout@v2
- name: Install compiler
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
sudo tar -xaf mingw.tar.xz -C /usr
@@ -206,7 +199,7 @@ jobs:
- uses: actions/checkout@v2
- name: Install compiler
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
sudo tar -xaf mingw.tar.xz -C /usr
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c3e120375..0441aeaa1 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,12 +18,12 @@ variables:
- mkdir cmakebuild
- mkdir -p artifact/minetest/usr/
- cd cmakebuild
- - cmake -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE ..
+ - cmake -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DENABLE_SYSTEM_JSONCPP=TRUE -DBUILD_SERVER=TRUE ..
- make -j2
- make install
artifacts:
when: on_success
- expire_in: 2h
+ expire_in: 1h
paths:
- artifact/*
@@ -34,15 +34,14 @@ variables:
- apt-get install -y git
- mkdir -p build/deb/minetest/DEBIAN/
- 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:
- 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/LEVELDB_PLACEHOLDER/'$LEVELDB_PKG'/g' build/deb/minetest/DEBIAN/control
- cd build/deb/ && dpkg-deb -b minetest/ && mv minetest.deb ../../
artifacts:
- when: on_success
expire_in: 90 day
paths:
- ./*.deb
@@ -51,44 +50,14 @@ variables:
stage: deploy
before_script:
- apt-get update -y
- - 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:
- - dpkg -i ./*.deb
+ - apt-get install -y ./*.deb
+ - minetest --version
##
## 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
build:debian-9:
@@ -101,7 +70,7 @@ build:debian-9:
package:debian-9:
extends: .debpkg_template
image: debian:9
- dependencies:
+ needs:
- build:debian-9
variables:
LEVELDB_PKG: libleveldb1v5
@@ -109,12 +78,10 @@ package:debian-9:
deploy:debian-9:
extends: .debpkg_install
image: debian:9
- dependencies:
+ needs:
- package:debian-9
- variables:
- LEVELDB_PKG: libleveldb1v5
-# Stretch
+# Buster
build:debian-10:
extends: .build_template
@@ -126,7 +93,7 @@ build:debian-10:
package:debian-10:
extends: .debpkg_template
image: debian:10
- dependencies:
+ needs:
- build:debian-10
variables:
LEVELDB_PKG: libleveldb1d
@@ -134,10 +101,9 @@ package:debian-10:
deploy:debian-10:
extends: .debpkg_install
image: debian:10
- dependencies:
+ needs:
- package:debian-10
- variables:
- LEVELDB_PKG: libleveldb1d
+
##
## Ubuntu
##
@@ -154,7 +120,7 @@ build:ubuntu-16.04:
package:ubuntu-16.04:
extends: .debpkg_template
image: ubuntu:xenial
- dependencies:
+ needs:
- build:ubuntu-16.04
variables:
LEVELDB_PKG: libleveldb1v5
@@ -162,10 +128,8 @@ package:ubuntu-16.04:
deploy:ubuntu-16.04:
extends: .debpkg_install
image: ubuntu:xenial
- dependencies:
+ needs:
- package:ubuntu-16.04
- variables:
- LEVELDB_PKG: libleveldb1v5
# Bionic
@@ -179,7 +143,7 @@ build:ubuntu-18.04:
package:ubuntu-18.04:
extends: .debpkg_template
image: ubuntu:bionic
- dependencies:
+ needs:
- build:ubuntu-18.04
variables:
LEVELDB_PKG: libleveldb1v5
@@ -187,25 +151,22 @@ package:ubuntu-18.04:
deploy:ubuntu-18.04:
extends: .debpkg_install
image: ubuntu:bionic
- dependencies:
+ needs:
- package:ubuntu-18.04
- variables:
- LEVELDB_PKG: libleveldb1v5
##
## Fedora
##
-# Do we need to support this old version ?
-build:fedora-24:
+# Fedora 28 <-> RHEL 8
+build:fedora-28:
extends: .build_template
- image: fedora:24
+ image: fedora:28
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 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 gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel
##
-## Mingw for Windows
+## MinGW for Windows
##
.generic_win_template:
@@ -213,68 +174,63 @@ build:fedora-24:
before_script:
- apt-get update -y
- 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
.build_win_template:
extends: .generic_win_template
stage: build
artifacts:
- when: on_success
- expire_in: 2h
+ expire_in: 1h
paths:
- - build/*
+ - build/minetest/_build/*
.package_win_template:
extends: .generic_win_template
stage: package
script:
- - cd build/minetest/_build
- - make package
- - cd ../../../
- - mkdir minetest-win-${WIN_ARCH}
- - 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
+ - unzip build/minetest/_build/minetest-*.zip
+ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libgcc*.dll minetest-*-win*/bin/
+ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libstdc++*.dll minetest-*-win*/bin/
+ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libwinpthread*.dll minetest-*-win*/bin/
artifacts:
- when: on_success
expire_in: 90 day
paths:
- - minetest-win-*/*
+ - minetest-*-win*/*
build:win32:
extends: .build_win_template
script:
- ./util/buildbot/buildwin32.sh build
variables:
- NO_PACKAGE: "1"
WIN_ARCH: "i686"
package:win32:
extends: .package_win_template
- dependencies:
+ needs:
- build:win32
variables:
- NO_PACKAGE: "1"
WIN_ARCH: "i686"
+
build:win64:
extends: .build_win_template
script:
- ./util/buildbot/buildwin64.sh build
variables:
- NO_PACKAGE: "1"
WIN_ARCH: "x86_64"
package:win64:
extends: .package_win_template
- dependencies:
+ needs:
- build:win64
variables:
- NO_PACKAGE: "1"
WIN_ARCH: "x86_64"
+##
+## Docker
+##
+
package:docker:
stage: package
image: docker:stable
@@ -288,6 +244,10 @@ package:docker:
- docker push ${CONTAINER_IMAGE}/server:$CI_COMMIT_REF_NAME
- docker push ${CONTAINER_IMAGE}/server:latest
+##
+## Gitlab Pages (Lua API documentation)
+##
+
pages:
stage: deploy
image: python:3.8
@@ -303,10 +263,14 @@ pages:
only:
- master
+##
+## AppImage
+##
+
package:appimage-client:
stage: package
image: appimagecrafters/appimage-builder
- dependencies:
+ needs:
- build:ubuntu-18.04
before_script:
- apt-get update -y
@@ -315,16 +279,15 @@ package:appimage-client:
- mkdir AppDir
- cp -a artifact/minetest/usr/ AppDir/usr/
- rm AppDir/usr/bin/minetestserver
- - cp -R clientmods AppDir/usr/share/minetest
+ - cp -a clientmods AppDir/usr/share/minetest
script:
- 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
# Remove PrefersNonDefaultGPU property due to validation errors
- sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop
- appimage-builder --skip-test
artifacts:
- when: on_success
expire_in: 90 day
paths:
- ./*.AppImage
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 80fba3603..65ad47102 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,15 +1,9 @@
-cmake_minimum_required(VERSION 2.6)
-
-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()
+cmake_minimum_required(VERSION 3.5)
# This can be read from ${PROJECT_NAME} after project() is called
project(minetest)
set(PROJECT_NAME_CAPITALIZED "Dragonfire")
-# Works only for cmake 3.1 and greater
set(CMAKE_CXX_STANDARD 11)
set(GCC_MINIMUM_VERSION "4.8")
set(CLANG_MINIMUM_VERSION "3.4")
@@ -165,7 +159,7 @@ if(RUN_IN_PLACE)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/texture_packs_here.txt" DESTINATION "${SHAREDIR}/textures")
endif()
-install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game" DESTINATION "${SHAREDIR}/games/"
+install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game" DESTINATION "${SHAREDIR}/games/"
COMPONENT "SUBGAME_MINETEST_GAME" OPTIONAL PATTERN ".git*" EXCLUDE )
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/devtest" DESTINATION "${SHAREDIR}/games/"
COMPONENT "SUBGAME_MINIMAL" OPTIONAL PATTERN ".git*" EXCLUDE )
@@ -278,19 +272,20 @@ if(WIN32)
set(CPACK_GENERATOR ZIP)
else()
- set(CPACK_GENERATOR WIX ZIP)
+ set(CPACK_GENERATOR WIX)
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_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")
- # Supported languages can be found at
+ # Supported languages can be found at
# 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_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_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
diff --git a/LICENSE.txt b/LICENSE.txt
index f5c51833b..9b8ee851a 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -11,6 +11,9 @@ http://creativecommons.org/licenses/by-sa/3.0/
textures/base/pack/refresh.png is under the Apache 2 license
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/
+
Authors of media files
-----------------------
Everything not listed in here:
@@ -23,6 +26,8 @@ paramat:
textures/base/pack/menu_header.png
textures/base/pack/next_icon.png
textures/base/pack/prev_icon.png
+ textures/base/pack/clear.png
+ textures/base/pack/search.png
rubenwardy, paramat:
textures/base/pack/start_icon.png
@@ -45,6 +50,14 @@ srifqi
textures/base/pack/joystick_off.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
+
License of Minetest source code
-------------------------------
diff --git a/build/android/app/src/main/java/net/minetest/minetest/GameActivity.java b/build/android/app/src/main/java/net/minetest/minetest/GameActivity.java
index db126a2b9..38a388230 100644
--- a/build/android/app/src/main/java/net/minetest/minetest/GameActivity.java
+++ b/build/android/app/src/main/java/net/minetest/minetest/GameActivity.java
@@ -142,8 +142,8 @@ public class GameActivity extends NativeActivity {
return getResources().getDisplayMetrics().widthPixels;
}
- public void openURL(String url) {
- Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ public void openURI(String uri) {
+ Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(browserIntent);
}
}
diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua
index 0fbb8fba8..b86d68f5f 100644
--- a/builtin/common/misc_helpers.lua
+++ b/builtin/common/misc_helpers.lua
@@ -781,3 +781,7 @@ function core.privs_to_string(privs, delim)
end
return table.concat(list, delim)
end
+
+function core.is_nan(number)
+ return number ~= number
+end
diff --git a/builtin/game/falling.lua b/builtin/game/falling.lua
index f489ea702..057d0d0ed 100644
--- a/builtin/game/falling.lua
+++ b/builtin/game/falling.lua
@@ -152,8 +152,8 @@ core.register_entity(":__builtin:falling_node", {
else
self.object:set_yaw(-math.pi*0.25)
end
- elseif (node.param2 ~= 0 and (def.wield_image == ""
- or def.wield_image == nil))
+ elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
+ and (def.wield_image == "" or def.wield_image == nil))
or def.drawtype == "signlike"
or def.drawtype == "mesh"
or def.drawtype == "normal"
@@ -168,16 +168,30 @@ core.register_entity(":__builtin:falling_node", {
elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted") then
local rot = node.param2 % 8
local pitch, yaw, roll = 0, 0, 0
- 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
+ if def.drawtype == "nodebox" or def.drawtype == "mesh" then
+ if rot == 0 then
+ pitch, yaw = math.pi/2, 0
+ elseif rot == 1 then
+ pitch, yaw = -math.pi/2, math.pi
+ elseif rot == 2 then
+ pitch, yaw = 0, math.pi/2
+ elseif rot == 3 then
+ pitch, yaw = 0, -math.pi/2
+ 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
if def.drawtype == "signlike" then
pitch = pitch - math.pi/2
@@ -186,7 +200,7 @@ core.register_entity(":__builtin:falling_node", {
elseif rot == 1 then
yaw = yaw - math.pi/2
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
roll = roll + math.pi
else
diff --git a/builtin/mainmenu/dlg_contentstore.lua b/builtin/mainmenu/dlg_contentstore.lua
index b3616bfc8..32703a3b9 100644
--- a/builtin/mainmenu/dlg_contentstore.lua
+++ b/builtin/mainmenu/dlg_contentstore.lua
@@ -159,6 +159,331 @@ local function queue_download(package)
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] = minetest.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] = minetest.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 = minetest.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 parts = path:split(".")
return parts[#parts]
@@ -340,7 +665,6 @@ function store.get_formspec(dlgdata)
local W = 15.75
local H = 9.5
-
local formspec
if #store.packages_full > 0 then
formspec = {
@@ -348,12 +672,13 @@ function store.get_formspec(dlgdata)
"size[15.75,9.5]",
"position[0.5,0.55]",
- "style[status;border=false]",
+ "style[status,downloading,queued;border=false]",
"container[0.375,0.375]",
"field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]",
"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, "]",
"container_end[]",
@@ -374,7 +699,7 @@ function store.get_formspec(dlgdata)
}
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
formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue)
else
@@ -418,11 +743,17 @@ function store.get_formspec(dlgdata)
}
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
for i=start_idx, math.min(#store.packages, start_idx+num_per_page-1) do
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] = (i - start_idx) * 1.375 + (2*0.375 + 0.8)
+ formspec[#formspec + 1] = container_y
formspec[#formspec + 1] = "]"
-- image
@@ -438,52 +769,50 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "]"
-- 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] = W - 0.375*2
formspec[#formspec + 1] = ",0.1]"
if package.downloading then
- formspec[#formspec + 1] = "button[-3.5,0;2,0.8;status;"
- formspec[#formspec + 1] = fgettext("Downloading...")
- formspec[#formspec + 1] = "]"
+ formspec[#formspec + 1] = "animated_image[-1.7,-0.15;1,1;downloading;"
+ formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
+ formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
elseif package.queued then
- formspec[#formspec + 1] = "button[-3.5,0;2,0.8;status;"
- formspec[#formspec + 1] = fgettext("Queued")
- formspec[#formspec + 1] = "]"
+ formspec[#formspec + 1] = left_base
+ formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
+ formspec[#formspec + 1] = "cdb_queued.png;queued]"
elseif not package.path then
- formspec[#formspec + 1] = "button[-3,0;1.5,0.8;install_"
- formspec[#formspec + 1] = tostring(i)
- formspec[#formspec + 1] = ";"
- formspec[#formspec + 1] = fgettext("Install")
- formspec[#formspec + 1] = "]"
+ local elem_name = "install_" .. i .. ";"
+ formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]"
+ formspec[#formspec + 1] = left_base .. "cdb_add.png;" .. elem_name .. "]"
+ formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Install") .. tooltip_colors
else
if package.installed_release < package.release then
- description_width = description_width - 1.5
-- The install_ action also handles updating
- formspec[#formspec + 1] = "button[-4.5,0;1.5,0.8;install_"
- formspec[#formspec + 1] = tostring(i)
- formspec[#formspec + 1] = ";"
- formspec[#formspec + 1] = fgettext("Update")
- formspec[#formspec + 1] = "]"
- end
+ local elem_name = "install_" .. i .. ";"
+ formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#28ccdf]"
+ formspec[#formspec + 1] = left_base .. "cdb_update.png;" .. elem_name .. "]"
+ formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Update") .. tooltip_colors
+ else
- formspec[#formspec + 1] = "button[-3,0;1.5,0.8;uninstall_"
- formspec[#formspec + 1] = tostring(i)
- formspec[#formspec + 1] = ";"
- formspec[#formspec + 1] = fgettext("Uninstall")
- formspec[#formspec + 1] = "]"
+ local elem_name = "uninstall_" .. i .. ";"
+ formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#a93b3b]"
+ formspec[#formspec + 1] = left_base .. "cdb_clear.png;" .. elem_name .. "]"
+ formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Uninstall") .. tooltip_colors
+ end
end
- formspec[#formspec + 1] = "button[-1.5,0;1.5,0.8;view_"
- formspec[#formspec + 1] = tostring(i)
- formspec[#formspec + 1] = ";"
- formspec[#formspec + 1] = fgettext("View")
- formspec[#formspec + 1] = "]"
+ local web_elem_name = "view_" .. i .. ";"
+ formspec[#formspec + 1] = "image_button[-0.7,0;0.7,0.7;" ..
+ core.formspec_escape(defaulttexturedir) .. "cdb_viewonline.png;" .. web_elem_name .. "]"
+ formspec[#formspec + 1] = "tooltip[" .. web_elem_name ..
+ fgettext("View more information in a web browser") .. tooltip_colors
formspec[#formspec + 1] = "container_end[]"
-- description
+ local description_width = W - 0.375*5 - 0.85 - 2*0.7
formspec[#formspec + 1] = "textarea[1.855,0.3;"
formspec[#formspec + 1] = tostring(description_width)
formspec[#formspec + 1] = ",0.8;;;"
@@ -504,6 +833,13 @@ function store.handle_submit(this, fields)
return true
end
+ if fields.clear then
+ search_string = ""
+ cur_page = 1
+ store.filter_packages("")
+ return true
+ end
+
if fields.back then
this:delete()
return true
@@ -563,15 +899,47 @@ function store.handle_submit(this, fields)
assert(package)
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
end
if fields["uninstall_" .. i] then
- local dlg_delmod = create_delete_content_dlg(package)
- dlg_delmod:set_parent(this)
+ local dlg = create_delete_content_dlg(package)
+ dlg:set_parent(this)
this:hide()
- dlg_delmod:show()
+ dlg:show()
return true
end
diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
index 7566d2409..5931496c1 100644
--- a/builtin/mainmenu/dlg_create_world.lua
+++ b/builtin/mainmenu/dlg_create_world.lua
@@ -98,7 +98,7 @@ local function create_world_formspec(dialogdata)
-- Error out when no games found
if #pkgmgr.games == 0 then
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;;;"..
fgettext("You have no games installed.") .. "\n" ..
fgettext("Download one from minetest.net") .. "]" ..
diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua
index b7e867d2e..5c7e20932 100644
--- a/builtin/mainmenu/init.lua
+++ b/builtin/mainmenu/init.lua
@@ -19,6 +19,7 @@ mt_color_grey = "#AAAAAA"
mt_color_blue = "#6389FF"
mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191"
+mt_color_orange = "#FF8800"
local menupath = core.get_mainmenu_path()
local basepath = core.get_builtin_path()
@@ -105,6 +106,16 @@ local function init_globals()
if last_tab and tv_main.current_tab ~= last_tab then
tv_main:set_tab(last_tab)
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")
tv_main:show()
diff --git a/builtin/mainmenu/tab_credits.lua b/builtin/mainmenu/tab_credits.lua
index 617823319..036369914 100644
--- a/builtin/mainmenu/tab_credits.lua
+++ b/builtin/mainmenu/tab_credits.lua
@@ -109,9 +109,10 @@ return {
cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version()
- return "image[0.5,1;" .. core.formspec_escape(logofile) .. "]" ..
- "label[0.5,2.8;" .. version.project .. " " .. version.string .. "]" ..
- "button[0.5,3;2,2;homepage;minetest.net]" ..
+ local fs = "image[0.75,0.5;2.2,2.2;" .. core.formspec_escape(logofile) .. "]" ..
+ "style[label_button;border=false]" ..
+ "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]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[3.5,-0.25;8.5,6.05;list_credits;" ..
@@ -126,10 +127,23 @@ return {
"#FFFF00," .. fgettext("Previous Contributors") .. ",," ..
buildCreditList(previous_contributors) .. "," ..
";1]"
+
+ 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.75;3.5,1;userdata;" .. fgettext("Open User Data Directory") .. "]"
+ end
+
+ return fs
end,
cbf_button_handler = function(this, fields, name, tabdata)
if fields.homepage then
core.open_url("https://www.minetest.net")
end
+
+ if fields.userdata then
+ core.open_dir(core.get_user_path())
+ end
end,
}
diff --git a/builtin/mainmenu/tab_local.lua b/builtin/mainmenu/tab_local.lua
index 1aee246fc..2eb4752bc 100644
--- a/builtin/mainmenu/tab_local.lua
+++ b/builtin/mainmenu/tab_local.lua
@@ -18,6 +18,7 @@
local enable_gamebar = PLATFORM ~= "Android"
local current_game, singleplayer_refresh_gamebar
+
if enable_gamebar then
function current_game()
local last_game_id = core.settings:get("menu_last_game")
diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua
index 7985fd84a..8f1341161 100644
--- a/builtin/mainmenu/tab_online.lua
+++ b/builtin/mainmenu/tab_online.lua
@@ -34,7 +34,8 @@ local function get_formspec(tabview, name, tabdata)
local retval =
-- Search
"field[0.15,0.075;5.91,1;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
- "button[5.62,-0.25;1.5,1;btn_mp_search;" .. fgettext("Search") .. "]" ..
+ "image_button[5.63,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
+ "image_button[6.3,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" ..
"image_button[6.97,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "refresh.png")
.. ";btn_mp_refresh;]" ..
@@ -243,6 +244,12 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true
end
+ if fields.btn_mp_clear then
+ tabdata.search_for = ""
+ menudata.search_result = nil
+ return true
+ end
+
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
tabdata.fav_selected = 1
local input = fields.te_search:lower()
diff --git a/builtin/profiler/instrumentation.lua b/builtin/profiler/instrumentation.lua
index 237f048fb..6b951a2c2 100644
--- a/builtin/profiler/instrumentation.lua
+++ b/builtin/profiler/instrumentation.lua
@@ -160,6 +160,7 @@ local function init()
-- Simple iteration would ignore lookup via __index.
local entity_instrumentation = {
"on_activate",
+ "on_deactivate",
"on_step",
"on_punch",
"on_rightclick",
diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
index 9849d88bc..39a6f7231 100644
--- a/builtin/settingtypes.txt
+++ b/builtin/settingtypes.txt
@@ -152,6 +152,9 @@ joystick_type (Joystick type) enum auto auto,generic,xbox
# when holding down a joystick button combination.
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
# ingame view frustum around.
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170
@@ -1060,6 +1063,13 @@ full_block_send_enable_min_time_from_building (Delay in sending blocks after bui
# client number.
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]
# Default game when creating a new world.
@@ -1252,6 +1262,13 @@ max_objects_per_block (Maximum objects per block) int 64
# See https://www.sqlite.org/pragma.html#pragma_synchronous
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
# network.
dedicated_server_step (Dedicated server step) float 0.09
@@ -2200,6 +2217,7 @@ contentdb_url (ContentDB URL) string https://content.minetest.net
contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default
# 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
[Cheat Menu]
diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl
index b0f6d45d0..b58095063 100644
--- a/client/shaders/nodes_shader/opengl_fragment.glsl
+++ b/client/shaders/nodes_shader/opengl_fragment.glsl
@@ -16,13 +16,17 @@ varying vec3 vPosition;
// precision must be considered).
varying vec3 worldPosition;
varying lowp vec4 varColor;
-centroid varying mediump vec2 varTexCoord;
+#ifdef GL_ES
+varying mediump vec2 varTexCoord;
+#else
+centroid varying vec2 varTexCoord;
+#endif
varying vec3 eyeVec;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
-#ifdef ENABLE_TONE_MAPPING
+#if ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters
A = 0.22;
@@ -73,7 +77,7 @@ void main(void)
vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
-#ifdef ENABLE_TONE_MAPPING
+#if ENABLE_TONE_MAPPING
col = applyToneMapping(col);
#endif
diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl
index 5742ec1d3..c68df4a8e 100644
--- a/client/shaders/nodes_shader/opengl_vertex.glsl
+++ b/client/shaders/nodes_shader/opengl_vertex.glsl
@@ -19,7 +19,11 @@ 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.
-centroid varying mediump vec2 varTexCoord;
+#ifdef GL_ES
+varying mediump vec2 varTexCoord;
+#else
+centroid varying vec2 varTexCoord;
+#endif
varying vec3 eyeVec;
// Color of the light emitted by the light sources.
diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl
index bf18c1499..9a81d8185 100644
--- a/client/shaders/object_shader/opengl_fragment.glsl
+++ b/client/shaders/object_shader/opengl_fragment.glsl
@@ -9,7 +9,11 @@ varying vec3 vNormal;
varying vec3 vPosition;
varying vec3 worldPosition;
varying lowp vec4 varColor;
-centroid varying mediump vec2 varTexCoord;
+#ifdef GL_ES
+varying mediump vec2 varTexCoord;
+#else
+centroid varying vec2 varTexCoord;
+#endif
varying vec3 eyeVec;
varying float vIDiff;
@@ -19,7 +23,7 @@ const float BS = 10.0;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / (1.0 - fogStart);
-#ifdef ENABLE_TONE_MAPPING
+#if ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters
A = 0.22;
@@ -75,7 +79,7 @@ void main(void)
col.rgb *= emissiveColor.rgb * vIDiff;
-#ifdef ENABLE_TONE_MAPPING
+#if ENABLE_TONE_MAPPING
col = applyToneMapping(col);
#endif
diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl
index f31b842ee..b4a4d0aaa 100644
--- a/client/shaders/object_shader/opengl_vertex.glsl
+++ b/client/shaders/object_shader/opengl_vertex.glsl
@@ -7,7 +7,11 @@ varying vec3 vNormal;
varying vec3 vPosition;
varying vec3 worldPosition;
varying lowp vec4 varColor;
-centroid varying mediump vec2 varTexCoord;
+#ifdef GL_ES
+varying mediump vec2 varTexCoord;
+#else
+centroid varying vec2 varTexCoord;
+#endif
varying vec3 eyeVec;
varying float vIDiff;
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 2bb739bc8..754f0305a 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -2113,6 +2113,22 @@ Examples
list[current_player;main;0,3.5;8,4;]
list[current_player;craft;3,0;3,3;]
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
--------
@@ -2125,6 +2141,7 @@ Elements
* Clients older than this version can neither show newer elements nor display
elements with new arguments correctly.
* Available since feature `formspec_version_element`.
+* See also: [Version History]
### `size[<W>,<H>,<fixed_size>]`
@@ -2277,7 +2294,7 @@ Elements
* `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`.
-### `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>]`
* Show a mesh model.
* `name`: Element name that can be used for styling
@@ -2288,6 +2305,9 @@ Elements
The axes are euler angles in degrees.
* `continuous` (Optional): Whether the rotation is continuous. Default `false`.
* `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>`
### `item_image[<X>,<Y>;<W>,<H>;<item name>]`
@@ -2789,6 +2809,7 @@ Some types may inherit styles from parent types.
* image_button
* item_image_button
* label
+* model
* pwdfield, inherits from field
* scrollbar
* tabheader
@@ -4188,6 +4209,8 @@ Callbacks:
* Called when the object is instantiated.
* `dtime_s` is the time passed since the object was unloaded, which can be
used for updating the entity state.
+* `on_deactivate(self)
+ * Called when the object is about to get removed or unloaded.
* `on_step(self, dtime)`
* Called on every server tick, after movement and collision processing.
`dtime` is usually 0.1 seconds, as per the `dedicated_server_step` setting
@@ -4308,11 +4331,14 @@ Utilities
* `minetest.get_current_modname()`: returns the currently loading mod's name,
when loading a mod.
-* `minetest.get_modpath(modname)`: returns e.g.
- `"/home/user/.minetest/usermods/modname"`.
- * Useful for loading additional `.lua` modules or static data from mod
-* `minetest.get_modnames()`: returns a list of installed mods
- * Return a list of installed mods, sorted alphabetically
+* `minetest.get_modpath(modname)`: returns the directory path for a mod,
+ e.g. `"/home/user/.minetest/usermods/modname"`.
+ * Returns nil if the mod is not enabled or does not exist (not installed).
+ * Works regardless of whether the mod has been loaded yet.
+ * 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"`
* Useful for storing custom data
* `minetest.is_singleplayer()`
@@ -4872,6 +4898,9 @@ Environment access
* `minetest.get_objects_inside_radius(pos, radius)`: returns a list of
ObjectRefs.
* `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)`
* `val` is between `0` and `1`; `0` for midnight, `0.5` for midday
* `minetest.get_timeofday()`
@@ -7614,6 +7643,13 @@ Used by `minetest.register_node`.
-- intensity: 1.0 = mid range of regular TNT.
-- If defined, called when an explosion touches the node, instead of
-- 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
diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt
index 76bebe08b..1bcf697e9 100644
--- a/doc/menu_lua_api.txt
+++ b/doc/menu_lua_api.txt
@@ -43,10 +43,14 @@ core.get_max_supp_proto()
core.open_url(url)
^ opens the URL in a web browser, returns false on failure.
^ 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)
^ returns current core version
+
Filesystem
----------
@@ -63,6 +67,8 @@ core.copy_dir(source,destination,keep_soure) (possible in async calls)
^ destination folder
^ keep_source DEFAULT true --> if set to false source is deleted after copying
^ 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]
^ zipfile to extract
^ destination folder to extract to
@@ -207,6 +213,9 @@ Content and Packages
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.
+* 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)
* returns path to global modpath
* core.get_clientmodpath() (possible in async calls)
diff --git a/games/devtest/mods/testentities/callbacks.lua b/games/devtest/mods/testentities/callbacks.lua
index 711079f87..320690b39 100644
--- a/games/devtest/mods/testentities/callbacks.lua
+++ b/games/devtest/mods/testentities/callbacks.lua
@@ -31,6 +31,9 @@ minetest.register_entity("testentities:callback", {
on_activate = function(self, staticdata, dtime_s)
message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s)
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)
local name = get_object_name(puncher)
message(
diff --git a/games/devtest/mods/testentities/visuals.lua b/games/devtest/mods/testentities/visuals.lua
index 8848ba49f..e3b758329 100644
--- a/games/devtest/mods/testentities/visuals.lua
+++ b/games/devtest/mods/testentities/visuals.lua
@@ -94,3 +94,32 @@ minetest.register_entity("testentities:upright_animated", {
self.object:set_sprite({x=0, y=0}, 4, 1.0, false)
end,
})
+
+minetest.register_entity("testentities:nametag", {
+ initial_properties = {
+ visual = "sprite",
+ textures = { "testentities_sprite.png" },
+ },
+
+ on_activate = function(self, staticdata)
+ if staticdata ~= "" then
+ self.color = minetest.deserialize(staticdata).color
+ else
+ self.color = {
+ r = math.random(0, 255),
+ g = math.random(0, 255),
+ b = math.random(0, 255),
+ }
+ end
+
+ assert(self.color)
+ self.object:set_properties({
+ nametag = tostring(math.random(1000, 10000)),
+ nametag_color = self.color,
+ })
+ end,
+
+ get_staticdata = function(self)
+ return minetest.serialize({ color = self.color })
+ end,
+})
diff --git a/games/devtest/mods/testfood/init.lua b/games/devtest/mods/testfood/init.lua
index a6236ff68..39b121306 100644
--- a/games/devtest/mods/testfood/init.lua
+++ b/games/devtest/mods/testfood/init.lua
@@ -22,3 +22,10 @@ minetest.register_craftitem("testfood:bad5", {
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"),
+})
+
diff --git a/games/devtest/mods/testfood/textures/testfood_replace.png b/games/devtest/mods/testfood/textures/testfood_replace.png
new file mode 100644
index 000000000..1ef6876e5
--- /dev/null
+++ b/games/devtest/mods/testfood/textures/testfood_replace.png
Binary files differ
diff --git a/lib/lua/CMakeLists.txt b/lib/lua/CMakeLists.txt
index 119dd6302..5d0dc0f70 100644
--- a/lib/lua/CMakeLists.txt
+++ b/lib/lua/CMakeLists.txt
@@ -1,5 +1,3 @@
-cmake_minimum_required(VERSION 2.4 FATAL_ERROR)
-
project(lua C)
set(LUA_VERSION_MAJOR 5)
@@ -15,9 +13,8 @@ set(LIBS)
if(APPLE)
set(DEFAULT_POSIX TRUE)
- set(DEFAULT_DLOPEN ON)
- # use this on Mac OS X 10.3-
- option(LUA_USE_MACOSX "Mac OS X 10.3-" OFF)
+ set(DEFAULT_DLOPEN OFF)
+ set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_USE_MACOSX")
elseif(UNIX OR CYGWIN)
set(DEFAULT_POSIX TRUE)
elseif(WIN32)
@@ -32,12 +29,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(DEFAULT_DLOPEN ON)
endif()
-# For "Mac OS X 10.3-"
-if(LUA_USE_MACOSX)
- set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_USE_MACOSX")
- set(LUA_USE_DLOPEN FALSE)
-endif(LUA_USE_MACOSX)
-
option(LUA_USE_DLOPEN "Enable dlopen support." ${DEFAULT_DLOPEN})
mark_as_advanced(LUA_USE_DLOPEN)
diff --git a/minetest.conf.example b/minetest.conf.example
index 6b315b6ea..086339037 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -129,6 +129,9 @@
# type: float min: 0.001
# repeat_joystick_button_time = 0.17
+# The deadzone of the joystick
+# joystick_deadzone = 2048
+
# The sensitivity of the joystick axes for moving the
# ingame view frustum around.
# type: float
diff --git a/misc/debpkg-control b/misc/debpkg-control
index b228f4c79..30dc94088 100644
--- a/misc/debpkg-control
+++ b/misc/debpkg-control
@@ -3,9 +3,9 @@ Priority: extra
Standards-Version: 3.6.2
Package: minetest-staging
Version: 0.4.15-DATEPLACEHOLDER
-Depends: libc6, libcurl3-gnutls, libfreetype6, libirrlicht1.8, LEVELDB_PLACEHOLDER, liblua5.1-0, libluajit-5.1-2, libopenal1, libstdc++6, libvorbisfile3, libx11-6, zlib1g
+Depends: libc6, libcurl3-gnutls, libfreetype6, libirrlicht1.8, libjsoncpp1, LEVELDB_PLACEHOLDER, liblua5.1-0, libluajit-5.1-2, libopenal1, libsqlite3-0, libstdc++6, libvorbisfile3, libx11-6, zlib1g
Maintainer: Loic Blot <loic.blot@unix-experience.fr>
-Homepage: http://minetest.net/
+Homepage: https://www.minetest.net/
Vcs-Git: https://github.com/minetest/minetest.git
Vcs-Browser: https://github.com/minetest/minetest.git
Architecture: amd64
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b8ce69f1d..b6bba6e8d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,3 @@
-cmake_minimum_required(VERSION 2.6)
-
project(minetest)
INCLUDE(CheckIncludeFiles)
@@ -124,27 +122,6 @@ option(ENABLE_FREETYPE "Enable FreeType2 (TrueType fonts and basic unicode suppo
set(USE_FREETYPE FALSE)
if(ENABLE_FREETYPE)
-##
-## Note: FindFreetype.cmake seems to have been fixed in recent versions of
-## CMake. If issues persist, re-enable this workaround specificially for the
-## failing platforms.
-##
-# if(UNIX)
-# include(FindPkgConfig)
-# if(PKG_CONFIG_FOUND)
-# pkg_check_modules(FREETYPE QUIET freetype2)
-# if(FREETYPE_FOUND)
-# SET(FREETYPE_PKGCONFIG_FOUND TRUE)
-# SET(FREETYPE_LIBRARY ${FREETYPE_LIBRARIES})
-# # Because CMake is idiotic
-# string(REPLACE ";" " " FREETYPE_CFLAGS_STR ${FREETYPE_CFLAGS})
-# string(REPLACE ";" " " FREETYPE_LDFLAGS_STR ${FREETYPE_LDFLAGS})
-# endif(FREETYPE_FOUND)
-# endif(PKG_CONFIG_FOUND)
-# endif(UNIX)
-# if(NOT FREETYPE_FOUND)
-# find_package(Freetype)
-# endif()
find_package(Freetype)
if(FREETYPE_FOUND)
message(STATUS "Freetype enabled.")
diff --git a/src/client/camera.cpp b/src/client/camera.cpp
index 53c0b351c..91d319c90 100644
--- a/src/client/camera.cpp
+++ b/src/client/camera.cpp
@@ -691,10 +691,11 @@ void Camera::drawNametags()
core::matrix4 trans = m_cameranode->getProjectionMatrix();
trans *= m_cameranode->getViewMatrix();
- for (std::list<Nametag *>::const_iterator
- i = m_nametags.begin();
- i != m_nametags.end(); ++i) {
- Nametag *nametag = *i;
+ gui::IGUIFont *font = g_fontengine->getFont();
+ video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ v2u32 screensize = driver->getScreenSize();
+
+ for (const Nametag *nametag : m_nametags) {
if (nametag->nametag_color.getAlpha() == 0) {
// Enforce hiding nametag,
// because if freetype is enabled, a grey
@@ -707,21 +708,29 @@ void Camera::drawNametags()
if (transformed_pos[3] > 0) {
std::wstring nametag_colorless =
unescape_translate(utf8_to_wide(nametag->nametag_text));
- core::dimension2d<u32> textsize =
- g_fontengine->getFont()->getDimension(
+ core::dimension2d<u32> textsize = font->getDimension(
nametag_colorless.c_str());
f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
core::reciprocal(transformed_pos[3]);
- v2u32 screensize = RenderingEngine::get_video_driver()->getScreenSize();
v2s32 screen_pos;
screen_pos.X = screensize.X *
(0.5 * transformed_pos[0] * zDiv + 0.5) - textsize.Width / 2;
screen_pos.Y = screensize.Y *
(0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2;
core::rect<s32> size(0, 0, textsize.Width, textsize.Height);
- g_fontengine->getFont()->draw(
+ core::rect<s32> bg_size(-2, 0, textsize.Width+2, textsize.Height);
+
+ video::SColor textColor = nametag->nametag_color;
+
+ bool darkBackground = textColor.getLuminance() > 186;
+ video::SColor backgroundColor = darkBackground
+ ? video::SColor(50, 50, 50, 50)
+ : video::SColor(50, 255, 255, 255);
+ driver->draw2DRectangle(backgroundColor, bg_size + screen_pos);
+
+ font->draw(
translate_string(utf8_to_wide(nametag->nametag_text)).c_str(),
- size + screen_pos, nametag->nametag_color);
+ size + screen_pos, textColor);
}
}
}
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index d480c5056..5f44c30ac 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -51,12 +51,8 @@ public:
~CAOShaderConstantSetter() override = default;
- void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel) override
+ void onSetConstants(video::IMaterialRendererServices *services) override
{
- if (!is_highlevel)
- return;
-
// Ambient color
video::SColorf emissive_color(m_emissive_color);
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index 293271b80..68fd41e39 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -290,6 +290,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
*/
u32 vertex_count = 0;
+ u32 drawcall_count = 0;
// For limiting number of mesh animations per frame
u32 mesh_animate_count = 0;
@@ -391,6 +392,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
}
driver->setMaterial(list.m);
+ drawcall_count += list.bufs.size();
for (auto &pair : list.bufs) {
scene::IMeshBuffer *buf = pair.second;
@@ -411,6 +413,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
}
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
+ g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
}
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index a5db49cd2..c44c167b5 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -1173,7 +1173,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
}
}
- if (!getParent() && std::fabs(m_prop.automatic_rotate) > 0.001) {
+ if (!getParent() && node && fabs(m_prop.automatic_rotate) > 0.001f) {
// This is the child node's rotation. It is only used for automatic_rotate.
v3f local_rot = node->getRotation();
local_rot.Y = modulo360f(local_rot.Y - dtime * core::RADTODEG *
@@ -1182,7 +1182,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
}
if (!getParent() && m_prop.automatic_face_movement_dir &&
- (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) {
+ (fabs(m_velocity.Z) > 0.001f || fabs(m_velocity.X) > 0.001f)) {
float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI
+ m_prop.automatic_face_movement_dir_offset;
float max_rotation_per_sec =
diff --git a/src/client/game.cpp b/src/client/game.cpp
index 816f8f307..10c3a7ceb 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -118,7 +118,7 @@ Game::Game() :
&updateAllMapBlocksCallback, this);
g_settings->registerChangedCallback("node_esp_nodes",
&updateAllMapBlocksCallback, this);
-
+
readSettings();
#ifdef __ANDROID__
@@ -244,7 +244,7 @@ void Game::run()
RunStats stats = { 0 };
FpsControl draw_times = { 0 };
f32 dtime; // in seconds
-
+
/* Clear the profiler */
Profiler::GraphValues dummyvalues;
g_profiler->graphGet(dummyvalues);
@@ -519,7 +519,7 @@ bool Game::createClient(const GameStartData &start_data)
return false;
}
- GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory(
+ auto *scsf = new GameGlobalShaderConstantSetterFactory(
&m_flags.force_fog_off, &runData.fog_range, client);
shader_src->addShaderConstantSetterFactory(scsf);
@@ -529,20 +529,14 @@ bool Game::createClient(const GameStartData &start_data)
/* Camera
*/
camera = new Camera(*draw_control, client);
- if (!camera || !camera->successfullyCreated(*error_message))
+ if (!camera->successfullyCreated(*error_message))
return false;
client->setCamera(camera);
/* Clouds
*/
- if (m_cache_enable_clouds) {
+ if (m_cache_enable_clouds)
clouds = new Clouds(smgr, -1, time(0));
- if (!clouds) {
- *error_message = "Memory allocation error (clouds)";
- errorstream << *error_message << std::endl;
- return false;
- }
- }
/* Skybox
*/
@@ -550,12 +544,6 @@ bool Game::createClient(const GameStartData &start_data)
scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop
- if (!sky) {
- *error_message = "Memory allocation error sky";
- errorstream << *error_message << std::endl;
- return false;
- }
-
/* Pre-calculated values
*/
video::ITexture *t = texture_src->getTexture("crack_anylength.png");
@@ -585,12 +573,6 @@ bool Game::createClient(const GameStartData &start_data)
hud = new Hud(guienv, client, player, &player->inventory);
- if (!hud) {
- *error_message = "Memory error: could not create HUD";
- errorstream << *error_message << std::endl;
- return false;
- }
-
mapper = client->getMinimap();
if (mapper && client->modsLoaded())
@@ -618,7 +600,7 @@ bool Game::initGui()
errorstream << *error_message << std::endl;
return false;
}
-
+
m_cheat_menu = new CheatMenu(client);
if (!m_cheat_menu) {
@@ -682,9 +664,6 @@ bool Game::connectToServer(const GameStartData &start_data,
itemdef_manager, nodedef_manager, sound, eventmgr,
connect_address.isIPv6(), m_game_ui.get());
- if (!client)
- return false;
-
client->m_simple_singleplayer_mode = simple_singleplayer_mode;
infostream << "Connecting to server at ";
@@ -1079,7 +1058,7 @@ void Game::processKeyInput()
} else if (wasKeyDown(KeyType::SELECT_CONFIRM)) {
m_cheat_menu->selectConfirm();
}
-
+
if (wasKeyDown(KeyType::DROP)) {
dropSelectedItem(isKeyDown(KeyType::SNEAK));
} else if (wasKeyDown(KeyType::AUTOFORWARD)) {
@@ -1875,7 +1854,7 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
}
void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam)
-{
+{
if (event->show_formspec.formspec->empty()) {
auto formspec = m_game_ui->getFormspecGUI();
if (formspec && (event->show_formspec.formname->empty()
@@ -1889,7 +1868,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend(), sound);
}
-
+
delete event->show_formspec.formspec;
delete event->show_formspec.formname;
}
@@ -2230,7 +2209,7 @@ void Game::updatePlayerCAOVisibility()
return;
playercao->updateMeshCulling();
bool is_visible = camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam");
- playercao->setChildrenVisible(is_visible);
+ playercao->setChildrenVisible(is_visible);
}
void Game::updateSound(f32 dtime)
@@ -2287,8 +2266,8 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
-
-
+
+
if (g_settings->getBool("reach"))
d += g_settings->getU16("tool_range");
@@ -2415,8 +2394,8 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
wasKeyDown(KeyType::DIG);
wasKeyDown(KeyType::PLACE);
- input->joystick.clearWasKeyDown(KeyType::DIG);
- input->joystick.clearWasKeyDown(KeyType::PLACE);
+ input->joystick.clearWasKeyPressed(KeyType::DIG);
+ input->joystick.clearWasKeyPressed(KeyType::PLACE);
input->joystick.clearWasKeyReleased(KeyType::DIG);
input->joystick.clearWasKeyReleased(KeyType::PLACE);
@@ -2862,7 +2841,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
player, nodepos, n, features);
}
}
-
+
if(g_settings->getBool("instant_break")) {
runData.dig_time_complete = 0;
runData.dig_instantly = true;
@@ -3603,7 +3582,7 @@ void the_game(bool *kill,
bool *reconnect_requested) // Used for local game
{
Game game;
-
+
g_game = &game;
/* Make a copy of the server address because if a local singleplayer server
diff --git a/src/client/game.h b/src/client/game.h
index 3e80b15e7..fd93ef82d 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -203,7 +203,7 @@ struct LocalFormspecHandler : public TextDest
return;
}
- if (m_client && m_client->modsLoaded())
+ if (m_client->modsLoaded())
m_client->getScript()->on_formspec_input(m_formname, fields);
}
@@ -492,12 +492,8 @@ public:
g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
}
- virtual void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel)
+ void onSetConstants(video::IMaterialRendererServices *services) override
{
- if (!is_highlevel)
- return;
-
// Background color
video::SColor bgcolor = m_sky->getBgColor();
video::SColorf bgcolorf(bgcolor);
@@ -604,7 +600,7 @@ public:
virtual IShaderConstantSetter* create()
{
- GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter(
+ auto *scs = new GameGlobalShaderConstantSetter(
m_sky, m_force_fog_off, m_fog_range, m_client);
if (!m_sky)
created_nosky.push_back(scs);
@@ -643,7 +639,6 @@ struct GameRunData {
bool btn_down_for_dig;
bool dig_instantly;
bool digging_blocked;
- bool left_punch;
bool reset_jump_timer;
float nodig_delay_timer;
float dig_time;
@@ -852,10 +847,10 @@ public:
ISoundManager *sound = nullptr;
bool sound_is_dummy = false;
SoundMaker *soundmaker = nullptr;
-
+
ChatBackend *chat_backend = nullptr;
LogOutputBuffer m_chat_log_buf;
-
+
EventManager *eventmgr = nullptr;
QuicktuneShortcutter *quicktune = nullptr;
bool registration_confirmation_shown = false;
diff --git a/src/client/hud.cpp b/src/client/hud.cpp
index f6497fe25..e956c2738 100644
--- a/src/client/hud.cpp
+++ b/src/client/hud.cpp
@@ -100,7 +100,7 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
if (g_settings->getBool("enable_shaders")) {
IShaderSource *shdrsrc = client->getShaderSource();
u16 shader_id = shdrsrc->getShader(
- m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1);
+ m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", TILE_MATERIAL_ALPHA);
m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
} else {
m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -1055,9 +1055,9 @@ void drawItemStack(
if (def.type == ITEM_TOOL && item.wear != 0) {
// Draw a progressbar
- float barheight = rect.getHeight() / 16;
- float barpad_x = rect.getWidth() / 16;
- float barpad_y = rect.getHeight() / 16;
+ float barheight = static_cast<float>(rect.getHeight()) / 16;
+ float barpad_x = static_cast<float>(rect.getWidth()) / 16;
+ float barpad_y = static_cast<float>(rect.getHeight()) / 16;
core::rect<s32> progressrect(
rect.UpperLeftCorner.X + barpad_x,
diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h
index 365263b39..766cd5266 100644
--- a/src/client/inputhandler.h
+++ b/src/client/inputhandler.h
@@ -290,7 +290,7 @@ public:
}
virtual bool wasKeyPressed(GameKeyType k)
{
- return m_receiver->WasKeyPressed(keycache.key[k]) || joystick.wasKeyReleased(k);
+ return m_receiver->WasKeyPressed(keycache.key[k]) || joystick.wasKeyPressed(k);
}
virtual bool wasKeyReleased(GameKeyType k)
{
diff --git a/src/client/joystick_controller.cpp b/src/client/joystick_controller.cpp
index 742115046..f61ae4ae6 100644
--- a/src/client/joystick_controller.cpp
+++ b/src/client/joystick_controller.cpp
@@ -37,7 +37,7 @@ bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
{
s16 ax_val = ev.Axis[axis_to_compare];
- return (ax_val * direction < 0) && (thresh * direction > ax_val * direction);
+ return (ax_val * direction < -thresh);
}
// spares many characters
@@ -48,7 +48,7 @@ JoystickLayout create_default_layout()
{
JoystickLayout jlo;
- jlo.axes_dead_border = 1024;
+ jlo.axes_deadzone = g_settings->getU16("joystick_deadzone");
const JoystickAxisLayout axes[JA_COUNT] = {
{0, 1}, // JA_SIDEWARD_MOVE
@@ -93,14 +93,14 @@ JoystickLayout create_default_layout()
// Now about the buttons simulated by the axes
// Movement buttons, important for vessels
- JLO_A_PB(KeyType::FORWARD, 1, 1, 1024);
- JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024);
- JLO_A_PB(KeyType::LEFT, 0, 1, 1024);
- JLO_A_PB(KeyType::RIGHT, 0, -1, 1024);
+ JLO_A_PB(KeyType::FORWARD, 1, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::BACKWARD, 1, -1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::LEFT, 0, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::RIGHT, 0, -1, jlo.axes_deadzone);
// Scroll buttons
- JLO_A_PB(KeyType::HOTBAR_PREV, 2, -1, 1024);
- JLO_A_PB(KeyType::HOTBAR_NEXT, 5, -1, 1024);
+ JLO_A_PB(KeyType::HOTBAR_PREV, 2, -1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::HOTBAR_NEXT, 5, -1, jlo.axes_deadzone);
return jlo;
}
@@ -109,7 +109,7 @@ JoystickLayout create_xbox_layout()
{
JoystickLayout jlo;
- jlo.axes_dead_border = 7000;
+ jlo.axes_deadzone = 7000;
const JoystickAxisLayout axes[JA_COUNT] = {
{0, 1}, // JA_SIDEWARD_MOVE
@@ -146,10 +146,10 @@ JoystickLayout create_xbox_layout()
JLO_B_PB(KeyType::FREEMOVE, 1 << 16, 1 << 16); // down
// Movement buttons, important for vessels
- JLO_A_PB(KeyType::FORWARD, 1, 1, 1024);
- JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024);
- JLO_A_PB(KeyType::LEFT, 0, 1, 1024);
- JLO_A_PB(KeyType::RIGHT, 0, -1, 1024);
+ JLO_A_PB(KeyType::FORWARD, 1, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::BACKWARD, 1, -1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::LEFT, 0, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::RIGHT, 0, -1, jlo.axes_deadzone);
return jlo;
}
@@ -219,16 +219,19 @@ bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
if (keys_pressed[i]) {
- if (!m_past_pressed_keys[i] &&
+ if (!m_past_keys_pressed[i] &&
m_past_pressed_time[i] < m_internal_time - doubling_dtime) {
- m_past_pressed_keys[i] = true;
+ m_past_keys_pressed[i] = true;
m_past_pressed_time[i] = m_internal_time;
}
- } else if (m_pressed_keys[i]) {
- m_past_released_keys[i] = true;
+ } else if (m_keys_down[i]) {
+ m_keys_released[i] = true;
}
- m_pressed_keys[i] = keys_pressed[i];
+ if (keys_pressed[i] && !(m_keys_down[i]))
+ m_keys_pressed[i] = true;
+
+ m_keys_down[i] = keys_pressed[i];
}
for (size_t i = 0; i < JA_COUNT; i++) {
@@ -236,23 +239,22 @@ bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
}
-
return true;
}
void JoystickController::clear()
{
- m_pressed_keys.reset();
- m_past_pressed_keys.reset();
- m_past_released_keys.reset();
+ m_keys_pressed.reset();
+ m_keys_down.reset();
+ m_past_keys_pressed.reset();
+ m_keys_released.reset();
memset(m_axes_vals, 0, sizeof(m_axes_vals));
}
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
{
s16 v = m_axes_vals[axis];
- if (((v > 0) && (v < m_layout.axes_dead_border)) ||
- ((v < 0) && (v > -m_layout.axes_dead_border)))
+ if (abs(v) < m_layout.axes_deadzone)
return 0;
return v;
}
diff --git a/src/client/joystick_controller.h b/src/client/joystick_controller.h
index 7baacd81b..3f361e4ef 100644
--- a/src/client/joystick_controller.h
+++ b/src/client/joystick_controller.h
@@ -96,7 +96,7 @@ struct JoystickLayout {
std::vector<JoystickButtonCmb> button_keys;
std::vector<JoystickAxisCmb> axis_keys;
JoystickAxisLayout axes[JA_COUNT];
- s16 axes_dead_border;
+ s16 axes_deadzone;
};
class JoystickController {
@@ -111,37 +111,32 @@ public:
bool wasKeyDown(GameKeyType b)
{
- bool r = m_past_pressed_keys[b];
- m_past_pressed_keys[b] = false;
+ bool r = m_past_keys_pressed[b];
+ m_past_keys_pressed[b] = false;
return r;
}
- bool getWasKeyDown(GameKeyType b)
+
+ bool wasKeyReleased(GameKeyType b)
{
- return m_past_pressed_keys[b];
+ return m_keys_released[b];
}
- void clearWasKeyDown(GameKeyType b)
+ void clearWasKeyReleased(GameKeyType b)
{
- m_past_pressed_keys[b] = false;
+ m_keys_released[b] = false;
}
- bool wasKeyReleased(GameKeyType b)
+ bool wasKeyPressed(GameKeyType b)
{
- bool r = m_past_released_keys[b];
- m_past_released_keys[b] = false;
- return r;
- }
- bool getWasKeyReleased(GameKeyType b)
- {
- return m_past_pressed_keys[b];
+ return m_keys_pressed[b];
}
- void clearWasKeyReleased(GameKeyType b)
+ void clearWasKeyPressed(GameKeyType b)
{
- m_past_pressed_keys[b] = false;
+ m_keys_pressed[b] = false;
}
bool isKeyDown(GameKeyType b)
{
- return m_pressed_keys[b];
+ return m_keys_down[b];
}
s16 getAxis(JoystickAxis axis)
@@ -162,12 +157,13 @@ private:
u8 m_joystick_id = 0;
- std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_pressed_keys;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_down;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_pressed;
f32 m_internal_time;
f32 m_past_pressed_time[KeyType::INTERNAL_ENUM_COUNT];
- std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_pressed_keys;
- std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_released_keys;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_keys_pressed;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_released;
};
diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp
index bdd4f784a..b7c5ea16a 100644
--- a/src/client/mapblock_mesh.cpp
+++ b/src/client/mapblock_mesh.cpp
@@ -1269,13 +1269,13 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
MapBlockMesh::~MapBlockMesh()
{
for (scene::IMesh *m : m_mesh) {
- if (m_enable_vbo && m)
+ if (m_enable_vbo) {
for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
scene::IMeshBuffer *buf = m->getMeshBuffer(i);
RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
}
+ }
m->drop();
- m = NULL;
}
delete m_minimap_mapblock;
}
diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp
index f809821c3..187428273 100644
--- a/src/client/minimap.cpp
+++ b/src/client/minimap.cpp
@@ -612,7 +612,7 @@ void Minimap::drawMinimap(core::rect<s32> rect) {
material.TextureLayer[1].Texture = data->heightmap_texture;
if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) {
- u16 sid = m_shdrsrc->getShader("minimap_shader", 1, 1);
+ u16 sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA);
material.MaterialType = m_shdrsrc->getShaderInfo(sid).material;
} else {
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
diff --git a/src/client/render/interlaced.cpp b/src/client/render/interlaced.cpp
index 2aadadc17..ce8e92f21 100644
--- a/src/client/render/interlaced.cpp
+++ b/src/client/render/interlaced.cpp
@@ -36,7 +36,7 @@ void RenderingCoreInterlaced::initMaterial()
mat.UseMipMaps = false;
mat.ZBuffer = false;
mat.ZWriteEnable = false;
- u32 shader = s->getShader("3d_interlaced_merge", TILE_MATERIAL_BASIC, 0);
+ u32 shader = s->getShader("3d_interlaced_merge", TILE_MATERIAL_BASIC);
mat.MaterialType = s->getShaderInfo(shader).material;
for (int k = 0; k < 3; ++k) {
mat.TextureLayer[k].AnisotropicFilter = false;
diff --git a/src/client/shader.cpp b/src/client/shader.cpp
index 1cec20d2c..b3e4911f4 100644
--- a/src/client/shader.cpp
+++ b/src/client/shader.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iterator>
#include "shader.h"
#include "irrlichttypes_extrabloated.h"
+#include "irr_ptr.h"
#include "debug.h"
#include "filesys.h"
#include "util/container.h"
@@ -189,19 +190,14 @@ private:
class ShaderCallback : public video::IShaderConstantSetCallBack
{
- std::vector<IShaderConstantSetter*> m_setters;
+ std::vector<std::unique_ptr<IShaderConstantSetter>> m_setters;
public:
- ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
+ template <typename Factories>
+ ShaderCallback(const Factories &factories)
{
- for (IShaderConstantSetterFactory *factory : factories)
- m_setters.push_back(factory->create());
- }
-
- ~ShaderCallback()
- {
- for (IShaderConstantSetter *setter : m_setters)
- delete setter;
+ for (auto &&factory : factories)
+ m_setters.push_back(std::unique_ptr<IShaderConstantSetter>(factory->create()));
}
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
@@ -209,15 +205,13 @@ public:
video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver != NULL);
- bool is_highlevel = userData;
-
- for (IShaderConstantSetter *setter : m_setters)
- setter->onSetConstants(services, is_highlevel);
+ for (auto &&setter : m_setters)
+ setter->onSetConstants(services);
}
virtual void OnSetMaterial(const video::SMaterial& material) override
{
- for (IShaderConstantSetter *setter : m_setters)
+ for (auto &&setter : m_setters)
setter->onSetMaterial(material);
}
};
@@ -252,47 +246,39 @@ public:
{}
~MainShaderConstantSetter() = default;
- virtual void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel)
+ virtual void onSetConstants(video::IMaterialRendererServices *services) override
{
video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver);
// Set world matrix
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
- if (is_highlevel)
- m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
- else
- services->setVertexShaderConstant(world.pointer(), 4, 4);
+ m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
// Set clip matrix
core::matrix4 worldView;
worldView = driver->getTransform(video::ETS_VIEW);
worldView *= world;
+
core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= worldView;
- if (is_highlevel)
- m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
- else
- services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
+ m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
#if ENABLE_GLES
- if (is_highlevel) {
- core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
- m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
- m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
-
- core::matrix4 normal;
- worldView.getTransposed(normal);
- sanity_check(normal.makeInverse());
- float m[9] = {
- normal[0], normal[1], normal[2],
- normal[4], normal[5], normal[6],
- normal[8], normal[9], normal[10],
- };
- m_normal.set(m, services);
- }
+ core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
+ m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
+ m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
+
+ core::matrix4 normal;
+ worldView.getTransposed(normal);
+ sanity_check(normal.makeInverse());
+ float m[9] = {
+ normal[0], normal[1], normal[2],
+ normal[4], normal[5], normal[6],
+ normal[8], normal[9], normal[10],
+ };
+ m_normal.set(m, services);
#endif
}
};
@@ -314,7 +300,6 @@ class ShaderSource : public IWritableShaderSource
{
public:
ShaderSource();
- ~ShaderSource();
/*
- If shader material specified by name is found from cache,
@@ -324,7 +309,7 @@ public:
The id 0 points to a null shader. Its material is EMT_SOLID.
*/
u32 getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype);
+ MaterialType material_type, NodeDrawType drawtype) override;
/*
If shader specified by the name pointed by the id doesn't
@@ -336,26 +321,26 @@ public:
*/
u32 getShader(const std::string &name,
- const u8 material_type, const u8 drawtype);
+ MaterialType material_type, NodeDrawType drawtype) override;
- ShaderInfo getShaderInfo(u32 id);
+ ShaderInfo getShaderInfo(u32 id) override;
// Processes queued shader requests from other threads.
// Shall be called from the main thread.
- void processQueue();
+ void processQueue() override;
// Insert a shader program into the cache without touching the
// filesystem. Shall be called from the main thread.
void insertSourceShader(const std::string &name_of_shader,
- const std::string &filename, const std::string &program);
+ const std::string &filename, const std::string &program) override;
// Rebuild shaders from the current set of source shaders
// Shall be called from the main thread.
- void rebuildShaders();
+ void rebuildShaders() override;
- void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
+ void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) override
{
- m_setter_factories.push_back(setter);
+ m_setter_factories.push_back(std::unique_ptr<IShaderConstantSetterFactory>(setter));
}
private:
@@ -377,10 +362,11 @@ private:
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
// Global constant setter factories
- std::vector<IShaderConstantSetterFactory *> m_setter_factories;
+ std::vector<std::unique_ptr<IShaderConstantSetterFactory>> m_setter_factories;
- // Shader callbacks
- std::vector<ShaderCallback *> m_callbacks;
+ // Generate shader given the shader name.
+ ShaderInfo generateShader(const std::string &name,
+ MaterialType material_type, NodeDrawType drawtype);
};
IWritableShaderSource *createShaderSource()
@@ -388,22 +374,6 @@ IWritableShaderSource *createShaderSource()
return new ShaderSource();
}
-/*
- Generate shader given the shader name.
-*/
-ShaderInfo generate_shader(const std::string &name,
- u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
- const std::vector<IShaderConstantSetterFactory *> &setter_factories,
- SourceShaderCache *sourcecache);
-
-/*
- Load shader programs
-*/
-void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
- video::E_DRIVER_TYPE drivertype, bool enable_shaders,
- std::string &vertex_program, std::string &pixel_program,
- std::string &geometry_program, bool &is_highlevel);
-
ShaderSource::ShaderSource()
{
m_main_thread = std::this_thread::get_id();
@@ -415,18 +385,8 @@ ShaderSource::ShaderSource()
addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
}
-ShaderSource::~ShaderSource()
-{
- for (ShaderCallback *callback : m_callbacks) {
- delete callback;
- }
- for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
- delete setter_factorie;
- }
-}
-
u32 ShaderSource::getShader(const std::string &name,
- const u8 material_type, const u8 drawtype)
+ MaterialType material_type, NodeDrawType drawtype)
{
/*
Get shader
@@ -468,7 +428,7 @@ u32 ShaderSource::getShader(const std::string &name,
This method generates all the shaders
*/
u32 ShaderSource::getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype)
+ MaterialType material_type, NodeDrawType drawtype)
{
//infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
@@ -495,8 +455,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
return 0;
}
- ShaderInfo info = generate_shader(name, material_type, drawtype,
- m_callbacks, m_setter_factories, &m_sourcecache);
+ ShaderInfo info = generateShader(name, material_type, drawtype);
/*
Add shader to caches (add dummy shaders too)
@@ -560,18 +519,14 @@ void ShaderSource::rebuildShaders()
for (ShaderInfo &i : m_shaderinfo_cache) {
ShaderInfo *info = &i;
if (!info->name.empty()) {
- *info = generate_shader(info->name, info->material_type,
- info->drawtype, m_callbacks,
- m_setter_factories, &m_sourcecache);
+ *info = generateShader(info->name, info->material_type, info->drawtype);
}
}
}
-ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
- std::vector<ShaderCallback *> &callbacks,
- const std::vector<IShaderConstantSetterFactory *> &setter_factories,
- SourceShaderCache *sourcecache)
+ShaderInfo ShaderSource::generateShader(const std::string &name,
+ MaterialType material_type, NodeDrawType drawtype)
{
ShaderInfo shaderinfo;
shaderinfo.name = name;
@@ -604,64 +559,27 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
return shaderinfo;
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
-
- video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
- if(!gpu){
- errorstream<<"generate_shader(): "
- "failed to generate \""<<name<<"\", "
- "GPU programming not supported."
- <<std::endl;
+ if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
+ errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
return shaderinfo;
}
-
- // Choose shader language depending on driver type and settings
- // Then load shaders
- std::string vertex_program;
- std::string pixel_program;
- std::string geometry_program;
- bool is_highlevel;
- load_shaders(name, sourcecache, driver->getDriverType(),
- enable_shaders, vertex_program, pixel_program,
- geometry_program, is_highlevel);
- // Check hardware/driver support
- if (!vertex_program.empty() &&
- !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
- !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
- infostream<<"generate_shader(): vertex shaders disabled "
- "because of missing driver/hardware support."
- <<std::endl;
- vertex_program = "";
- }
- if (!pixel_program.empty() &&
- !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
- !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
- infostream<<"generate_shader(): pixel shaders disabled "
- "because of missing driver/hardware support."
- <<std::endl;
- pixel_program = "";
- }
- if (!geometry_program.empty() &&
- !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
- infostream<<"generate_shader(): geometry shaders disabled "
- "because of missing driver/hardware support."
- <<std::endl;
- geometry_program = "";
- }
-
- // If no shaders are used, don't make a separate material type
- if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
- return shaderinfo;
+ video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
// Create shaders header
bool use_gles = false;
#if ENABLE_GLES
use_gles = driver->getDriverType() == video::EDT_OGLES2;
#endif
- std::string shaders_header, vertex_header, pixel_header; // geometry shaders aren’t supported in GLES<3
+ std::stringstream shaders_header;
+ shaders_header
+ << std::noboolalpha
+ << std::showpoint // for GLSL ES
+ ;
+ std::string vertex_header, fragment_header, geometry_header;
if (use_gles) {
- shaders_header =
- "#version 100\n"
- ;
+ shaders_header << R"(
+ #version 100
+ )";
vertex_header = R"(
uniform highp mat4 mWorldView;
uniform highp mat4 mWorldViewProj;
@@ -675,11 +593,11 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
attribute mediump vec4 inVertexTangent;
attribute mediump vec4 inVertexBinormal;
)";
- pixel_header = R"(
+ fragment_header = R"(
precision mediump float;
)";
} else {
- shaders_header = R"(
+ shaders_header << R"(
#version 120
#define lowp
#define mediump
@@ -708,224 +626,97 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
use_discard = true;
#endif
if (use_discard && shaderinfo.base_material != video::EMT_SOLID)
- shaders_header += "#define USE_DISCARD\n";
-
- static const char* drawTypes[] = {
- "NDT_NORMAL",
- "NDT_AIRLIKE",
- "NDT_LIQUID",
- "NDT_FLOWINGLIQUID",
- "NDT_GLASSLIKE",
- "NDT_ALLFACES",
- "NDT_ALLFACES_OPTIONAL",
- "NDT_TORCHLIKE",
- "NDT_SIGNLIKE",
- "NDT_PLANTLIKE",
- "NDT_FENCELIKE",
- "NDT_RAILLIKE",
- "NDT_NODEBOX",
- "NDT_GLASSLIKE_FRAMED",
- "NDT_FIRELIKE",
- "NDT_GLASSLIKE_FRAMED_OPTIONAL",
- "NDT_PLANTLIKE_ROOTED",
- };
-
- for (int i = 0; i < 14; i++){
- shaders_header += "#define ";
- shaders_header += drawTypes[i];
- shaders_header += " ";
- shaders_header += itos(i);
- shaders_header += "\n";
- }
-
- static const char* materialTypes[] = {
- "TILE_MATERIAL_BASIC",
- "TILE_MATERIAL_ALPHA",
- "TILE_MATERIAL_LIQUID_TRANSPARENT",
- "TILE_MATERIAL_LIQUID_OPAQUE",
- "TILE_MATERIAL_WAVING_LEAVES",
- "TILE_MATERIAL_WAVING_PLANTS",
- "TILE_MATERIAL_OPAQUE",
- "TILE_MATERIAL_WAVING_LIQUID_BASIC",
- "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
- "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
- "TILE_MATERIAL_PLAIN",
- "TILE_MATERIAL_PLAIN_ALPHA",
- };
-
- for (int i = 0; i < 12; i++){
- shaders_header += "#define ";
- shaders_header += materialTypes[i];
- shaders_header += " ";
- shaders_header += itos(i);
- shaders_header += "\n";
- }
-
- shaders_header += "#define MATERIAL_TYPE ";
- shaders_header += itos(material_type);
- shaders_header += "\n";
- shaders_header += "#define DRAW_TYPE ";
- shaders_header += itos(drawtype);
- shaders_header += "\n";
-
- if (g_settings->getBool("enable_waving_water")){
- shaders_header += "#define ENABLE_WAVING_WATER 1\n";
- shaders_header += "#define WATER_WAVE_HEIGHT ";
- shaders_header += std::to_string(g_settings->getFloat("water_wave_height"));
- shaders_header += "\n";
- shaders_header += "#define WATER_WAVE_LENGTH ";
- shaders_header += std::to_string(g_settings->getFloat("water_wave_length"));
- shaders_header += "\n";
- shaders_header += "#define WATER_WAVE_SPEED ";
- shaders_header += std::to_string(g_settings->getFloat("water_wave_speed"));
- shaders_header += "\n";
- } else{
- shaders_header += "#define ENABLE_WAVING_WATER 0\n";
- }
-
- shaders_header += "#define ENABLE_WAVING_LEAVES ";
- if (g_settings->getBool("enable_waving_leaves"))
- shaders_header += "1\n";
- else
- shaders_header += "0\n";
-
- shaders_header += "#define ENABLE_WAVING_PLANTS ";
- if (g_settings->getBool("enable_waving_plants"))
- shaders_header += "1\n";
- else
- shaders_header += "0\n";
-
- if (g_settings->getBool("tone_mapping"))
- shaders_header += "#define ENABLE_TONE_MAPPING\n";
-
- shaders_header += "#define FOG_START ";
- shaders_header += std::to_string(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
- shaders_header += "\n";
-
- // Call addHighLevelShaderMaterial() or addShaderMaterial()
- const c8* vertex_program_ptr = 0;
- const c8* pixel_program_ptr = 0;
- const c8* geometry_program_ptr = 0;
- if (!vertex_program.empty()) {
- vertex_program = shaders_header + vertex_header + vertex_program;
- vertex_program_ptr = vertex_program.c_str();
- }
- if (!pixel_program.empty()) {
- pixel_program = shaders_header + pixel_header + pixel_program;
- pixel_program_ptr = pixel_program.c_str();
- }
- if (!geometry_program.empty()) {
- geometry_program = shaders_header + geometry_program;
- geometry_program_ptr = geometry_program.c_str();
- }
- ShaderCallback *cb = new ShaderCallback(setter_factories);
- s32 shadermat = -1;
- if(is_highlevel){
- infostream<<"Compiling high level shaders for "<<name<<std::endl;
- shadermat = gpu->addHighLevelShaderMaterial(
- vertex_program_ptr, // Vertex shader program
- "vertexMain", // Vertex shader entry point
- video::EVST_VS_1_1, // Vertex shader version
- pixel_program_ptr, // Pixel shader program
- "pixelMain", // Pixel shader entry point
- video::EPST_PS_1_2, // Pixel shader version
- geometry_program_ptr, // Geometry shader program
- "geometryMain", // Geometry shader entry point
- video::EGST_GS_4_0, // Geometry shader version
- scene::EPT_TRIANGLES, // Geometry shader input
- scene::EPT_TRIANGLE_STRIP, // Geometry shader output
- 0, // Support maximum number of vertices
- cb, // Set-constant callback
- shaderinfo.base_material, // Base material
- 1 // Userdata passed to callback
- );
- if(shadermat == -1){
- errorstream<<"generate_shader(): "
- "failed to generate \""<<name<<"\", "
- "addHighLevelShaderMaterial failed."
- <<std::endl;
- dumpShaderProgram(warningstream, "Vertex", vertex_program);
- dumpShaderProgram(warningstream, "Pixel", pixel_program);
- dumpShaderProgram(warningstream, "Geometry", geometry_program);
- delete cb;
- return shaderinfo;
- }
- }
- else{
- infostream<<"Compiling assembly shaders for "<<name<<std::endl;
- shadermat = gpu->addShaderMaterial(
- vertex_program_ptr, // Vertex shader program
- pixel_program_ptr, // Pixel shader program
- cb, // Set-constant callback
- shaderinfo.base_material, // Base material
- 0 // Userdata passed to callback
- );
-
- if(shadermat == -1){
- errorstream<<"generate_shader(): "
- "failed to generate \""<<name<<"\", "
- "addShaderMaterial failed."
- <<std::endl;
- dumpShaderProgram(warningstream, "Vertex", vertex_program);
- dumpShaderProgram(warningstream,"Pixel", pixel_program);
- delete cb;
- return shaderinfo;
- }
+ shaders_header << "#define USE_DISCARD 1\n";
+
+#define PROVIDE(constant) shaders_header << "#define " #constant " " << (int)constant << "\n"
+
+ PROVIDE(NDT_NORMAL);
+ PROVIDE(NDT_AIRLIKE);
+ PROVIDE(NDT_LIQUID);
+ PROVIDE(NDT_FLOWINGLIQUID);
+ PROVIDE(NDT_GLASSLIKE);
+ PROVIDE(NDT_ALLFACES);
+ PROVIDE(NDT_ALLFACES_OPTIONAL);
+ PROVIDE(NDT_TORCHLIKE);
+ PROVIDE(NDT_SIGNLIKE);
+ PROVIDE(NDT_PLANTLIKE);
+ PROVIDE(NDT_FENCELIKE);
+ PROVIDE(NDT_RAILLIKE);
+ PROVIDE(NDT_NODEBOX);
+ PROVIDE(NDT_GLASSLIKE_FRAMED);
+ PROVIDE(NDT_FIRELIKE);
+ PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL);
+ PROVIDE(NDT_PLANTLIKE_ROOTED);
+
+ PROVIDE(TILE_MATERIAL_BASIC);
+ PROVIDE(TILE_MATERIAL_ALPHA);
+ PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT);
+ PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE);
+ PROVIDE(TILE_MATERIAL_WAVING_LEAVES);
+ PROVIDE(TILE_MATERIAL_WAVING_PLANTS);
+ PROVIDE(TILE_MATERIAL_OPAQUE);
+ PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC);
+ PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT);
+ PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE);
+ PROVIDE(TILE_MATERIAL_PLAIN);
+ PROVIDE(TILE_MATERIAL_PLAIN_ALPHA);
+
+#undef PROVIDE
+
+ shaders_header << "#define MATERIAL_TYPE " << (int)material_type << "\n";
+ shaders_header << "#define DRAW_TYPE " << (int)drawtype << "\n";
+
+ bool enable_waving_water = g_settings->getBool("enable_waving_water");
+ shaders_header << "#define ENABLE_WAVING_WATER " << enable_waving_water << "\n";
+ if (enable_waving_water) {
+ shaders_header << "#define WATER_WAVE_HEIGHT " << g_settings->getFloat("water_wave_height") << "\n";
+ shaders_header << "#define WATER_WAVE_LENGTH " << g_settings->getFloat("water_wave_length") << "\n";
+ shaders_header << "#define WATER_WAVE_SPEED " << g_settings->getFloat("water_wave_speed") << "\n";
+ }
+
+ shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
+ shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
+ shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n";
+
+ shaders_header << "#define FOG_START " << core::clamp(g_settings->getFloat("fog_start"), 0.0f, 0.99f) << "\n";
+
+ std::string common_header = shaders_header.str();
+
+ std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
+ std::string fragment_shader = m_sourcecache.getOrLoad(name, "opengl_fragment.glsl");
+ std::string geometry_shader = m_sourcecache.getOrLoad(name, "opengl_geometry.glsl");
+
+ vertex_shader = common_header + vertex_header + vertex_shader;
+ fragment_shader = common_header + fragment_header + fragment_shader;
+ const char *geometry_shader_ptr = nullptr; // optional
+ if (!geometry_shader.empty()) {
+ geometry_shader = common_header + geometry_header + geometry_shader;
+ geometry_shader_ptr = geometry_shader.c_str();
+ }
+
+ irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
+ infostream<<"Compiling high level shaders for "<<name<<std::endl;
+ s32 shadermat = gpu->addHighLevelShaderMaterial(
+ vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
+ fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
+ geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
+ cb.get(), shaderinfo.base_material, 1);
+ if (shadermat == -1) {
+ errorstream<<"generate_shader(): "
+ "failed to generate \""<<name<<"\", "
+ "addHighLevelShaderMaterial failed."
+ <<std::endl;
+ dumpShaderProgram(warningstream, "Vertex", vertex_shader);
+ dumpShaderProgram(warningstream, "Fragment", fragment_shader);
+ dumpShaderProgram(warningstream, "Geometry", geometry_shader);
+ return shaderinfo;
}
- callbacks.push_back(cb);
-
- // HACK, TODO: investigate this better
- // Grab the material renderer once more so minetest doesn't crash on exit
- driver->getMaterialRenderer(shadermat)->grab();
// Apply the newly created material type
shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
return shaderinfo;
}
-void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
- video::E_DRIVER_TYPE drivertype, bool enable_shaders,
- std::string &vertex_program, std::string &pixel_program,
- std::string &geometry_program, bool &is_highlevel)
-{
- vertex_program = "";
- pixel_program = "";
- geometry_program = "";
- is_highlevel = false;
-
- if (!enable_shaders)
- return;
-
- // Look for high level shaders
- switch (drivertype) {
- case video::EDT_DIRECT3D9:
- // Direct3D 9: HLSL
- // (All shaders in one file)
- vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
- pixel_program = vertex_program;
- geometry_program = vertex_program;
- break;
-
- case video::EDT_OPENGL:
-#if ENABLE_GLES
- case video::EDT_OGLES2:
-#endif
- // OpenGL: GLSL
- vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
- pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
- geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
- break;
-
- default:
- // e.g. OpenGL ES 1 (with no shader support)
- break;
- }
- if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
- is_highlevel = true;
- return;
- }
-}
-
void dumpShaderProgram(std::ostream &output_stream,
const std::string &program_type, const std::string &program)
{
diff --git a/src/client/shader.h b/src/client/shader.h
index 109d39336..d99182693 100644
--- a/src/client/shader.h
+++ b/src/client/shader.h
@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IMaterialRendererServices.h>
#include "irrlichttypes_bloated.h"
#include <string>
+#include "tile.h"
+#include "nodedef.h"
class IGameDef;
@@ -46,8 +48,8 @@ struct ShaderInfo {
std::string name = "";
video::E_MATERIAL_TYPE base_material = video::EMT_SOLID;
video::E_MATERIAL_TYPE material = video::EMT_SOLID;
- u8 drawtype = 0;
- u8 material_type = 0;
+ NodeDrawType drawtype = NDT_NORMAL;
+ MaterialType material_type = TILE_MATERIAL_BASIC;
ShaderInfo() = default;
virtual ~ShaderInfo() = default;
@@ -65,8 +67,7 @@ namespace irr { namespace video {
class IShaderConstantSetter {
public:
virtual ~IShaderConstantSetter() = default;
- virtual void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel) = 0;
+ virtual void onSetConstants(video::IMaterialRendererServices *services) = 0;
virtual void onSetMaterial(const video::SMaterial& material)
{ }
};
@@ -128,10 +129,10 @@ public:
virtual ~IShaderSource() = default;
virtual u32 getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
+ MaterialType material_type, NodeDrawType drawtype = NDT_NORMAL){return 0;}
virtual ShaderInfo getShaderInfo(u32 id){return ShaderInfo();}
virtual u32 getShader(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
+ MaterialType material_type, NodeDrawType drawtype = NDT_NORMAL){return 0;}
};
class IWritableShaderSource : public IShaderSource {
@@ -139,16 +140,12 @@ public:
IWritableShaderSource() = default;
virtual ~IWritableShaderSource() = default;
- virtual u32 getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
- virtual ShaderInfo getShaderInfo(u32 id){return ShaderInfo();}
- virtual u32 getShader(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
-
virtual void processQueue()=0;
virtual void insertSourceShader(const std::string &name_of_shader,
const std::string &filename, const std::string &program)=0;
virtual void rebuildShaders()=0;
+
+ /// @note Takes ownership of @p setter.
virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0;
};
diff --git a/src/client/sky.cpp b/src/client/sky.cpp
index 9a2614eda..3a40321dd 100644
--- a/src/client/sky.cpp
+++ b/src/client/sky.cpp
@@ -65,7 +65,7 @@ Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) :
// Create materials
m_materials[0] = baseMaterial();
- m_materials[0].MaterialType = ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA, 0)).material;
+ m_materials[0].MaterialType = ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material;
m_materials[0].Lighting = true;
m_materials[0].ColorMaterial = video::ECM_NONE;
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index d03588b2b..37836d0df 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -1633,6 +1633,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
/* IMPORTANT: When changing this, getTextureForMesh() needs to be
* updated too. */
+ if (!baseimg) {
+ errorstream << "generateImagePart(): baseimg == NULL "
+ << "for part_of_name=\"" << part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
+
// Apply the "clean transparent" filter, if configured.
if (g_settings->getBool("texture_clean_transparent"))
imageCleanTransparent(baseimg, 127);
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index c7d79ff3a..23e06ab05 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -347,6 +347,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("joystick_type", "");
settings->setDefault("repeat_joystick_button_time", "0.17");
settings->setDefault("joystick_frustum_sensitivity", "170");
+ settings->setDefault("joystick_deadzone", "2048");
// Main menu
settings->setDefault("main_menu_path", "");
@@ -453,6 +454,8 @@ void set_default_settings(Settings *settings)
settings->setDefault("chat_message_limit_per_10sec", "8.0");
settings->setDefault("chat_message_limit_trigger_kick", "50");
settings->setDefault("sqlite_synchronous", "2");
+ settings->setDefault("map_compression_level_disk", "3");
+ settings->setDefault("map_compression_level_net", "-1");
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
settings->setDefault("dedicated_server_step", "0.09");
settings->setDefault("active_block_mgmt_interval", "2.0");
@@ -538,6 +541,8 @@ void set_default_settings(Settings *settings)
settings->setDefault("fps_max_unfocused", "10");
settings->setDefault("max_objects_per_block", "20");
settings->setDefault("sqlite_synchronous", "1");
+ settings->setDefault("map_compression_level_disk", "-1");
+ settings->setDefault("map_compression_level_net", "3");
settings->setDefault("server_map_save_interval", "15");
settings->setDefault("client_mapblock_limit", "1000");
settings->setDefault("active_block_range", "2");
diff --git a/src/filesys.cpp b/src/filesys.cpp
index 2470b1b64..28a33f4d0 100644
--- a/src/filesys.cpp
+++ b/src/filesys.cpp
@@ -295,31 +295,26 @@ bool RecursiveDelete(const std::string &path)
infostream<<"Removing \""<<path<<"\""<<std::endl;
- //return false;
-
pid_t child_pid = fork();
if(child_pid == 0)
{
// Child
- char argv_data[3][10000];
+ const char *argv[4] = {
#ifdef __ANDROID__
- strcpy(argv_data[0], "/system/bin/rm");
+ "/system/bin/rm",
#else
- strcpy(argv_data[0], "/bin/rm");
+ "/bin/rm",
#endif
- strcpy(argv_data[1], "-rf");
- strncpy(argv_data[2], path.c_str(), sizeof(argv_data[2]) - 1);
- char *argv[4];
- argv[0] = argv_data[0];
- argv[1] = argv_data[1];
- argv[2] = argv_data[2];
- argv[3] = NULL;
+ "-rf",
+ path.c_str(),
+ NULL
+ };
verbosestream<<"Executing '"<<argv[0]<<"' '"<<argv[1]<<"' '"
<<argv[2]<<"'"<<std::endl;
- execv(argv[0], argv);
+ execv(argv[0], const_cast<char**>(argv));
// Execv shouldn't return. Failed.
_exit(1);
@@ -331,7 +326,6 @@ bool RecursiveDelete(const std::string &path)
pid_t tpid;
do{
tpid = wait(&child_status);
- //if(tpid != child_pid) process_terminated(tpid);
}while(tpid != child_pid);
return (child_status == 0);
}
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 91476ada6..f93b85aff 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -8,6 +8,7 @@ set(gui_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/guiButtonItemImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/guiEditBox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp
diff --git a/src/gui/guiEditBox.cpp b/src/gui/guiEditBox.cpp
new file mode 100644
index 000000000..159bd38ac
--- /dev/null
+++ b/src/gui/guiEditBox.cpp
@@ -0,0 +1,95 @@
+/*
+Minetest
+Copyright (C) 2021 Minetest
+
+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.
+*/
+
+#include "guiEditBox.h"
+
+#include "IGUISkin.h"
+#include "IGUIEnvironment.h"
+#include "IGUIFont.h"
+
+GUIEditBox::~GUIEditBox()
+{
+ if (m_override_font)
+ m_override_font->drop();
+}
+
+void GUIEditBox::setOverrideFont(IGUIFont *font)
+{
+ if (m_override_font == font)
+ return;
+
+ if (m_override_font)
+ m_override_font->drop();
+
+ m_override_font = font;
+
+ if (m_override_font)
+ m_override_font->grab();
+
+ breakText();
+}
+
+//! Get the font which is used right now for drawing
+IGUIFont *GUIEditBox::getActiveFont() const
+{
+ if (m_override_font)
+ return m_override_font;
+ IGUISkin *skin = Environment->getSkin();
+ if (skin)
+ return skin->getFont();
+ return 0;
+}
+
+//! Sets another color for the text.
+void GUIEditBox::setOverrideColor(video::SColor color)
+{
+ m_override_color = color;
+ m_override_color_enabled = true;
+}
+
+video::SColor GUIEditBox::getOverrideColor() const
+{
+ return m_override_color;
+}
+
+//! Sets if the text should use the overide color or the color in the gui skin.
+void GUIEditBox::enableOverrideColor(bool enable)
+{
+ m_override_color_enabled = enable;
+}
+
+//! Enables or disables word wrap
+void GUIEditBox::setWordWrap(bool enable)
+{
+ m_word_wrap = enable;
+ breakText();
+}
+
+//! Enables or disables newlines.
+void GUIEditBox::setMultiLine(bool enable)
+{
+ m_multiline = enable;
+}
+
+//! Enables or disables automatic scrolling with cursor position
+//! \param enable: If set to true, the text will move around with the cursor position
+void GUIEditBox::setAutoScroll(bool enable)
+{
+ m_autoscroll = enable;
+}
diff --git a/src/gui/guiEditBox.h b/src/gui/guiEditBox.h
new file mode 100644
index 000000000..c673f2f5f
--- /dev/null
+++ b/src/gui/guiEditBox.h
@@ -0,0 +1,103 @@
+/*
+Minetest
+Copyright (C) 2021 Minetest
+
+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.
+*/
+
+#pragma once
+
+#include "IGUIEditBox.h"
+#include "IOSOperator.h"
+#include "guiScrollBar.h"
+
+using namespace irr;
+using namespace irr::gui;
+
+class GUIEditBox : public IGUIEditBox
+{
+public:
+ GUIEditBox(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
+ core::rect<s32> rectangle) :
+ IGUIEditBox(environment, parent, id, rectangle)
+ {
+ }
+
+ virtual ~GUIEditBox();
+
+ //! Sets another skin independent font.
+ virtual void setOverrideFont(IGUIFont *font = 0);
+
+ virtual IGUIFont *getOverrideFont() const { return m_override_font; }
+
+ //! Get the font which is used right now for drawing
+ /** Currently this is the override font when one is set and the
+ font of the active skin otherwise */
+ virtual IGUIFont *getActiveFont() const;
+
+ //! Sets another color for the text.
+ virtual void setOverrideColor(video::SColor color);
+
+ //! Gets the override color
+ virtual video::SColor getOverrideColor() const;
+
+ //! Sets if the text should use the overide color or the
+ //! color in the gui skin.
+ virtual void enableOverrideColor(bool enable);
+
+ //! Checks if an override color is enabled
+ /** \return true if the override color is enabled, false otherwise */
+ virtual bool isOverrideColorEnabled(void) const
+ {
+ return m_override_color_enabled;
+ }
+
+ //! Enables or disables word wrap for using the edit box as multiline text editor.
+ virtual void setWordWrap(bool enable);
+
+ //! Checks if word wrap is enabled
+ //! \return true if word wrap is enabled, false otherwise
+ virtual bool isWordWrapEnabled() const { return m_word_wrap; }
+
+ //! Enables or disables newlines.
+ /** \param enable: If set to true, the EGET_EDITBOX_ENTER event will not be fired,
+ instead a newline character will be inserted. */
+ virtual void setMultiLine(bool enable);
+
+ //! Checks if multi line editing is enabled
+ //! \return true if mult-line is enabled, false otherwise
+ virtual bool isMultiLineEnabled() const { return m_multiline; }
+
+ //! Enables or disables automatic scrolling with cursor position
+ //! \param enable: If set to true, the text will move around with the cursor
+ //! position
+ virtual void setAutoScroll(bool enable);
+
+ //! Checks to see if automatic scrolling is enabled
+ //! \return true if automatic scrolling is enabled, false if not
+ virtual bool isAutoScrollEnabled() const { return m_autoscroll; }
+
+protected:
+ virtual void breakText() = 0;
+
+ gui::IGUIFont *m_override_font = nullptr;
+
+ bool m_override_color_enabled = false;
+ bool m_word_wrap = false;
+ bool m_multiline = false;
+ bool m_autoscroll = true;
+
+ video::SColor m_override_color = video::SColor(101, 255, 255, 255);
+}; \ No newline at end of file
diff --git a/src/gui/guiEditBoxWithScrollbar.cpp b/src/gui/guiEditBoxWithScrollbar.cpp
index 169425a9a..7f9fdafd7 100644
--- a/src/gui/guiEditBoxWithScrollbar.cpp
+++ b/src/gui/guiEditBoxWithScrollbar.cpp
@@ -22,16 +22,14 @@ optional? dragging selected text
numerical
*/
-
//! constructor
GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool border,
IGUIEnvironment* environment, IGUIElement* parent, s32 id,
const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
- : IGUIEditBox(environment, parent, id, rectangle), m_mouse_marking(false),
- m_border(border), m_background(true), m_override_color_enabled(false), m_mark_begin(0), m_mark_end(0),
- m_override_color(video::SColor(101, 255, 255, 255)), m_override_font(0), m_last_break_font(0),
+ : GUIEditBox(environment, parent, id, rectangle), m_mouse_marking(false),
+ m_border(border), m_background(true), m_mark_begin(0), m_mark_end(0), m_last_break_font(0),
m_operator(0), m_blink_start_time(0), m_cursor_pos(0), m_hscroll_pos(0), m_vscroll_pos(0), m_max(0),
- m_word_wrap(false), m_multiline(false), m_autoscroll(true), m_passwordbox(false),
+ m_passwordbox(false),
m_passwordchar(L'*'), m_halign(EGUIA_UPPERLEFT), m_valign(EGUIA_CENTER),
m_current_text_rect(0, 0, 1, 1), m_frame_rect(rectangle),
m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable),
@@ -69,9 +67,6 @@ GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool borde
//! destructor
GUIEditBoxWithScrollBar::~GUIEditBoxWithScrollBar()
{
- if (m_override_font)
- m_override_font->drop();
-
if (m_operator)
m_operator->drop();
@@ -80,54 +75,6 @@ GUIEditBoxWithScrollBar::~GUIEditBoxWithScrollBar()
}
-//! Sets another skin independent font.
-void GUIEditBoxWithScrollBar::setOverrideFont(IGUIFont* font)
-{
- if (m_override_font == font)
- return;
-
- if (m_override_font)
- m_override_font->drop();
-
- m_override_font = font;
-
- if (m_override_font)
- m_override_font->grab();
-
- breakText();
-}
-
-//! Gets the override font (if any)
-IGUIFont * GUIEditBoxWithScrollBar::getOverrideFont() const
-{
- return m_override_font;
-}
-
-//! Get the font which is used right now for drawing
-IGUIFont* GUIEditBoxWithScrollBar::getActiveFont() const
-{
- if (m_override_font)
- return m_override_font;
- IGUISkin* skin = Environment->getSkin();
- if (skin)
- return skin->getFont();
- return 0;
-}
-
-//! Sets another color for the text.
-void GUIEditBoxWithScrollBar::setOverrideColor(video::SColor color)
-{
- m_override_color = color;
- m_override_color_enabled = true;
-}
-
-
-video::SColor GUIEditBoxWithScrollBar::getOverrideColor() const
-{
- return m_override_color;
-}
-
-
//! Turns the border on or off
void GUIEditBoxWithScrollBar::setDrawBorder(bool border)
{
@@ -140,24 +87,6 @@ void GUIEditBoxWithScrollBar::setDrawBackground(bool draw)
m_background = draw;
}
-//! Sets if the text should use the overide color or the color in the gui skin.
-void GUIEditBoxWithScrollBar::enableOverrideColor(bool enable)
-{
- m_override_color_enabled = enable;
-}
-
-bool GUIEditBoxWithScrollBar::isOverrideColorEnabled() const
-{
- return m_override_color_enabled;
-}
-
-//! Enables or disables word wrap
-void GUIEditBoxWithScrollBar::setWordWrap(bool enable)
-{
- m_word_wrap = enable;
- breakText();
-}
-
void GUIEditBoxWithScrollBar::updateAbsolutePosition()
{
@@ -170,26 +99,6 @@ void GUIEditBoxWithScrollBar::updateAbsolutePosition()
}
}
-//! Checks if word wrap is enabled
-bool GUIEditBoxWithScrollBar::isWordWrapEnabled() const
-{
- return m_word_wrap;
-}
-
-
-//! Enables or disables newlines.
-void GUIEditBoxWithScrollBar::setMultiLine(bool enable)
-{
- m_multiline = enable;
-}
-
-
-//! Checks if multi line editing is enabled
-bool GUIEditBoxWithScrollBar::isMultiLineEnabled() const
-{
- return m_multiline;
-}
-
void GUIEditBoxWithScrollBar::setPasswordBox(bool password_box, wchar_t password_char)
{
@@ -850,22 +759,6 @@ void GUIEditBoxWithScrollBar::setText(const wchar_t* text)
}
-//! Enables or disables automatic scrolling with cursor position
-//! \param enable: If set to true, the text will move around with the cursor position
-void GUIEditBoxWithScrollBar::setAutoScroll(bool enable)
-{
- m_autoscroll = enable;
-}
-
-
-//! Checks to see if automatic scrolling is enabled
-//! \return true if automatic scrolling is enabled, false if not
-bool GUIEditBoxWithScrollBar::isAutoScrollEnabled() const
-{
- return m_autoscroll;
-}
-
-
//! Gets the area of the text in the edit box
//! \return Returns the size in pixels of the text
core::dimension2du GUIEditBoxWithScrollBar::getTextDimension()
diff --git a/src/gui/guiEditBoxWithScrollbar.h b/src/gui/guiEditBoxWithScrollbar.h
index 77538e2f7..5ae58b934 100644
--- a/src/gui/guiEditBoxWithScrollbar.h
+++ b/src/gui/guiEditBoxWithScrollbar.h
@@ -5,15 +5,10 @@
#ifndef GUIEDITBOXWITHSCROLLBAR_HEADER
#define GUIEDITBOXWITHSCROLLBAR_HEADER
-#include "IGUIEditBox.h"
-#include "IOSOperator.h"
-#include "guiScrollBar.h"
+#include "guiEditBox.h"
#include <vector>
-using namespace irr;
-using namespace irr::gui;
-
-class GUIEditBoxWithScrollBar : public IGUIEditBox
+class GUIEditBoxWithScrollBar : public GUIEditBox
{
public:
@@ -25,61 +20,13 @@ public:
//! destructor
virtual ~GUIEditBoxWithScrollBar();
- //! Sets another skin independent font.
- virtual void setOverrideFont(IGUIFont* font = 0);
-
- //! Gets the override font (if any)
- /** \return The override font (may be 0) */
- virtual IGUIFont* getOverrideFont() const;
-
- //! Get the font which is used right now for drawing
- /** Currently this is the override font when one is set and the
- font of the active skin otherwise */
- virtual IGUIFont* getActiveFont() const;
-
- //! Sets another color for the text.
- virtual void setOverrideColor(video::SColor color);
-
- //! Gets the override color
- virtual video::SColor getOverrideColor() const;
-
- //! Sets if the text should use the overide color or the
- //! color in the gui skin.
- virtual void enableOverrideColor(bool enable);
-
- //! Checks if an override color is enabled
- /** \return true if the override color is enabled, false otherwise */
- virtual bool isOverrideColorEnabled(void) const;
-
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw);
//! Turns the border on or off
virtual void setDrawBorder(bool border);
- //! Enables or disables word wrap for using the edit box as multiline text editor.
- virtual void setWordWrap(bool enable);
-
- //! Checks if word wrap is enabled
- //! \return true if word wrap is enabled, false otherwise
- virtual bool isWordWrapEnabled() const;
-
- //! Enables or disables newlines.
- /** \param enable: If set to true, the EGET_EDITBOX_ENTER event will not be fired,
- instead a newline character will be inserted. */
- virtual void setMultiLine(bool enable);
- //! Checks if multi line editing is enabled
- //! \return true if mult-line is enabled, false otherwise
- virtual bool isMultiLineEnabled() const;
-
- //! Enables or disables automatic scrolling with cursor position
- //! \param enable: If set to true, the text will move around with the cursor position
- virtual void setAutoScroll(bool enable);
-
- //! Checks to see if automatic scrolling is enabled
- //! \return true if automatic scrolling is enabled, false if not
- virtual bool isAutoScrollEnabled() const;
//! Gets the size area of the text in the edit box
//! \return Returns the size in pixels of the text
@@ -137,7 +84,7 @@ public:
protected:
//! Breaks the single text line.
- void breakText();
+ virtual void breakText();
//! sets the area of the given line
void setTextRect(s32 line);
//! returns the line number that the cursor is on
@@ -164,12 +111,11 @@ protected:
bool m_mouse_marking;
bool m_border;
bool m_background;
- bool m_override_color_enabled;
+
s32 m_mark_begin;
s32 m_mark_end;
- video::SColor m_override_color;
- gui::IGUIFont *m_override_font, *m_last_break_font;
+ gui::IGUIFont *m_last_break_font;
IOSOperator* m_operator;
u32 m_blink_start_time;
@@ -177,7 +123,7 @@ protected:
s32 m_hscroll_pos, m_vscroll_pos; // scroll position in characters
u32 m_max;
- bool m_word_wrap, m_multiline, m_autoscroll, m_passwordbox;
+ bool m_passwordbox;
wchar_t m_passwordchar;
EGUI_ALIGNMENT m_halign, m_valign;
diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp
index 632b15992..973fc60a8 100644
--- a/src/gui/guiFormSpecMenu.cpp
+++ b/src/gui/guiFormSpecMenu.cpp
@@ -70,7 +70,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MY_CHECKPOS(a,b) \
if (v_pos.size() != 2) { \
- errorstream<< "Invalid pos for element " << a << "specified: \"" \
+ errorstream<< "Invalid pos for element " << a << " specified: \"" \
<< parts[b] << "\"" << std::endl; \
return; \
}
@@ -78,7 +78,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MY_CHECKGEOM(a,b) \
if (v_geom.size() != 2) { \
errorstream<< "Invalid geometry for element " << a << \
- "specified: \"" << parts[b] << "\"" << std::endl; \
+ " specified: \"" << parts[b] << "\"" << std::endl; \
return; \
}
/*
@@ -2725,7 +2725,7 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
{
std::vector<std::string> parts = split(element, ';');
- if (parts.size() < 5 || (parts.size() > 8 &&
+ if (parts.size() < 5 || (parts.size() > 9 &&
m_formspec_version <= FORMSPEC_API_VERSION)) {
errorstream << "Invalid model element (" << parts.size() << "): '" << element
<< "'" << std::endl;
@@ -2733,8 +2733,8 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
}
// Avoid length checks by resizing
- if (parts.size() < 8)
- parts.resize(8);
+ if (parts.size() < 9)
+ parts.resize(9);
std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ',');
@@ -2744,6 +2744,7 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
std::vector<std::string> vec_rot = split(parts[5], ',');
bool inf_rotation = is_yes(parts[6]);
bool mousectrl = is_yes(parts[7]) || parts[7].empty(); // default true
+ std::vector<std::string> frame_loop = split(parts[8], ',');
MY_CHECKPOS("model", 0);
MY_CHECKGEOM("model", 1);
@@ -2786,7 +2787,7 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
auto meshnode = e->setMesh(mesh);
for (u32 i = 0; i < textures.size() && i < meshnode->getMaterialCount(); ++i)
- e->setTexture(i, m_tsrc->getTexture(textures[i]));
+ e->setTexture(i, m_tsrc->getTexture(unescape_string(textures[i])));
if (vec_rot.size() >= 2)
e->setRotation(v2f(stof(vec_rot[0]), stof(vec_rot[1])));
@@ -2794,6 +2795,16 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
e->enableContinuousRotation(inf_rotation);
e->enableMouseControl(mousectrl);
+ s32 frame_loop_begin = 0;
+ s32 frame_loop_end = 0x7FFFFFFF;
+
+ if (frame_loop.size() == 2) {
+ frame_loop_begin = stoi(frame_loop[0]);
+ frame_loop_end = stoi(frame_loop[1]);
+ }
+
+ e->setFrameLoop(frame_loop_begin, frame_loop_end);
+
auto style = getStyleForElement("model", spec.fname);
e->setStyles(style);
e->drop();
@@ -3707,7 +3718,8 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
{
EnrichedString ntext(text);
ntext.setDefaultColor(color);
- ntext.setBackground(bgcolor);
+ if (!ntext.hasBackground())
+ ntext.setBackground(bgcolor);
setStaticText(m_tooltip_element, ntext);
diff --git a/src/gui/guiScene.cpp b/src/gui/guiScene.cpp
index 08f119e07..5f4c50b91 100644
--- a/src/gui/guiScene.cpp
+++ b/src/gui/guiScene.cpp
@@ -152,6 +152,15 @@ void GUIScene::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &sty
setBackgroundColor(style.getColor(StyleSpec::BGCOLOR, m_bgcolor));
}
+/**
+ * Sets the frame loop range for the mesh
+ */
+void GUIScene::setFrameLoop(s32 begin, s32 end)
+{
+ if (m_mesh->getStartFrame() != begin || m_mesh->getEndFrame() != end)
+ m_mesh->setFrameLoop(begin, end);
+}
+
/* Camera control functions */
inline void GUIScene::calcOptimalDistance()
diff --git a/src/gui/guiScene.h b/src/gui/guiScene.h
index 707e6f66a..08eb7f350 100644
--- a/src/gui/guiScene.h
+++ b/src/gui/guiScene.h
@@ -36,6 +36,7 @@ public:
scene::IAnimatedMeshSceneNode *setMesh(scene::IAnimatedMesh *mesh = nullptr);
void setTexture(u32 idx, video::ITexture *texture);
void setBackgroundColor(const video::SColor &color) noexcept { m_bgcolor = color; };
+ void setFrameLoop(s32 begin, s32 end);
void enableMouseControl(bool enable) noexcept { m_mouse_ctrl = enable; };
void setRotation(v2f rot) noexcept { m_custom_rot = rot; };
void enableContinuousRotation(bool enable) noexcept { m_inf_rot = enable; };
diff --git a/src/gui/intlGUIEditBox.cpp b/src/gui/intlGUIEditBox.cpp
index 8be63fd6f..e917f73c1 100644
--- a/src/gui/intlGUIEditBox.cpp
+++ b/src/gui/intlGUIEditBox.cpp
@@ -59,7 +59,7 @@ namespace gui
intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
IGUIEnvironment* environment, IGUIElement* parent, s32 id,
const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
- : IGUIEditBox(environment, parent, id, rectangle),
+ : GUIEditBox(environment, parent, id, rectangle),
Border(border), FrameRect(rectangle),
m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable)
{
@@ -108,9 +108,6 @@ intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
//! destructor
intlGUIEditBox::~intlGUIEditBox()
{
- if (OverrideFont)
- OverrideFont->drop();
-
if (Operator)
Operator->drop();
@@ -118,52 +115,6 @@ intlGUIEditBox::~intlGUIEditBox()
m_vscrollbar->drop();
}
-
-//! Sets another skin independent font.
-void intlGUIEditBox::setOverrideFont(IGUIFont* font)
-{
- if (OverrideFont == font)
- return;
-
- if (OverrideFont)
- OverrideFont->drop();
-
- OverrideFont = font;
-
- if (OverrideFont)
- OverrideFont->grab();
-
- breakText();
-}
-
-IGUIFont * intlGUIEditBox::getOverrideFont() const
-{
- return OverrideFont;
-}
-
-//! Get the font which is used right now for drawing
-IGUIFont* intlGUIEditBox::getActiveFont() const
-{
- if ( OverrideFont )
- return OverrideFont;
- IGUISkin* skin = Environment->getSkin();
- if (skin)
- return skin->getFont();
- return 0;
-}
-
-//! Sets another color for the text.
-void intlGUIEditBox::setOverrideColor(video::SColor color)
-{
- OverrideColor = color;
- OverrideColorEnabled = true;
-}
-
-video::SColor intlGUIEditBox::getOverrideColor() const
-{
- return OverrideColor;
-}
-
//! Turns the border on or off
void intlGUIEditBox::setDrawBorder(bool border)
{
@@ -175,25 +126,6 @@ void intlGUIEditBox::setDrawBackground(bool draw)
{
}
-//! Sets if the text should use the overide color or the color in the gui skin.
-void intlGUIEditBox::enableOverrideColor(bool enable)
-{
- OverrideColorEnabled = enable;
-}
-
-bool intlGUIEditBox::isOverrideColorEnabled() const
-{
- return OverrideColorEnabled;
-}
-
-//! Enables or disables word wrap
-void intlGUIEditBox::setWordWrap(bool enable)
-{
- WordWrap = enable;
- breakText();
-}
-
-
void intlGUIEditBox::updateAbsolutePosition()
{
core::rect<s32> oldAbsoluteRect(AbsoluteRect);
@@ -204,28 +136,6 @@ void intlGUIEditBox::updateAbsolutePosition()
}
}
-
-//! Checks if word wrap is enabled
-bool intlGUIEditBox::isWordWrapEnabled() const
-{
- return WordWrap;
-}
-
-
-//! Enables or disables newlines.
-void intlGUIEditBox::setMultiLine(bool enable)
-{
- MultiLine = enable;
-}
-
-
-//! Checks if multi line editing is enabled
-bool intlGUIEditBox::isMultiLineEnabled() const
-{
- return MultiLine;
-}
-
-
void intlGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar)
{
PasswordBox = passwordBox;
@@ -464,7 +374,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
case KEY_END:
{
s32 p = Text.size();
- if (WordWrap || MultiLine)
+ if (m_word_wrap || m_multiline)
{
p = getLineFromPos(CursorPos);
p = BrokenTextPositions[p] + (s32)BrokenText[p].size();
@@ -492,7 +402,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
{
s32 p = 0;
- if (WordWrap || MultiLine)
+ if (m_word_wrap || m_multiline)
{
p = getLineFromPos(CursorPos);
p = BrokenTextPositions[p];
@@ -514,7 +424,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
}
break;
case KEY_RETURN:
- if (MultiLine)
+ if (m_multiline)
{
inputChar(L'\n');
return true;
@@ -567,7 +477,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
BlinkStartTime = porting::getTimeMs();
break;
case KEY_UP:
- if (MultiLine || (WordWrap && BrokenText.size() > 1) )
+ if (m_multiline || (m_word_wrap && BrokenText.size() > 1) )
{
s32 lineNo = getLineFromPos(CursorPos);
s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd);
@@ -598,7 +508,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
}
break;
case KEY_DOWN:
- if (MultiLine || (WordWrap && BrokenText.size() > 1) )
+ if (m_multiline || (m_word_wrap && BrokenText.size() > 1) )
{
s32 lineNo = getLineFromPos(CursorPos);
s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd);
@@ -791,8 +701,8 @@ void intlGUIEditBox::draw()
// draw the text
- IGUIFont* font = OverrideFont;
- if (!OverrideFont)
+ IGUIFont* font = m_override_font;
+ if (!m_override_font)
font = skin->getFont();
s32 cursorLine = 0;
@@ -813,7 +723,7 @@ void intlGUIEditBox::draw()
core::stringw s, s2;
// get mark position
- const bool ml = (!PasswordBox && (WordWrap || MultiLine));
+ const bool ml = (!PasswordBox && (m_word_wrap || m_multiline));
const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0;
@@ -822,14 +732,14 @@ void intlGUIEditBox::draw()
// Save the override color information.
// Then, alter it if the edit box is disabled.
- const bool prevOver = OverrideColorEnabled;
- const video::SColor prevColor = OverrideColor;
+ const bool prevOver = m_override_color_enabled;
+ const video::SColor prevColor = m_override_color;
if (!Text.empty()) {
- if (!IsEnabled && !OverrideColorEnabled)
+ if (!IsEnabled && !m_override_color_enabled)
{
- OverrideColorEnabled = true;
- OverrideColor = skin->getColor(EGDC_GRAY_TEXT);
+ m_override_color_enabled = true;
+ m_override_color = skin->getColor(EGDC_GRAY_TEXT);
}
for (s32 i=0; i < lineCount; ++i)
@@ -870,7 +780,7 @@ void intlGUIEditBox::draw()
// draw normal text
font->draw(txtLine->c_str(), CurrentTextRect,
- OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
+ m_override_color_enabled ? m_override_color : skin->getColor(EGDC_BUTTON_TEXT),
false, true, &localClipRect);
// draw mark and marked text
@@ -914,20 +824,20 @@ void intlGUIEditBox::draw()
if (!s.empty())
font->draw(s.c_str(), CurrentTextRect,
- OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
+ m_override_color_enabled ? m_override_color : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
false, true, &localClipRect);
}
}
// Return the override color information to its previous settings.
- OverrideColorEnabled = prevOver;
- OverrideColor = prevColor;
+ m_override_color_enabled = prevOver;
+ m_override_color = prevColor;
}
// draw cursor
- if (WordWrap || MultiLine)
+ if (m_word_wrap || m_multiline)
{
cursorLine = getLineFromPos(CursorPos);
txtLine = &BrokenText[cursorLine];
@@ -943,7 +853,7 @@ void intlGUIEditBox::draw()
CurrentTextRect.UpperLeftCorner.X += charcursorpos;
font->draw(L"_", CurrentTextRect,
- OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
+ m_override_color_enabled ? m_override_color : skin->getColor(EGDC_BUTTON_TEXT),
false, true, &localClipRect);
}
}
@@ -965,22 +875,6 @@ void intlGUIEditBox::setText(const wchar_t* text)
}
-//! Enables or disables automatic scrolling with cursor position
-//! \param enable: If set to true, the text will move around with the cursor position
-void intlGUIEditBox::setAutoScroll(bool enable)
-{
- AutoScroll = enable;
-}
-
-
-//! Checks to see if automatic scrolling is enabled
-//! \return true if automatic scrolling is enabled, false if not
-bool intlGUIEditBox::isAutoScrollEnabled() const
-{
- return AutoScroll;
-}
-
-
//! Gets the area of the text in the edit box
//! \return Returns the size in pixels of the text
core::dimension2du intlGUIEditBox::getTextDimension()
@@ -1096,12 +990,12 @@ bool intlGUIEditBox::processMouse(const SEvent& event)
s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
{
- IGUIFont* font = OverrideFont;
+ IGUIFont* font = m_override_font;
IGUISkin* skin = Environment->getSkin();
- if (!OverrideFont)
+ if (!m_override_font)
font = skin->getFont();
- const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
+ const u32 lineCount = (m_word_wrap || m_multiline) ? BrokenText.size() : 1;
core::stringw *txtLine = NULL;
s32 startPos = 0;
@@ -1118,8 +1012,8 @@ s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
// is it inside this region?
if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) {
// we've found the clicked line
- txtLine = (WordWrap || MultiLine) ? &BrokenText[curr_line_idx] : &Text;
- startPos = (WordWrap || MultiLine) ? BrokenTextPositions[curr_line_idx] : 0;
+ txtLine = (m_word_wrap || m_multiline) ? &BrokenText[curr_line_idx] : &Text;
+ startPos = (m_word_wrap || m_multiline) ? BrokenTextPositions[curr_line_idx] : 0;
break;
}
}
@@ -1144,14 +1038,14 @@ void intlGUIEditBox::breakText()
{
IGUISkin* skin = Environment->getSkin();
- if ((!WordWrap && !MultiLine) || !skin)
+ if ((!m_word_wrap && !m_multiline) || !skin)
return;
BrokenText.clear(); // need to reallocate :/
BrokenTextPositions.set_used(0);
- IGUIFont* font = OverrideFont;
- if (!OverrideFont)
+ IGUIFont* font = m_override_font;
+ if (!m_override_font)
font = skin->getFont();
if (!font)
@@ -1190,7 +1084,7 @@ void intlGUIEditBox::breakText()
}
// don't break if we're not a multi-line edit box
- if (!MultiLine)
+ if (!m_multiline)
lineBreak = false;
if (c == L' ' || c == 0 || i == (size-1))
@@ -1201,7 +1095,7 @@ void intlGUIEditBox::breakText()
s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
s32 worldlgth = font->getDimension(word.c_str()).Width;
- if (WordWrap && length + worldlgth + whitelgth > elWidth)
+ if (m_word_wrap && length + worldlgth + whitelgth > elWidth)
{
// break to next line
length = worldlgth;
@@ -1260,14 +1154,14 @@ void intlGUIEditBox::setTextRect(s32 line)
if (!skin)
return;
- IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
+ IGUIFont* font = m_override_font ? m_override_font : skin->getFont();
if (!font)
return;
// get text dimension
- const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
- if (WordWrap || MultiLine)
+ const u32 lineCount = (m_word_wrap || m_multiline) ? BrokenText.size() : 1;
+ if (m_word_wrap || m_multiline)
{
d = font->getDimension(BrokenText[line].c_str());
}
@@ -1328,7 +1222,7 @@ void intlGUIEditBox::setTextRect(s32 line)
s32 intlGUIEditBox::getLineFromPos(s32 pos)
{
- if (!WordWrap && !MultiLine)
+ if (!m_word_wrap && !m_multiline)
return 0;
s32 i=0;
@@ -1387,7 +1281,7 @@ void intlGUIEditBox::inputChar(wchar_t c)
void intlGUIEditBox::calculateScrollPos()
{
- if (!AutoScroll)
+ if (!m_autoscroll)
return;
// calculate horizontal scroll position
@@ -1395,18 +1289,18 @@ void intlGUIEditBox::calculateScrollPos()
setTextRect(cursLine);
// don't do horizontal scrolling when wordwrap is enabled.
- if (!WordWrap)
+ if (!m_word_wrap)
{
// get cursor position
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
- IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
+ IGUIFont* font = m_override_font ? m_override_font : skin->getFont();
if (!font)
return;
- core::stringw *txtLine = MultiLine ? &BrokenText[cursLine] : &Text;
- s32 cPos = MultiLine ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
+ core::stringw *txtLine = m_multiline ? &BrokenText[cursLine] : &Text;
+ s32 cPos = m_multiline ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos +
font->getDimension(txtLine->subString(0, cPos).c_str()).Width;
@@ -1423,7 +1317,7 @@ void intlGUIEditBox::calculateScrollPos()
// todo: adjust scrollbar
}
- if (!WordWrap && !MultiLine)
+ if (!m_word_wrap && !m_multiline)
return;
// vertical scroll position
@@ -1468,8 +1362,8 @@ void intlGUIEditBox::createVScrollBar()
{
s32 fontHeight = 1;
- if (OverrideFont) {
- fontHeight = OverrideFont->getDimension(L"").Height;
+ if (m_override_font) {
+ fontHeight = m_override_font->getDimension(L"").Height;
} else {
if (IGUISkin* skin = Environment->getSkin()) {
if (IGUIFont* font = skin->getFont()) {
@@ -1520,7 +1414,7 @@ void intlGUIEditBox::updateVScrollBar()
m_vscrollbar->setPageSize(s32(getTextDimension().Height));
}
- if (!m_vscrollbar->isVisible() && MultiLine) {
+ if (!m_vscrollbar->isVisible() && m_multiline) {
AbsoluteRect.LowerRightCorner.X -= m_scrollbar_width;
m_vscrollbar->setVisible(true);
@@ -1548,20 +1442,20 @@ void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeRea
{
// IGUIEditBox::serializeAttributes(out,options);
- out->addBool ("OverrideColorEnabled",OverrideColorEnabled );
- out->addColor ("OverrideColor", OverrideColor);
- // out->addFont("OverrideFont",OverrideFont);
- out->addInt ("MaxChars", Max);
- out->addBool ("WordWrap", WordWrap);
- out->addBool ("MultiLine", MultiLine);
- out->addBool ("AutoScroll", AutoScroll);
- out->addBool ("PasswordBox", PasswordBox);
+ out->addBool ("OverrideColorEnabled", m_override_color_enabled );
+ out->addColor ("OverrideColor", m_override_color);
+ // out->addFont("OverrideFont",m_override_font);
+ out->addInt ("MaxChars", Max);
+ out->addBool ("WordWrap", m_word_wrap);
+ out->addBool ("MultiLine", m_multiline);
+ out->addBool ("AutoScroll", m_autoscroll);
+ out->addBool ("PasswordBox", PasswordBox);
core::stringw ch = L" ";
ch[0] = PasswordChar;
- out->addString("PasswordChar", ch.c_str());
- out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
- out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
- out->addBool ("Writable", m_writable);
+ out->addString("PasswordChar", ch.c_str());
+ out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
+ out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
+ out->addBool ("Writable", m_writable);
IGUIEditBox::serializeAttributes(out,options);
}
diff --git a/src/gui/intlGUIEditBox.h b/src/gui/intlGUIEditBox.h
index 9d643495e..a1e423aa2 100644
--- a/src/gui/intlGUIEditBox.h
+++ b/src/gui/intlGUIEditBox.h
@@ -7,16 +7,15 @@
#include "IrrCompileConfig.h"
//#ifdef _IRR_COMPILE_WITH_GUI_
-#include <IGUIEditBox.h>
+#include "guiEditBox.h"
#include "irrArray.h"
#include "IOSOperator.h"
-#include "guiScrollBar.h"
namespace irr
{
namespace gui
{
- class intlGUIEditBox : public IGUIEditBox
+ class intlGUIEditBox : public GUIEditBox
{
public:
@@ -28,32 +27,6 @@ namespace gui
//! destructor
virtual ~intlGUIEditBox();
- //! Sets another skin independent font.
- virtual void setOverrideFont(IGUIFont* font=0);
-
- //! Gets the override font (if any)
- /** \return The override font (may be 0) */
- virtual IGUIFont* getOverrideFont() const;
-
- //! Get the font which is used right now for drawing
- /** Currently this is the override font when one is set and the
- font of the active skin otherwise */
- virtual IGUIFont* getActiveFont() const;
-
- //! Sets another color for the text.
- virtual void setOverrideColor(video::SColor color);
-
- //! Gets the override color
- virtual video::SColor getOverrideColor() const;
-
- //! Sets if the text should use the overide color or the
- //! color in the gui skin.
- virtual void enableOverrideColor(bool enable);
-
- //! Checks if an override color is enabled
- /** \return true if the override color is enabled, false otherwise */
- virtual bool isOverrideColorEnabled(void) const;
-
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw);
@@ -64,30 +37,6 @@ namespace gui
virtual bool isDrawBorderEnabled() const { return Border; }
- //! Enables or disables word wrap for using the edit box as multiline text editor.
- virtual void setWordWrap(bool enable);
-
- //! Checks if word wrap is enabled
- //! \return true if word wrap is enabled, false otherwise
- virtual bool isWordWrapEnabled() const;
-
- //! Enables or disables newlines.
- /** \param enable: If set to true, the EGET_EDITBOX_ENTER event will not be fired,
- instead a newline character will be inserted. */
- virtual void setMultiLine(bool enable);
-
- //! Checks if multi line editing is enabled
- //! \return true if mult-line is enabled, false otherwise
- virtual bool isMultiLineEnabled() const;
-
- //! Enables or disables automatic scrolling with cursor position
- //! \param enable: If set to true, the text will move around with the cursor position
- virtual void setAutoScroll(bool enable);
-
- //! Checks to see if automatic scrolling is enabled
- //! \return true if automatic scrolling is enabled, false if not
- virtual bool isAutoScrollEnabled() const;
-
//! Gets the size area of the text in the edit box
//! \return Returns the size in pixels of the text
virtual core::dimension2du getTextDimension();
@@ -143,7 +92,7 @@ namespace gui
protected:
//! Breaks the single text line.
- void breakText();
+ virtual void breakText();
//! sets the area of the given line
void setTextRect(s32 line);
//! returns the line number that the cursor is on
@@ -169,12 +118,9 @@ namespace gui
bool MouseMarking = false;
bool Border;
- bool OverrideColorEnabled = false;
s32 MarkBegin = 0;
s32 MarkEnd = 0;
- video::SColor OverrideColor = video::SColor(101,255,255,255);
- gui::IGUIFont *OverrideFont = nullptr;
gui::IGUIFont *LastBreakFont = nullptr;
IOSOperator *Operator = nullptr;
@@ -184,9 +130,6 @@ namespace gui
s32 VScrollPos = 0; // scroll position in characters
u32 Max = 0;
- bool WordWrap = false;
- bool MultiLine = false;
- bool AutoScroll = true;
bool PasswordBox = false;
wchar_t PasswordChar = L'*';
EGUI_ALIGNMENT HAlign = EGUIA_UPPERLEFT;
diff --git a/src/gui/touchscreengui.cpp b/src/gui/touchscreengui.cpp
index 0d64aa618..e1a971462 100644
--- a/src/gui/touchscreengui.cpp
+++ b/src/gui/touchscreengui.cpp
@@ -881,8 +881,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5.0f / 2.0f;
bool inside_joystick = (dxj * dxj + dyj * dyj <= button_size * button_size * 1.5 * 1.5);
- if (m_joystick_has_really_moved ||
- (!m_joystick_has_really_moved && inside_joystick) ||
+ if (m_joystick_has_really_moved || inside_joystick ||
(!m_fixed_joystick &&
distance_sq > m_touchscreen_threshold * m_touchscreen_threshold)) {
m_joystick_has_really_moved = true;
diff --git a/src/irrlicht_changes/CGUITTFont.h b/src/irrlicht_changes/CGUITTFont.h
index cf64934a2..310f74f67 100644
--- a/src/irrlicht_changes/CGUITTFont.h
+++ b/src/irrlicht_changes/CGUITTFont.h
@@ -356,7 +356,7 @@ namespace gui
load_flags = FT_LOAD_DEFAULT | FT_LOAD_RENDER;
if (!useHinting()) load_flags |= FT_LOAD_NO_HINTING;
if (!useAutoHinting()) load_flags |= FT_LOAD_NO_AUTOHINT;
- if (useMonochrome()) load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO | FT_RENDER_MODE_MONO;
+ if (useMonochrome()) load_flags |= FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO;
else load_flags |= FT_LOAD_TARGET_NORMAL;
}
u32 getWidthFromCharacter(wchar_t c) const;
diff --git a/src/irrlicht_changes/irrUString.h b/src/irrlicht_changes/irrUString.h
index b628c092c..09172ee6d 100644
--- a/src/irrlicht_changes/irrUString.h
+++ b/src/irrlicht_changes/irrUString.h
@@ -1331,7 +1331,7 @@ public:
{
u32 i;
const uchar16_t* oa = other.c_str();
- for(i=0; array[i] && oa[i] && i < n; ++i)
+ for(i=0; i < n && array[i] && oa[i]; ++i)
if (array[i] != oa[i])
return false;
@@ -1350,7 +1350,7 @@ public:
if (!str)
return false;
u32 i;
- for(i=0; array[i] && str[i] && i < n; ++i)
+ for(i=0; i < n && array[i] && str[i]; ++i)
if (array[i] != str[i])
return false;
diff --git a/src/map.cpp b/src/map.cpp
index 6d53351ef..a80e7ff92 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1250,6 +1250,8 @@ ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef,
m_save_time_counter = mb->addCounter("minetest_core_map_save_time", "Map save time (in nanoseconds)");
+ m_map_compression_level = rangelim(g_settings->getS16("map_compression_level_disk"), -1, 9);
+
try {
// If directory exists, check contents and load if possible
if (fs::PathExists(m_savedir)) {
@@ -1863,10 +1865,10 @@ void ServerMap::endSave()
bool ServerMap::saveBlock(MapBlock *block)
{
- return saveBlock(block, dbase);
+ return saveBlock(block, dbase, m_map_compression_level);
}
-bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db)
+bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db, int compression_level)
{
v3s16 p3d = block->getPos();
@@ -1886,7 +1888,7 @@ bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db)
*/
std::ostringstream o(std::ios_base::binary);
o.write((char*) &version, 1);
- block->serialize(o, version, true);
+ block->serialize(o, version, true, compression_level);
bool ret = db->saveBlock(p3d, o.str());
if (ret) {
diff --git a/src/map.h b/src/map.h
index 0b0213ca0..821e638c1 100644
--- a/src/map.h
+++ b/src/map.h
@@ -382,7 +382,7 @@ public:
MapgenParams *getMapgenParams();
bool saveBlock(MapBlock *block);
- static bool saveBlock(MapBlock *block, MapDatabase *db);
+ static bool saveBlock(MapBlock *block, MapDatabase *db, int compression_level = -1);
MapBlock* loadBlock(v3s16 p);
// Database version
void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
@@ -417,6 +417,7 @@ private:
std::string m_savedir;
bool m_map_saving_enabled;
+ int m_map_compression_level;
#if 0
// Chunk size in MapSectors
// If 0, chunks are disabled.
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 8bfecd755..0ca71e643 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -355,7 +355,7 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
}
}
-void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
+void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compression_level)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapBlock format not supported");
@@ -394,7 +394,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
writeU8(os, content_width);
writeU8(os, params_width);
MapNode::serializeBulk(os, version, tmp_nodes, nodecount,
- content_width, params_width, true);
+ content_width, params_width, compression_level);
delete[] tmp_nodes;
}
else
@@ -404,7 +404,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
writeU8(os, content_width);
writeU8(os, params_width);
MapNode::serializeBulk(os, version, data, nodecount,
- content_width, params_width, true);
+ content_width, params_width, compression_level);
}
/*
@@ -412,7 +412,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
*/
std::ostringstream oss(std::ios_base::binary);
m_node_metadata.serialize(oss, version, disk);
- compressZlib(oss.str(), os);
+ compressZlib(oss.str(), os, compression_level);
/*
Data that goes to disk, but not the network
@@ -485,7 +485,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
if(params_width != 2)
throw SerializationError("MapBlock::deSerialize(): invalid params_width");
MapNode::deSerializeBulk(is, version, data, nodecount,
- content_width, params_width, true);
+ content_width, params_width);
/*
NodeMetadata
diff --git a/src/mapblock.h b/src/mapblock.h
index 6b5015cab..641a1b69b 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -482,7 +482,7 @@ public:
// These don't write or read version by itself
// Set disk to true for on-disk format, false for over-the-network format
// Precondition: version >= SER_FMT_VER_LOWEST_WRITE
- void serialize(std::ostream &os, u8 version, bool disk);
+ void serialize(std::ostream &os, u8 version, bool disk, int compression_level);
// If disk == true: In addition to doing other things, will add
// unknown blocks from id-name mapping to wndef
void deSerialize(std::istream &is, u8 version, bool disk);
diff --git a/src/mapgen/mapgen_v7.cpp b/src/mapgen/mapgen_v7.cpp
index cc5f5726d..91f004518 100644
--- a/src/mapgen/mapgen_v7.cpp
+++ b/src/mapgen/mapgen_v7.cpp
@@ -297,7 +297,7 @@ int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
int iters = 256;
while (iters > 0 && y <= max_spawn_y) {
if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) {
- if (y <= water_level || y > max_spawn_y)
+ if (y <= water_level)
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
// y + 1 due to biome 'dust'
diff --git a/src/mapgen/mg_schematic.cpp b/src/mapgen/mg_schematic.cpp
index dfd414709..e70e97e48 100644
--- a/src/mapgen/mg_schematic.cpp
+++ b/src/mapgen/mg_schematic.cpp
@@ -334,7 +334,7 @@ bool Schematic::deserializeFromMts(std::istream *is,
schemdata = new MapNode[nodecount];
MapNode::deSerializeBulk(ss, SER_FMT_VER_HIGHEST_READ, schemdata,
- nodecount, 2, 2, true);
+ nodecount, 2, 2);
// Fix probability values for nodes that were ignore; removed in v2
if (version < 2) {
@@ -376,7 +376,7 @@ bool Schematic::serializeToMts(std::ostream *os,
// compressed bulk node data
MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE,
- schemdata, size.X * size.Y * size.Z, 2, 2, true);
+ schemdata, size.X * size.Y * size.Z, 2, 2, -1);
return true;
}
diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp
index e633d800a..ec7771439 100644
--- a/src/mapgen/treegen.cpp
+++ b/src/mapgen/treegen.cpp
@@ -406,7 +406,8 @@ treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
v3f(position.X, position.Y, position.Z - 1),
tree_definition
);
- } if (!stack_orientation.empty()) {
+ }
+ if (!stack_orientation.empty()) {
s16 size = 1;
for (x = -size; x <= size; x++)
for (y = -size; y <= size; y++)
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index dcf1f6d6e..0551f3b6f 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -706,7 +706,7 @@ void MapNode::deSerialize(u8 *source, u8 version)
}
void MapNode::serializeBulk(std::ostream &os, int version,
const MapNode *nodes, u32 nodecount,
- u8 content_width, u8 params_width, bool compressed)
+ u8 content_width, u8 params_width, int compression_level)
{
if (!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported");
@@ -737,10 +737,7 @@ void MapNode::serializeBulk(std::ostream &os, int version,
Compress data to output stream
*/
- if (compressed)
- compressZlib(databuf, databuf_size, os);
- else
- os.write((const char*) &databuf[0], databuf_size);
+ compressZlib(databuf, databuf_size, os, compression_level);
delete [] databuf;
}
@@ -748,7 +745,7 @@ void MapNode::serializeBulk(std::ostream &os, int version,
// Deserialize bulk node data
void MapNode::deSerializeBulk(std::istream &is, int version,
MapNode *nodes, u32 nodecount,
- u8 content_width, u8 params_width, bool compressed)
+ u8 content_width, u8 params_width)
{
if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported");
@@ -760,24 +757,13 @@ void MapNode::deSerializeBulk(std::istream &is, int version,
// Uncompress or read data
u32 len = nodecount * (content_width + params_width);
- SharedBuffer<u8> databuf(len);
- if(compressed)
- {
- std::ostringstream os(std::ios_base::binary);
- decompressZlib(is, os);
- std::string s = os.str();
- if(s.size() != len)
- throw SerializationError("deSerializeBulkNodes: "
- "decompress resulted in invalid size");
- memcpy(&databuf[0], s.c_str(), len);
- }
- else
- {
- is.read((char*) &databuf[0], len);
- if(is.eof() || is.fail())
- throw SerializationError("deSerializeBulkNodes: "
- "failed to read bulk node data");
- }
+ std::ostringstream os(std::ios_base::binary);
+ decompressZlib(is, os);
+ std::string s = os.str();
+ if(s.size() != len)
+ throw SerializationError("deSerializeBulkNodes: "
+ "decompress resulted in invalid size");
+ const u8 *databuf = reinterpret_cast<const u8*>(s.c_str());
// Deserialize content
if(content_width == 1)
diff --git a/src/mapnode.h b/src/mapnode.h
index 32ac1b4f6..a9ae63ba3 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -292,10 +292,10 @@ struct MapNode
// compressed = true to zlib-compress output
static void serializeBulk(std::ostream &os, int version,
const MapNode *nodes, u32 nodecount,
- u8 content_width, u8 params_width, bool compressed);
+ u8 content_width, u8 params_width, int compression_level);
static void deSerializeBulk(std::istream &is, int version,
MapNode *nodes, u32 nodecount,
- u8 content_width, u8 params_width, bool compressed);
+ u8 content_width, u8 params_width);
private:
// Deprecated serialization methods
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index 98d143c89..88a5ac177 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -226,22 +226,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
// base64-encoded SHA-1 (27+\0).
-/*
- Changes by FORMSPEC_API_VERSION:
-
- 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
-*/
+// See also: Formspec Version History in doc/lua_api.txt
#define FORMSPEC_API_VERSION 4
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"
diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp
index 3db4eb286..c636d01e1 100644
--- a/src/network/serverpackethandler.cpp
+++ b/src/network/serverpackethandler.cpp
@@ -316,7 +316,7 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
// Send active objects
{
PlayerSAO *sao = getPlayerSAO(peer_id);
- if (client && sao)
+ if (sao)
SendActiveObjectRemoveAdd(client, sao);
}
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 4d4fc7a7a..bc00d5637 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -617,7 +617,7 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer,
bool has_scale = tiledef.scale > 0;
bool use_autoscale = tsettings.autoscale_mode == AUTOSCALE_FORCE ||
(tsettings.autoscale_mode == AUTOSCALE_ENABLE && !has_scale);
- if (use_autoscale && layer->texture) {
+ if (use_autoscale) {
auto texture_size = layer->texture->getOriginalSize();
float base_size = tsettings.node_texture_size;
float size = std::fmin(texture_size.Width, texture_size.Height);
@@ -774,7 +774,7 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
bool is_liquid = false;
- u8 material_type = (alpha == 255) ?
+ MaterialType material_type = (alpha == 255) ?
TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
switch (drawtype) {
@@ -892,7 +892,7 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
u32 tile_shader = shdsrc->getShader("nodes_shader", material_type, drawtype);
- u8 overlay_material = material_type;
+ MaterialType overlay_material = material_type;
if (overlay_material == TILE_MATERIAL_OPAQUE)
overlay_material = TILE_MATERIAL_BASIC;
else if (overlay_material == TILE_MATERIAL_LIQUID_OPAQUE)
@@ -913,7 +913,7 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
tdef[j].backface_culling, tsettings);
}
- u8 special_material = material_type;
+ MaterialType special_material = material_type;
if (drawtype == NDT_PLANTLIKE_ROOTED) {
if (waving == 1)
special_material = TILE_MATERIAL_WAVING_PLANTS;
diff --git a/src/porting.cpp b/src/porting.cpp
index e7ed4e090..4c87bddee 100644
--- a/src/porting.cpp
+++ b/src/porting.cpp
@@ -719,29 +719,48 @@ int mt_snprintf(char *buf, const size_t buf_size, const char *fmt, ...)
return c;
}
-bool openURL(const std::string &url)
+static bool open_uri(const std::string &uri)
{
- if ((url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://") ||
- url.find_first_of("\r\n") != std::string::npos) {
- errorstream << "Invalid url: " << url << std::endl;
+ if (uri.find_first_of("\r\n") != std::string::npos) {
+ errorstream << "Unable to open URI as it is invalid, contains new line: " << uri << std::endl;
return false;
}
#if defined(_WIN32)
- return (intptr_t)ShellExecuteA(NULL, NULL, url.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32;
+ return (intptr_t)ShellExecuteA(NULL, NULL, uri.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32;
#elif defined(__ANDROID__)
- openURLAndroid(url);
+ openURIAndroid(uri);
return true;
#elif defined(__APPLE__)
- const char *argv[] = {"open", url.c_str(), NULL};
+ const char *argv[] = {"open", uri.c_str(), NULL};
return posix_spawnp(NULL, "open", NULL, NULL, (char**)argv,
(*_NSGetEnviron())) == 0;
#else
- const char *argv[] = {"xdg-open", url.c_str(), NULL};
+ const char *argv[] = {"xdg-open", uri.c_str(), NULL};
return posix_spawnp(NULL, "xdg-open", NULL, NULL, (char**)argv, environ) == 0;
#endif
}
+bool open_url(const std::string &url)
+{
+ if (url.substr(0, 7) != "http://" && url.substr(0, 8) != "https://") {
+ errorstream << "Unable to open browser as URL is missing schema: " << url << std::endl;
+ return false;
+ }
+
+ return open_uri(url);
+}
+
+bool open_directory(const std::string &path)
+{
+ if (!fs::IsDir(path)) {
+ errorstream << "Unable to open directory as it does not exist: " << path << std::endl;
+ return false;
+ }
+
+ return open_uri(path);
+}
+
// Load performance counter frequency only once at startup
#ifdef _WIN32
diff --git a/src/porting.h b/src/porting.h
index c7adf12a2..e4ebe36fd 100644
--- a/src/porting.h
+++ b/src/porting.h
@@ -332,7 +332,25 @@ void attachOrCreateConsole();
int mt_snprintf(char *buf, const size_t buf_size, const char *fmt, ...);
-bool openURL(const std::string &url);
+/**
+ * Opens URL in default web browser
+ *
+ * Must begin with http:// or https://, and not contain any new lines
+ *
+ * @param url The URL
+ * @return true on success, false on failure
+ */
+bool open_url(const std::string &url);
+
+/**
+ * Opens a directory in the default file manager
+ *
+ * The directory must exist.
+ *
+ * @param path Path to directory
+ * @return true on success, false on failure
+ */
+bool open_directory(const std::string &path);
} // namespace porting
diff --git a/src/porting_android.cpp b/src/porting_android.cpp
index 41b521ec2..f5870c174 100644
--- a/src/porting_android.cpp
+++ b/src/porting_android.cpp
@@ -213,13 +213,13 @@ void showInputDialog(const std::string &acceptButton, const std::string &hint,
jacceptButton, jhint, jcurrent, jeditType);
}
-void openURLAndroid(const std::string &url)
+void openURIAndroid(const std::string &url)
{
- jmethodID url_open = jnienv->GetMethodID(nativeActivity, "openURL",
+ jmethodID url_open = jnienv->GetMethodID(nativeActivity, "openURI",
"(Ljava/lang/String;)V");
FATAL_ERROR_IF(url_open == nullptr,
- "porting::openURLAndroid unable to find java openURL method");
+ "porting::openURIAndroid unable to find java openURI method");
jstring jurl = jnienv->NewStringUTF(url.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
diff --git a/src/porting_android.h b/src/porting_android.h
index 6eb054041..239815922 100644
--- a/src/porting_android.h
+++ b/src/porting_android.h
@@ -58,7 +58,7 @@ void initializePathsAndroid();
void showInputDialog(const std::string &acceptButton,
const std::string &hint, const std::string &current, int editType);
-void openURLAndroid(const std::string &url);
+void openURIAndroid(const std::string &url);
/**
* WORKAROUND for not working callbacks from java -> c++
diff --git a/src/profiler.cpp b/src/profiler.cpp
index be8be591e..d05b7abfe 100644
--- a/src/profiler.cpp
+++ b/src/profiler.cpp
@@ -38,7 +38,7 @@ ScopeProfiler::~ScopeProfiler()
return;
float duration_ms = m_timer->stop(true);
- float duration = duration_ms / 1000.0;
+ float duration = duration_ms;
if (m_profiler) {
switch (m_type) {
case SPT_ADD:
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index ea9320051..746f7013e 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -103,6 +103,32 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
lua_pop(L, 2); // Pop object and error handler
}
+void ScriptApiEntity::luaentity_Deactivate(u16 id)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ verbosestream << "scriptapi_luaentity_deactivate: id=" << id << std::endl;
+
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
+ // Get the entity
+ luaentity_get(L, id);
+ int object = lua_gettop(L);
+
+ // Get on_deactivate
+ lua_getfield(L, -1, "on_deactivate");
+ if (!lua_isnil(L, -1)) {
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_pushvalue(L, object);
+
+ setOriginFromTable(object);
+ PCALL_RES(lua_pcall(L, 1, 0, error_handler));
+ } else {
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 2); // Pop object and error handler
+}
+
void ScriptApiEntity::luaentity_Remove(u16 id)
{
SCRIPTAPI_PRECHECKHEADER
diff --git a/src/script/cpp_api/s_entity.h b/src/script/cpp_api/s_entity.h
index b5f7a6586..b52f6e447 100644
--- a/src/script/cpp_api/s_entity.h
+++ b/src/script/cpp_api/s_entity.h
@@ -33,6 +33,7 @@ public:
bool luaentity_Add(u16 id, const char *name);
void luaentity_Activate(u16 id,
const std::string &staticdata, u32 dtime_s);
+ void luaentity_Deactivate(u16 id);
void luaentity_Remove(u16 id);
std::string luaentity_GetStaticdata(u16 id);
void luaentity_GetProperties(u16 id,
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index d5db43db9..37c5b61dc 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -401,10 +401,9 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
lua_pushfstring(L, "%s: %s", path, strerror(errno));
return false;
}
- chunk_name = new char[strlen(display_name) + 2];
- chunk_name[0] = '@';
- chunk_name[1] = '\0';
- strcat(chunk_name, display_name);
+ size_t len = strlen(display_name) + 2;
+ chunk_name = new char[len];
+ snprintf(chunk_name, len, "@%s", display_name);
}
size_t start = 0;
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index dbb0a5ab7..d6dc79ca8 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -743,6 +743,31 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
return 1;
}
+// get_objects_in_area(pos, minp, maxp)
+int ModApiEnvMod::l_get_objects_in_area(lua_State *L)
+{
+ GET_ENV_PTR;
+ ScriptApiBase *script = getScriptApiBase(L);
+
+ v3f minp = read_v3f(L, 1) * BS;
+ v3f maxp = read_v3f(L, 2) * BS;
+ aabb3f box(minp, maxp);
+ box.repair();
+ std::vector<ServerActiveObject *> objs;
+
+ auto include_obj_cb = [](ServerActiveObject *obj){ return !obj->isGone(); };
+ env->getObjectsInArea(objs, box, include_obj_cb);
+
+ int i = 0;
+ lua_createtable(L, objs.size(), 0);
+ for (const auto obj : objs) {
+ // Insert object reference into table
+ script->objectrefGetOrCreate(L, obj);
+ lua_rawseti(L, -2, ++i);
+ }
+ return 1;
+}
+
// set_timeofday(val)
// val = 0...1
int ModApiEnvMod::l_set_timeofday(lua_State *L)
@@ -1571,6 +1596,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(get_node_timer);
API_FCT(get_connected_players);
API_FCT(get_player_by_name);
+ API_FCT(get_objects_in_area);
API_FCT(get_objects_inside_radius);
API_FCT(set_timeofday);
API_FCT(get_timeofday);
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index ad9a0f509..29044c0e8 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -114,6 +114,9 @@ private:
// get_objects_inside_radius(pos, radius)
static int l_get_objects_inside_radius(lua_State *L);
+
+ // get_objects_in_area(pos, minp, maxp)
+ static int l_get_objects_in_area(lua_State *L);
// set_timeofday(val)
// val = 0...1
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 2cf4a979b..3ea5eb4ba 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -687,6 +687,14 @@ int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
/******************************************************************************/
+int ModApiMainMenu::l_get_user_path(lua_State *L)
+{
+ std::string path = fs::RemoveRelativePathComponents(porting::path_user);
+ lua_pushstring(L, path.c_str());
+ return 1;
+}
+
+/******************************************************************************/
int ModApiMainMenu::l_get_modpath(lua_State *L)
{
std::string modpath = fs::RemoveRelativePathComponents(
@@ -796,6 +804,15 @@ int ModApiMainMenu::l_copy_dir(lua_State *L)
}
/******************************************************************************/
+int ModApiMainMenu::l_is_dir(lua_State *L)
+{
+ const char *path = luaL_checkstring(L, 1);
+
+ lua_pushboolean(L, fs::IsDir(path));
+ return 1;
+}
+
+/******************************************************************************/
int ModApiMainMenu::l_extract_zip(lua_State *L)
{
const char *zipfile = luaL_checkstring(L, 1);
@@ -1070,7 +1087,15 @@ int ModApiMainMenu::l_get_max_supp_proto(lua_State *L)
int ModApiMainMenu::l_open_url(lua_State *L)
{
std::string url = luaL_checkstring(L, 1);
- lua_pushboolean(L, porting::openURL(url));
+ lua_pushboolean(L, porting::open_url(url));
+ return 1;
+}
+
+/******************************************************************************/
+int ModApiMainMenu::l_open_dir(lua_State *L)
+{
+ std::string path = luaL_checkstring(L, 1);
+ lua_pushboolean(L, porting::open_directory(path));
return 1;
}
@@ -1116,6 +1141,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(set_background);
API_FCT(set_topleft_text);
API_FCT(get_mapgen_names);
+ API_FCT(get_user_path);
API_FCT(get_modpath);
API_FCT(get_clientmodpath);
API_FCT(get_gamepath);
@@ -1125,6 +1151,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(create_dir);
API_FCT(delete_dir);
API_FCT(copy_dir);
+ API_FCT(is_dir);
API_FCT(extract_zip);
API_FCT(may_modify_path);
API_FCT(get_mainmenu_path);
@@ -1137,6 +1164,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(get_min_supp_proto);
API_FCT(get_max_supp_proto);
API_FCT(open_url);
+ API_FCT(open_dir);
API_FCT(do_async_callback);
}
@@ -1147,6 +1175,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(get_games);
API_FCT(get_favorites);
API_FCT(get_mapgen_names);
+ API_FCT(get_user_path);
API_FCT(get_modpath);
API_FCT(get_clientmodpath);
API_FCT(get_gamepath);
@@ -1156,6 +1185,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(create_dir);
API_FCT(delete_dir);
API_FCT(copy_dir);
+ API_FCT(is_dir);
//API_FCT(extract_zip); //TODO remove dependency to GuiEngine
API_FCT(may_modify_path);
API_FCT(download_file);
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index 5a16b3bfe..0b02ed892 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -112,6 +112,8 @@ private:
static int l_get_mainmenu_path(lua_State *L);
+ static int l_get_user_path(lua_State *L);
+
static int l_get_modpath(lua_State *L);
static int l_get_clientmodpath(lua_State *L);
@@ -130,6 +132,8 @@ private:
static int l_copy_dir(lua_State *L);
+ static int l_is_dir(lua_State *L);
+
static int l_extract_zip(lua_State *L);
static int l_may_modify_path(lua_State *L);
@@ -148,6 +152,8 @@ private:
// other
static int l_open_url(lua_State *L);
+ static int l_open_dir(lua_State *L);
+
// async
static int l_do_async_callback(lua_State *L);
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index bc59bd55c..f52e4892e 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -110,7 +110,7 @@ int ObjectRef::l_remove(lua_State *L)
sao->clearParentAttachment();
verbosestream << "ObjectRef::l_remove(): id=" << sao->getId() << std::endl;
- sao->m_pending_removal = true;
+ sao->markForRemoval();
return 0;
}
@@ -1409,7 +1409,7 @@ int ObjectRef::l_set_physics_override(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
- PlayerSAO *playersao = (PlayerSAO *) getobject(ref);
+ PlayerSAO *playersao = getplayersao(ref);
if (playersao == nullptr)
return 0;
@@ -1449,7 +1449,7 @@ int ObjectRef::l_get_physics_override(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
- PlayerSAO *playersao = (PlayerSAO *)getobject(ref);
+ PlayerSAO *playersao = getplayersao(ref);
if (playersao == nullptr)
return 0;
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index 4595dc1c1..e2730c6d9 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -239,15 +239,6 @@ int ModApiUtil::l_is_yes(lua_State *L)
return 1;
}
-// is_nan(arg)
-int ModApiUtil::l_is_nan(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
-
- lua_pushboolean(L, isNaN(L, 1));
- return 1;
-}
-
// get_builtin_path()
int ModApiUtil::l_get_builtin_path(lua_State *L)
{
@@ -493,7 +484,6 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(get_password_hash);
API_FCT(is_yes);
- API_FCT(is_nan);
API_FCT(get_builtin_path);
@@ -526,8 +516,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(write_json);
API_FCT(is_yes);
- API_FCT(is_nan);
-
+
API_FCT(compress);
API_FCT(decompress);
@@ -538,7 +527,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(get_version);
API_FCT(sha1);
-
+
LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings");
}
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index 9ff91bb53..b6c1b58af 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -65,9 +65,6 @@ private:
// is_yes(arg)
static int l_is_yes(lua_State *L);
- // is_nan(arg)
- static int l_is_nan(lua_State *L);
-
// get_builtin_path()
static int l_get_builtin_path(lua_State *L);
diff --git a/src/server.cpp b/src/server.cpp
index 8f6257afe..b5352749c 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -2332,9 +2332,9 @@ void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
/*
Create a packet with the block in the right format
*/
-
+ thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
std::ostringstream os(std::ios_base::binary);
- block->serialize(os, ver, false);
+ block->serialize(os, ver, false, net_compression_level);
block->serializeNetworkSpecific(os);
std::string s = os.str();
diff --git a/src/server/activeobjectmgr.cpp b/src/server/activeobjectmgr.cpp
index 1b8e31409..acd6611f4 100644
--- a/src/server/activeobjectmgr.cpp
+++ b/src/server/activeobjectmgr.cpp
@@ -127,6 +127,21 @@ void ActiveObjectMgr::getObjectsInsideRadius(const v3f &pos, float radius,
}
}
+void ActiveObjectMgr::getObjectsInArea(const aabb3f &box,
+ std::vector<ServerActiveObject *> &result,
+ std::function<bool(ServerActiveObject *obj)> include_obj_cb)
+{
+ for (auto &activeObject : m_active_objects) {
+ ServerActiveObject *obj = activeObject.second;
+ const v3f &objectpos = obj->getBasePosition();
+ if (!box.isPointInside(objectpos))
+ continue;
+
+ if (!include_obj_cb || include_obj_cb(obj))
+ result.push_back(obj);
+ }
+}
+
void ActiveObjectMgr::getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius,
f32 player_radius, std::set<u16> &current_objects,
std::queue<u16> &added_objects)
diff --git a/src/server/activeobjectmgr.h b/src/server/activeobjectmgr.h
index bc2085499..d43f5643c 100644
--- a/src/server/activeobjectmgr.h
+++ b/src/server/activeobjectmgr.h
@@ -38,6 +38,9 @@ public:
void getObjectsInsideRadius(const v3f &pos, float radius,
std::vector<ServerActiveObject *> &result,
std::function<bool(ServerActiveObject *obj)> include_obj_cb);
+ void getObjectsInArea(const aabb3f &box,
+ std::vector<ServerActiveObject *> &result,
+ std::function<bool(ServerActiveObject *obj)> include_obj_cb);
void getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius,
f32 player_radius, std::set<u16> &current_objects,
diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp
index b39797531..c7277491a 100644
--- a/src/server/luaentity_sao.cpp
+++ b/src/server/luaentity_sao.cpp
@@ -112,6 +112,15 @@ void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
}
}
+void LuaEntitySAO::dispatchScriptDeactivate()
+{
+ // Ensure that this is in fact a registered entity,
+ // and that it isn't already gone.
+ // The latter also prevents this from ever being called twice.
+ if (m_registered && !isGone())
+ m_env->getScriptIface()->luaentity_Deactivate(m_id);
+}
+
void LuaEntitySAO::step(float dtime, bool send_recommended)
{
if(!m_properties_sent)
@@ -302,7 +311,7 @@ u16 LuaEntitySAO::punch(v3f dir,
{
if (!m_registered) {
// Delete unknown LuaEntities when punched
- m_pending_removal = true;
+ markForRemoval();
return 0;
}
@@ -335,7 +344,7 @@ u16 LuaEntitySAO::punch(v3f dir,
clearParentAttachment();
clearChildAttachments();
m_env->getScriptIface()->luaentity_on_death(m_id, puncher);
- m_pending_removal = true;
+ markForRemoval();
}
actionstream << puncher->getDescription() << " (id=" << puncher->getId() <<
diff --git a/src/server/luaentity_sao.h b/src/server/luaentity_sao.h
index e060aa06d..6883ae1b9 100644
--- a/src/server/luaentity_sao.h
+++ b/src/server/luaentity_sao.h
@@ -71,6 +71,11 @@ public:
bool getSelectionBox(aabb3f *toset) const;
bool collideWithObjects() const;
+protected:
+ void dispatchScriptDeactivate();
+ virtual void onMarkedForDeactivation() { dispatchScriptDeactivate(); }
+ virtual void onMarkedForRemoval() { dispatchScriptDeactivate(); }
+
private:
std::string getPropertyPacket();
void sendPosition(bool do_interpolate, bool is_movement_end);
diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp
index 62515d1c9..232c6a01d 100644
--- a/src/server/player_sao.cpp
+++ b/src/server/player_sao.cpp
@@ -531,7 +531,7 @@ bool PlayerSAO::setWieldedItem(const ItemStack &item)
void PlayerSAO::disconnected()
{
m_peer_id = PEER_ID_INEXISTENT;
- m_pending_removal = true;
+ markForRemoval();
}
void PlayerSAO::unlinkPlayerSessionAndSave()
diff --git a/src/server/serveractiveobject.cpp b/src/server/serveractiveobject.cpp
index 8cb59b2d6..96b433d1d 100644
--- a/src/server/serveractiveobject.cpp
+++ b/src/server/serveractiveobject.cpp
@@ -73,3 +73,19 @@ void ServerActiveObject::dumpAOMessagesToQueue(std::queue<ActiveObjectMessage> &
m_messages_out.pop();
}
}
+
+void ServerActiveObject::markForRemoval()
+{
+ if (!m_pending_removal) {
+ onMarkedForRemoval();
+ m_pending_removal = true;
+ }
+}
+
+void ServerActiveObject::markForDeactivation()
+{
+ if (!m_pending_deactivation) {
+ onMarkedForDeactivation();
+ m_pending_deactivation = true;
+ }
+}
diff --git a/src/server/serveractiveobject.h b/src/server/serveractiveobject.h
index 2764d159e..25653a1ad 100644
--- a/src/server/serveractiveobject.h
+++ b/src/server/serveractiveobject.h
@@ -70,6 +70,10 @@ public:
virtual bool environmentDeletes() const
{ return true; }
+ // Safely mark the object for removal or deactivation
+ void markForRemoval();
+ void markForDeactivation();
+
// Create a certain type of ServerActiveObject
static ServerActiveObject* create(ActiveObjectType type,
ServerEnvironment *env, u16 id, v3f pos,
@@ -214,31 +218,15 @@ public:
u16 m_known_by_count = 0;
/*
- - Whether this object is to be removed when nobody knows about
- it anymore.
- - Removal is delayed to preserve the id for the time during which
- it could be confused to some other object by some client.
- - This is usually set to true by the step() method when the object wants
- to be deleted but can be set by anything else too.
- */
- bool m_pending_removal = false;
-
- /*
- Same purpose as m_pending_removal but for deactivation.
- deactvation = save static data in block, remove active object
-
- If this is set alongside with m_pending_removal, removal takes
- priority.
- */
- bool m_pending_deactivation = false;
-
- /*
A getter that unifies the above to answer the question:
"Can the environment still interact with this object?"
*/
inline bool isGone() const
{ return m_pending_removal || m_pending_deactivation; }
+ inline bool isPendingRemoval() const
+ { return m_pending_removal; }
+
/*
Whether the object's static data has been stored to a block
*/
@@ -250,6 +238,9 @@ public:
v3s16 m_static_block = v3s16(1337,1337,1337);
protected:
+ virtual void onMarkedForDeactivation() {}
+ virtual void onMarkedForRemoval() {}
+
virtual void onAttach(int parent_id) {}
virtual void onDetach(int parent_id) {}
@@ -258,6 +249,27 @@ protected:
std::unordered_set<u32> m_attached_particle_spawners;
/*
+ Same purpose as m_pending_removal but for deactivation.
+ deactvation = save static data in block, remove active object
+
+ If this is set alongside with m_pending_removal, removal takes
+ priority.
+ Note: Do not assign this directly, use markForDeactivation() instead.
+ */
+ bool m_pending_deactivation = false;
+
+ /*
+ - Whether this object is to be removed when nobody knows about
+ it anymore.
+ - Removal is delayed to preserve the id for the time during which
+ it could be confused to some other object by some client.
+ - This is usually set to true by the step() method when the object wants
+ to be deleted but can be set by anything else too.
+ Note: Do not assign this directly, use markForRemoval() instead.
+ */
+ bool m_pending_removal = false;
+
+ /*
Queue of messages to be sent to the client
*/
std::queue<ActiveObjectMessage> m_messages_out;
diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp
index d044b003d..56dbb0632 100644
--- a/src/serverenvironment.cpp
+++ b/src/serverenvironment.cpp
@@ -1164,7 +1164,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
// If known by some client, don't delete immediately
if (obj->m_known_by_count > 0) {
- obj->m_pending_removal = true;
+ obj->markForRemoval();
return false;
}
@@ -1792,7 +1792,7 @@ void ServerEnvironment::removeRemovedObjects()
/*
Delete static data from block if removed
*/
- if (obj->m_pending_removal)
+ if (obj->isPendingRemoval())
deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
// If still known by clients, don't actually remove. On some future
@@ -1803,7 +1803,7 @@ void ServerEnvironment::removeRemovedObjects()
/*
Move static data from active to stored if deactivated
*/
- if (!obj->m_pending_removal && obj->m_static_exists) {
+ if (!obj->isPendingRemoval() && obj->m_static_exists) {
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
if (block) {
const auto i = block->m_static_objects.m_active.find(id);
@@ -1991,6 +1991,7 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
if (!force_delete && obj->m_static_exists &&
!m_active_blocks.contains(obj->m_static_block) &&
m_active_blocks.contains(blockpos_o)) {
+
// Delete from block where object was located
deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
@@ -2068,6 +2069,10 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
force_delete = true;
}
+ // Regardless of what happens to the object at this point, deactivate it first.
+ // This ensures that LuaEntity on_deactivate is always called.
+ obj->markForDeactivation();
+
/*
If known by some client, set pending deactivation.
Otherwise delete it immediately.
@@ -2077,7 +2082,6 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
<< "object id=" << id << " is known by clients"
<< "; not deleting yet" << std::endl;
- obj->m_pending_deactivation = true;
return false;
}
diff --git a/src/serverenvironment.h b/src/serverenvironment.h
index cfd5b8f3e..c76d34a37 100644
--- a/src/serverenvironment.h
+++ b/src/serverenvironment.h
@@ -331,6 +331,13 @@ public:
{
return m_ao_manager.getObjectsInsideRadius(pos, radius, objects, include_obj_cb);
}
+
+ // Find all active objects inside a box
+ void getObjectsInArea(std::vector<ServerActiveObject *> &objects, const aabb3f &box,
+ std::function<bool(ServerActiveObject *obj)> include_obj_cb)
+ {
+ return m_ao_manager.getObjectsInArea(box, objects, include_obj_cb);
+ }
// Clear objects, loading and going through every MapBlock
void clearObjects(ClearObjectsMode mode);
diff --git a/src/util/srp.cpp b/src/util/srp.cpp
index f4d369d68..ceb2fef9e 100644
--- a/src/util/srp.cpp
+++ b/src/util/srp.cpp
@@ -1015,10 +1015,10 @@ void srp_user_process_challenge(struct SRPUser *usr,
goto cleanup_and_exit;
*bytes_M = usr->M;
- if (len_M) *len_M = hash_length(usr->hash_alg);
+ *len_M = hash_length(usr->hash_alg);
} else {
*bytes_M = NULL;
- if (len_M) *len_M = 0;
+ *len_M = 0;
}
cleanup_and_exit:
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 8381a29c5..3ac3b8cf0 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -633,7 +633,7 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
color_name = value;
}
- color_name = lowercase(value);
+ color_name = lowercase(color_name);
std::map<const std::string, unsigned>::const_iterator it;
it = named_colors.colors.find(color_name);
diff --git a/textures/base/pack/cdb_add.png b/textures/base/pack/cdb_add.png
new file mode 100644
index 000000000..3e3d067e3
--- /dev/null
+++ b/textures/base/pack/cdb_add.png
Binary files differ
diff --git a/textures/base/pack/cdb_clear.png b/textures/base/pack/cdb_clear.png
new file mode 100644
index 000000000..4490d41cb
--- /dev/null
+++ b/textures/base/pack/cdb_clear.png
Binary files differ
diff --git a/textures/base/pack/cdb_downloading.png b/textures/base/pack/cdb_downloading.png
new file mode 100644
index 000000000..8cba383cc
--- /dev/null
+++ b/textures/base/pack/cdb_downloading.png
Binary files differ
diff --git a/textures/base/pack/cdb_queued.png b/textures/base/pack/cdb_queued.png
new file mode 100644
index 000000000..6972f7fb8
--- /dev/null
+++ b/textures/base/pack/cdb_queued.png
Binary files differ
diff --git a/textures/base/pack/cdb_update.png b/textures/base/pack/cdb_update.png
new file mode 100644
index 000000000..262e42d3b
--- /dev/null
+++ b/textures/base/pack/cdb_update.png
Binary files differ
diff --git a/textures/base/pack/cdb_viewonline.png b/textures/base/pack/cdb_viewonline.png
new file mode 100644
index 000000000..ae2a146b8
--- /dev/null
+++ b/textures/base/pack/cdb_viewonline.png
Binary files differ
diff --git a/textures/base/pack/clear.png b/textures/base/pack/clear.png
new file mode 100644
index 000000000..9244264ad
--- /dev/null
+++ b/textures/base/pack/clear.png
Binary files differ
diff --git a/textures/base/pack/search.png b/textures/base/pack/search.png
new file mode 100644
index 000000000..aace8044a
--- /dev/null
+++ b/textures/base/pack/search.png
Binary files differ
diff --git a/util/ci/common.sh b/util/ci/common.sh
index a2e4beac9..7523fa7ff 100644
--- a/util/ci/common.sh
+++ b/util/ci/common.sh
@@ -7,13 +7,9 @@ install_linux_deps() {
libhiredis-dev libogg-dev libgmp-dev libvorbis-dev libopenal-dev \
gettext libpq-dev postgresql-server-dev-all libleveldb-dev \
libcurl4-openssl-dev)
- # for better coverage, build some jobs with luajit
- if [ -n "$WITH_LUAJIT" ]; then
- pkgs+=(libluajit-5.1-dev)
- fi
sudo apt-get update
- sudo apt-get install -y --no-install-recommends ${pkgs[@]}
+ sudo apt-get install -y --no-install-recommends ${pkgs[@]} "$@"
}
# Mac OSX build only