This commit is contained in:
Elias Fleckenstein 2021-01-07 12:35:04 +01:00
commit cca4254f7c
109 changed files with 1547 additions and 1248 deletions

View File

@ -33,9 +33,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install g++-6 gcc-6 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps g++-6
- name: Build - name: Build
run: | run: |
@ -55,9 +54,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install g++-8 gcc-8 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps g++-8
- name: Build - name: Build
run: | run: |
@ -77,9 +75,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-3.9 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps clang-3.9
- name: Build - name: Build
run: | run: |
@ -99,11 +96,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-9 valgrind -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps clang-9 valgrind libluajit-5.1-dev
env:
WITH_LUAJIT: 1
- name: Build - name: Build
run: | run: |
@ -111,6 +105,7 @@ jobs:
env: env:
CC: clang-9 CC: clang-9
CXX: clang++-9 CXX: clang++-9
CMAKE_FLAGS: "-DREQUIRE_LUAJIT=1"
- name: Test - name: Test
run: | run: |
@ -128,9 +123,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps clang-9
- name: Build prometheus-cpp - name: Build prometheus-cpp
run: | run: |
@ -156,9 +150,8 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get install clang-9 -qyy
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps install_linux_deps clang-9
- name: Build - name: Build
run: | run: |
@ -188,7 +181,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install compiler - name: Install compiler
run: | run: |
sudo apt-get install gettext -qyy sudo apt-get update -q && sudo apt-get install gettext -qyy
wget http://minetest.kitsunemimi.pw/mingw-w64-i686_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz wget http://minetest.kitsunemimi.pw/mingw-w64-i686_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz
sudo tar -xaf mingw.tar.xz -C /usr sudo tar -xaf mingw.tar.xz -C /usr
@ -206,7 +199,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install compiler - name: Install compiler
run: | run: |
sudo apt-get install gettext -qyy sudo apt-get update -q && sudo apt-get install gettext -qyy
wget http://minetest.kitsunemimi.pw/mingw-w64-x86_64_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz wget http://minetest.kitsunemimi.pw/mingw-w64-x86_64_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz
sudo tar -xaf mingw.tar.xz -C /usr sudo tar -xaf mingw.tar.xz -C /usr

View File

@ -18,12 +18,12 @@ variables:
- mkdir cmakebuild - mkdir cmakebuild
- mkdir -p artifact/minetest/usr/ - mkdir -p artifact/minetest/usr/
- cd cmakebuild - cd cmakebuild
- cmake -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE .. - cmake -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 -j2
- make install - make install
artifacts: artifacts:
when: on_success when: on_success
expire_in: 2h expire_in: 1h
paths: paths:
- artifact/* - artifact/*
@ -34,15 +34,14 @@ variables:
- apt-get install -y git - apt-get install -y git
- mkdir -p build/deb/minetest/DEBIAN/ - mkdir -p build/deb/minetest/DEBIAN/
- cp misc/debpkg-control build/deb/minetest/DEBIAN/control - cp misc/debpkg-control build/deb/minetest/DEBIAN/control
- cp -Rp artifact/minetest/usr build/deb/minetest/ - cp -a artifact/minetest/usr build/deb/minetest/
script: script:
- git clone $MINETEST_GAME_REPO build/deb/minetest/usr/share/minetest/games/minetest_game - git clone $MINETEST_GAME_REPO build/deb/minetest/usr/share/minetest/games/minetest_game
- rm -Rf build/deb/minetest/usr/share/minetest/games/minetest/.git - rm -rf build/deb/minetest/usr/share/minetest/games/minetest/.git
- sed -i 's/DATEPLACEHOLDER/'$(date +%y.%m.%d)'/g' build/deb/minetest/DEBIAN/control - sed -i 's/DATEPLACEHOLDER/'$(date +%y.%m.%d)'/g' build/deb/minetest/DEBIAN/control
- sed -i 's/LEVELDB_PLACEHOLDER/'$LEVELDB_PKG'/g' build/deb/minetest/DEBIAN/control - sed -i 's/LEVELDB_PLACEHOLDER/'$LEVELDB_PKG'/g' build/deb/minetest/DEBIAN/control
- cd build/deb/ && dpkg-deb -b minetest/ && mv minetest.deb ../../ - cd build/deb/ && dpkg-deb -b minetest/ && mv minetest.deb ../../
artifacts: artifacts:
when: on_success
expire_in: 90 day expire_in: 90 day
paths: paths:
- ./*.deb - ./*.deb
@ -51,44 +50,14 @@ variables:
stage: deploy stage: deploy
before_script: before_script:
- apt-get update -y - 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: script:
- dpkg -i ./*.deb - apt-get install -y ./*.deb
- minetest --version
## ##
## Debian ## Debian
## ##
# Jessie
build:debian-8:
extends: .build_template
image: debian:8
before_script:
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu trusty main" > /etc/apt/sources.list.d/uptodate-toolchain.list
- apt-key adv --keyserver keyserver.ubuntu.com --recv BA9EF27F
- apt-get update -y
- apt-get -y install build-essential gcc-6 g++-6 libirrlicht-dev cmake libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
variables:
CC: gcc-6
CXX: g++-6
package:debian-8:
extends: .debpkg_template
image: debian:8
dependencies:
- build:debian-8
variables:
LEVELDB_PKG: libleveldb1
deploy:debian-8:
extends: .debpkg_install
image: debian:8
dependencies:
- package:debian-8
variables:
LEVELDB_PKG: libleveldb1
# Stretch # Stretch
build:debian-9: build:debian-9:
@ -101,7 +70,7 @@ build:debian-9:
package:debian-9: package:debian-9:
extends: .debpkg_template extends: .debpkg_template
image: debian:9 image: debian:9
dependencies: needs:
- build:debian-9 - build:debian-9
variables: variables:
LEVELDB_PKG: libleveldb1v5 LEVELDB_PKG: libleveldb1v5
@ -109,12 +78,10 @@ package:debian-9:
deploy:debian-9: deploy:debian-9:
extends: .debpkg_install extends: .debpkg_install
image: debian:9 image: debian:9
dependencies: needs:
- package:debian-9 - package:debian-9
variables:
LEVELDB_PKG: libleveldb1v5
# Stretch # Buster
build:debian-10: build:debian-10:
extends: .build_template extends: .build_template
@ -126,7 +93,7 @@ build:debian-10:
package:debian-10: package:debian-10:
extends: .debpkg_template extends: .debpkg_template
image: debian:10 image: debian:10
dependencies: needs:
- build:debian-10 - build:debian-10
variables: variables:
LEVELDB_PKG: libleveldb1d LEVELDB_PKG: libleveldb1d
@ -134,10 +101,9 @@ package:debian-10:
deploy:debian-10: deploy:debian-10:
extends: .debpkg_install extends: .debpkg_install
image: debian:10 image: debian:10
dependencies: needs:
- package:debian-10 - package:debian-10
variables:
LEVELDB_PKG: libleveldb1d
## ##
## Ubuntu ## Ubuntu
## ##
@ -154,7 +120,7 @@ build:ubuntu-16.04:
package:ubuntu-16.04: package:ubuntu-16.04:
extends: .debpkg_template extends: .debpkg_template
image: ubuntu:xenial image: ubuntu:xenial
dependencies: needs:
- build:ubuntu-16.04 - build:ubuntu-16.04
variables: variables:
LEVELDB_PKG: libleveldb1v5 LEVELDB_PKG: libleveldb1v5
@ -162,10 +128,8 @@ package:ubuntu-16.04:
deploy:ubuntu-16.04: deploy:ubuntu-16.04:
extends: .debpkg_install extends: .debpkg_install
image: ubuntu:xenial image: ubuntu:xenial
dependencies: needs:
- package:ubuntu-16.04 - package:ubuntu-16.04
variables:
LEVELDB_PKG: libleveldb1v5
# Bionic # Bionic
@ -179,7 +143,7 @@ build:ubuntu-18.04:
package:ubuntu-18.04: package:ubuntu-18.04:
extends: .debpkg_template extends: .debpkg_template
image: ubuntu:bionic image: ubuntu:bionic
dependencies: needs:
- build:ubuntu-18.04 - build:ubuntu-18.04
variables: variables:
LEVELDB_PKG: libleveldb1v5 LEVELDB_PKG: libleveldb1v5
@ -187,25 +151,22 @@ package:ubuntu-18.04:
deploy:ubuntu-18.04: deploy:ubuntu-18.04:
extends: .debpkg_install extends: .debpkg_install
image: ubuntu:bionic image: ubuntu:bionic
dependencies: needs:
- package:ubuntu-18.04 - package:ubuntu-18.04
variables:
LEVELDB_PKG: libleveldb1v5
## ##
## Fedora ## Fedora
## ##
# Do we need to support this old version ? # Fedora 28 <-> RHEL 8
build:fedora-24: build:fedora-28:
extends: .build_template extends: .build_template
image: fedora:24 image: fedora:28
before_script: before_script:
- dnf -y install make automake gcc gcc-c++ kernel-devel cmake libcurl* openal* libvorbis* libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel irrlicht-devel bzip2-libs gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel doxygen spatialindex-devel bzip2-devel - dnf -y install make 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: .generic_win_template:
@ -213,68 +174,63 @@ build:fedora-24:
before_script: before_script:
- apt-get update -y - apt-get update -y
- apt-get install -y wget xz-utils unzip git cmake gettext - apt-get install -y wget xz-utils unzip git cmake gettext
- wget -q http://minetest.kitsunemimi.pw/mingw-w64-${WIN_ARCH}_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz - wget -nv http://minetest.kitsunemimi.pw/mingw-w64-${WIN_ARCH}_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz
- tar -xaf mingw.tar.xz -C /usr - tar -xaf mingw.tar.xz -C /usr
.build_win_template: .build_win_template:
extends: .generic_win_template extends: .generic_win_template
stage: build stage: build
artifacts: artifacts:
when: on_success expire_in: 1h
expire_in: 2h
paths: paths:
- build/* - build/minetest/_build/*
.package_win_template: .package_win_template:
extends: .generic_win_template extends: .generic_win_template
stage: package stage: package
script: script:
- cd build/minetest/_build - unzip build/minetest/_build/minetest-*.zip
- make package - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libgcc*.dll minetest-*-win*/bin/
- cd ../../../ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libstdc++*.dll minetest-*-win*/bin/
- mkdir minetest-win-${WIN_ARCH} - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libwinpthread*.dll minetest-*-win*/bin/
- unzip build/minetest/_build/minetest-*-win*.zip -d minetest-win-${WIN_ARCH}
- cp /usr/${WIN_ARCH}-w64-mingw32/bin/libgcc*.dll minetest-win-${WIN_ARCH}/minetest-*-win*/bin
- cp /usr/${WIN_ARCH}-w64-mingw32/bin/libstdc++*.dll minetest-win-${WIN_ARCH}/minetest-*-win*/bin
- cp /usr/${WIN_ARCH}-w64-mingw32/bin/libwinpthread*.dll minetest-win-${WIN_ARCH}/minetest-*-win*/bin
artifacts: artifacts:
when: on_success
expire_in: 90 day expire_in: 90 day
paths: paths:
- minetest-win-*/* - minetest-*-win*/*
build:win32: build:win32:
extends: .build_win_template extends: .build_win_template
script: script:
- ./util/buildbot/buildwin32.sh build - ./util/buildbot/buildwin32.sh build
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "i686" WIN_ARCH: "i686"
package:win32: package:win32:
extends: .package_win_template extends: .package_win_template
dependencies: needs:
- build:win32 - build:win32
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "i686" WIN_ARCH: "i686"
build:win64: build:win64:
extends: .build_win_template extends: .build_win_template
script: script:
- ./util/buildbot/buildwin64.sh build - ./util/buildbot/buildwin64.sh build
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "x86_64" WIN_ARCH: "x86_64"
package:win64: package:win64:
extends: .package_win_template extends: .package_win_template
dependencies: needs:
- build:win64 - build:win64
variables: variables:
NO_PACKAGE: "1"
WIN_ARCH: "x86_64" WIN_ARCH: "x86_64"
##
## Docker
##
package:docker: package:docker:
stage: package stage: package
image: docker:stable image: docker:stable
@ -288,6 +244,10 @@ package:docker:
- docker push ${CONTAINER_IMAGE}/server:$CI_COMMIT_REF_NAME - docker push ${CONTAINER_IMAGE}/server:$CI_COMMIT_REF_NAME
- docker push ${CONTAINER_IMAGE}/server:latest - docker push ${CONTAINER_IMAGE}/server:latest
##
## Gitlab Pages (Lua API documentation)
##
pages: pages:
stage: deploy stage: deploy
image: python:3.8 image: python:3.8
@ -303,10 +263,14 @@ pages:
only: only:
- master - master
##
## AppImage
##
package:appimage-client: package:appimage-client:
stage: package stage: package
image: appimagecrafters/appimage-builder image: appimagecrafters/appimage-builder
dependencies: needs:
- build:ubuntu-18.04 - build:ubuntu-18.04
before_script: before_script:
- apt-get update -y - apt-get update -y
@ -315,16 +279,15 @@ package:appimage-client:
- mkdir AppDir - mkdir AppDir
- cp -a artifact/minetest/usr/ AppDir/usr/ - cp -a artifact/minetest/usr/ AppDir/usr/
- rm AppDir/usr/bin/minetestserver - rm AppDir/usr/bin/minetestserver
- cp -R clientmods AppDir/usr/share/minetest - cp -a clientmods AppDir/usr/share/minetest
script: script:
- git clone $MINETEST_GAME_REPO AppDir/usr/share/minetest/games/minetest_game - git clone $MINETEST_GAME_REPO AppDir/usr/share/minetest/games/minetest_game
- rm -Rf AppDir/usr/share/minetest/games/minetest/.git - rm -rf AppDir/usr/share/minetest/games/minetest/.git
- export VERSION=$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - export VERSION=$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA
# Remove PrefersNonDefaultGPU property due to validation errors # Remove PrefersNonDefaultGPU property due to validation errors
- sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop - sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop
- appimage-builder --skip-test - appimage-builder --skip-test
artifacts: artifacts:
when: on_success
expire_in: 90 day expire_in: 90 day
paths: paths:
- ./*.AppImage - ./*.AppImage

View File

@ -1,15 +1,9 @@
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 3.5)
if(${CMAKE_VERSION} STREQUAL "2.8.2")
# Bug http://vtk.org/Bug/view.php?id=11020
message(WARNING "CMake/CPack version 2.8.2 will not create working .deb packages!")
endif()
# This can be read from ${PROJECT_NAME} after project() is called # This can be read from ${PROJECT_NAME} after project() is called
project(minetest) project(minetest)
set(PROJECT_NAME_CAPITALIZED "Dragonfire") set(PROJECT_NAME_CAPITALIZED "Dragonfire")
# Works only for cmake 3.1 and greater
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(GCC_MINIMUM_VERSION "4.8") set(GCC_MINIMUM_VERSION "4.8")
set(CLANG_MINIMUM_VERSION "3.4") set(CLANG_MINIMUM_VERSION "3.4")
@ -278,11 +272,12 @@ if(WIN32)
set(CPACK_GENERATOR ZIP) set(CPACK_GENERATOR ZIP)
else() else()
set(CPACK_GENERATOR WIX ZIP) set(CPACK_GENERATOR WIX)
set(CPACK_PACKAGE_NAME "${PROJECT_NAME_CAPITALIZED}") set(CPACK_PACKAGE_NAME "${PROJECT_NAME_CAPITALIZED}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME_CAPITALIZED}") set(CPACK_PACKAGE_INSTALL_DIRECTORY ".")
set(CPACK_PACKAGE_EXECUTABLES ${PROJECT_NAME} "${PROJECT_NAME_CAPITALIZED}") set(CPACK_PACKAGE_EXECUTABLES ${PROJECT_NAME} "${PROJECT_NAME_CAPITALIZED}")
set(CPACK_CREATE_DESKTOP_LINKS ${PROJECT_NAME}) set(CPACK_CREATE_DESKTOP_LINKS ${PROJECT_NAME})
set(CPACK_PACKAGING_INSTALL_PREFIX "/${PROJECT_NAME_CAPITALIZED}")
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/minetest-icon.ico") set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/minetest-icon.ico")
# Supported languages can be found at # Supported languages can be found at

View File

@ -11,6 +11,9 @@ http://creativecommons.org/licenses/by-sa/3.0/
textures/base/pack/refresh.png is under the Apache 2 license textures/base/pack/refresh.png is under the Apache 2 license
https://www.apache.org/licenses/LICENSE-2.0.html https://www.apache.org/licenses/LICENSE-2.0.html
Textures by Zughy are under CC BY-SA 4.0
https://creativecommons.org/licenses/by-sa/4.0/
Authors of media files Authors of media files
----------------------- -----------------------
Everything not listed in here: Everything not listed in here:
@ -23,6 +26,8 @@ paramat:
textures/base/pack/menu_header.png textures/base/pack/menu_header.png
textures/base/pack/next_icon.png textures/base/pack/next_icon.png
textures/base/pack/prev_icon.png textures/base/pack/prev_icon.png
textures/base/pack/clear.png
textures/base/pack/search.png
rubenwardy, paramat: rubenwardy, paramat:
textures/base/pack/start_icon.png textures/base/pack/start_icon.png
@ -45,6 +50,14 @@ srifqi
textures/base/pack/joystick_off.png textures/base/pack/joystick_off.png
textures/base/pack/minimap_btn.png textures/base/pack/minimap_btn.png
Zughy:
textures/base/pack/cdb_add.png
textures/base/pack/cdb_clear.png
textures/base/pack/cdb_downloading.png
textures/base/pack/cdb_queued.png
textures/base/pack/cdb_update.png
textures/base/pack/cdb_viewonline.png
License of Minetest source code License of Minetest source code
------------------------------- -------------------------------

View File

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

View File

@ -781,3 +781,7 @@ function core.privs_to_string(privs, delim)
end end
return table.concat(list, delim) return table.concat(list, delim)
end end
function core.is_nan(number)
return number ~= number
end

View File

@ -152,8 +152,8 @@ core.register_entity(":__builtin:falling_node", {
else else
self.object:set_yaw(-math.pi*0.25) self.object:set_yaw(-math.pi*0.25)
end end
elseif (node.param2 ~= 0 and (def.wield_image == "" elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
or def.wield_image == nil)) and (def.wield_image == "" or def.wield_image == nil))
or def.drawtype == "signlike" or def.drawtype == "signlike"
or def.drawtype == "mesh" or def.drawtype == "mesh"
or def.drawtype == "normal" or def.drawtype == "normal"
@ -168,16 +168,30 @@ core.register_entity(":__builtin:falling_node", {
elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted") then elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted") then
local rot = node.param2 % 8 local rot = node.param2 % 8
local pitch, yaw, roll = 0, 0, 0 local pitch, yaw, roll = 0, 0, 0
if rot == 1 then if def.drawtype == "nodebox" or def.drawtype == "mesh" then
pitch, yaw = math.pi, math.pi if rot == 0 then
elseif rot == 2 then pitch, yaw = math.pi/2, 0
pitch, yaw = math.pi/2, math.pi/2 elseif rot == 1 then
elseif rot == 3 then pitch, yaw = -math.pi/2, math.pi
pitch, yaw = math.pi/2, -math.pi/2 elseif rot == 2 then
elseif rot == 4 then pitch, yaw = 0, math.pi/2
pitch, yaw = math.pi/2, math.pi elseif rot == 3 then
elseif rot == 5 then pitch, yaw = 0, -math.pi/2
pitch, yaw = math.pi/2, 0 elseif rot == 4 then
pitch, yaw = 0, math.pi
end
else
if rot == 1 then
pitch, yaw = math.pi, math.pi
elseif rot == 2 then
pitch, yaw = math.pi/2, math.pi/2
elseif rot == 3 then
pitch, yaw = math.pi/2, -math.pi/2
elseif rot == 4 then
pitch, yaw = math.pi/2, math.pi
elseif rot == 5 then
pitch, yaw = math.pi/2, 0
end
end end
if def.drawtype == "signlike" then if def.drawtype == "signlike" then
pitch = pitch - math.pi/2 pitch = pitch - math.pi/2
@ -186,7 +200,7 @@ core.register_entity(":__builtin:falling_node", {
elseif rot == 1 then elseif rot == 1 then
yaw = yaw - math.pi/2 yaw = yaw - math.pi/2
end end
elseif def.drawtype == "mesh" or def.drawtype == "normal" then elseif def.drawtype == "mesh" or def.drawtype == "normal" or def.drawtype == "nodebox" then
if rot >= 0 and rot <= 1 then if rot >= 0 and rot <= 1 then
roll = roll + math.pi roll = roll + math.pi
else else

View File

@ -159,6 +159,331 @@ local function queue_download(package)
end end
end end
local function get_raw_dependencies(package)
if package.raw_deps then
return package.raw_deps
end
local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s"
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local url = base_url .. url_fmt:format(package.id, core.get_max_supp_proto(), version.string)
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
local data = core.parse_json(response.data) or {}
local content_lookup = {}
for _, pkg in pairs(store.packages_full) do
content_lookup[pkg.id] = pkg
end
for id, raw_deps in pairs(data) do
local package2 = content_lookup[id:lower()]
if package2 and not package2.raw_deps then
package2.raw_deps = raw_deps
for _, dep in pairs(raw_deps) do
local packages = {}
for i=1, #dep.packages do
packages[#packages + 1] = content_lookup[dep.packages[i]:lower()]
end
dep.packages = packages
end
end
end
return package.raw_deps
end
local function has_hard_deps(raw_deps)
for i=1, #raw_deps do
if not raw_deps[i].is_optional then
return true
end
end
return false
end
-- Recursively resolve dependencies, given the installed mods
local function resolve_dependencies_2(raw_deps, installed_mods, out)
local function resolve_dep(dep)
-- Check whether it's already installed
if installed_mods[dep.name] then
return {
is_optional = dep.is_optional,
name = dep.name,
installed = true,
}
end
-- Find exact name matches
local fallback
for _, package in pairs(dep.packages) do
if package.type ~= "game" then
if package.name == dep.name then
return {
is_optional = dep.is_optional,
name = dep.name,
installed = false,
package = package,
}
elseif not fallback then
fallback = package
end
end
end
-- Otherwise, find the first mod that fulfils it
if fallback then
return {
is_optional = dep.is_optional,
name = dep.name,
installed = false,
package = fallback,
}
end
return {
is_optional = dep.is_optional,
name = dep.name,
installed = false,
}
end
for _, dep in pairs(raw_deps) do
if not dep.is_optional and not out[dep.name] then
local result = resolve_dep(dep)
out[dep.name] = result
if result and result.package and not result.installed then
local raw_deps2 = get_raw_dependencies(result.package)
if raw_deps2 then
resolve_dependencies_2(raw_deps2, installed_mods, out)
end
end
end
end
return true
end
-- Resolve dependencies for a package, calls the recursive version.
local function resolve_dependencies(raw_deps, game)
assert(game)
local installed_mods = {}
local mods = {}
pkgmgr.get_game_mods(game, mods)
for _, mod in pairs(mods) do
installed_mods[mod.name] = true
end
for _, mod in pairs(pkgmgr.global_mods:get_list()) do
installed_mods[mod.name] = true
end
local out = {}
if not resolve_dependencies_2(raw_deps, installed_mods, out) then
return nil
end
local retval = {}
for _, dep in pairs(out) do
retval[#retval + 1] = dep
end
table.sort(retval, function(a, b)
return a.name < b.name
end)
return retval
end
local install_dialog = {}
function install_dialog.get_formspec()
local package = install_dialog.package
local raw_deps = install_dialog.raw_deps
local will_install_deps = install_dialog.will_install_deps
local selected_game_idx = 1
local selected_gameid = core.settings:get("menu_last_game")
local games = table.copy(pkgmgr.games)
for i=1, #games do
if selected_gameid and games[i].id == selected_gameid then
selected_game_idx = i
end
games[i] = 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 function get_file_extension(path)
local parts = path:split(".") local parts = path:split(".")
return parts[#parts] return parts[#parts]
@ -340,7 +665,6 @@ function store.get_formspec(dlgdata)
local W = 15.75 local W = 15.75
local H = 9.5 local H = 9.5
local formspec local formspec
if #store.packages_full > 0 then if #store.packages_full > 0 then
formspec = { formspec = {
@ -348,12 +672,13 @@ function store.get_formspec(dlgdata)
"size[15.75,9.5]", "size[15.75,9.5]",
"position[0.5,0.55]", "position[0.5,0.55]",
"style[status;border=false]", "style[status,downloading,queued;border=false]",
"container[0.375,0.375]", "container[0.375,0.375]",
"field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]", "field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]",
"field_close_on_enter[search_string;false]", "field_close_on_enter[search_string;false]",
"button[7.225,0;2,0.8;search;", fgettext("Search"), "]", "image_button[7.3,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
"image_button[8.125,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]",
"dropdown[9.6,0;2.4,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]", "dropdown[9.6,0;2.4,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]",
"container_end[]", "container_end[]",
@ -374,7 +699,7 @@ function store.get_formspec(dlgdata)
} }
if number_downloading > 0 then if number_downloading > 0 then
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;status;" formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;downloading;"
if #download_queue > 0 then if #download_queue > 0 then
formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue) formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue)
else else
@ -418,11 +743,17 @@ function store.get_formspec(dlgdata)
} }
end end
-- download/queued tooltips always have the same message
local tooltip_colors = ";#dff6f5;#302c2e]"
formspec[#formspec + 1] = "tooltip[downloading;" .. fgettext("Downloading...") .. tooltip_colors
formspec[#formspec + 1] = "tooltip[queued;" .. fgettext("Queued") .. tooltip_colors
local start_idx = (cur_page - 1) * num_per_page + 1 local start_idx = (cur_page - 1) * num_per_page + 1
for i=start_idx, math.min(#store.packages, start_idx+num_per_page-1) do for i=start_idx, math.min(#store.packages, start_idx+num_per_page-1) do
local package = store.packages[i] local package = store.packages[i]
local container_y = (i - start_idx) * 1.375 + (2*0.375 + 0.8)
formspec[#formspec + 1] = "container[0.375," formspec[#formspec + 1] = "container[0.375,"
formspec[#formspec + 1] = (i - start_idx) * 1.375 + (2*0.375 + 0.8) formspec[#formspec + 1] = container_y
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "]"
-- image -- image
@ -438,52 +769,50 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "]"
-- buttons -- buttons
local description_width = W - 0.375*5 - 1 - 2*1.5 local left_base = "image_button[-1.55,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "container[" formspec[#formspec + 1] = "container["
formspec[#formspec + 1] = W - 0.375*2 formspec[#formspec + 1] = W - 0.375*2
formspec[#formspec + 1] = ",0.1]" formspec[#formspec + 1] = ",0.1]"
if package.downloading then if package.downloading then
formspec[#formspec + 1] = "button[-3.5,0;2,0.8;status;" formspec[#formspec + 1] = "animated_image[-1.7,-0.15;1,1;downloading;"
formspec[#formspec + 1] = fgettext("Downloading...") formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
elseif package.queued then elseif package.queued then
formspec[#formspec + 1] = "button[-3.5,0;2,0.8;status;" formspec[#formspec + 1] = left_base
formspec[#formspec + 1] = fgettext("Queued") formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "]" formspec[#formspec + 1] = "cdb_queued.png;queued]"
elseif not package.path then elseif not package.path then
formspec[#formspec + 1] = "button[-3,0;1.5,0.8;install_" local elem_name = "install_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]"
formspec[#formspec + 1] = ";" formspec[#formspec + 1] = left_base .. "cdb_add.png;" .. elem_name .. "]"
formspec[#formspec + 1] = fgettext("Install") formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Install") .. tooltip_colors
formspec[#formspec + 1] = "]"
else else
if package.installed_release < package.release then if package.installed_release < package.release then
description_width = description_width - 1.5
-- The install_ action also handles updating -- The install_ action also handles updating
formspec[#formspec + 1] = "button[-4.5,0;1.5,0.8;install_" local elem_name = "install_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#28ccdf]"
formspec[#formspec + 1] = ";" formspec[#formspec + 1] = left_base .. "cdb_update.png;" .. elem_name .. "]"
formspec[#formspec + 1] = fgettext("Update") formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Update") .. tooltip_colors
formspec[#formspec + 1] = "]" else
end
formspec[#formspec + 1] = "button[-3,0;1.5,0.8;uninstall_" local elem_name = "uninstall_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#a93b3b]"
formspec[#formspec + 1] = ";" formspec[#formspec + 1] = left_base .. "cdb_clear.png;" .. elem_name .. "]"
formspec[#formspec + 1] = fgettext("Uninstall") formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Uninstall") .. tooltip_colors
formspec[#formspec + 1] = "]" end
end end
formspec[#formspec + 1] = "button[-1.5,0;1.5,0.8;view_" local web_elem_name = "view_" .. i .. ";"
formspec[#formspec + 1] = tostring(i) formspec[#formspec + 1] = "image_button[-0.7,0;0.7,0.7;" ..
formspec[#formspec + 1] = ";" core.formspec_escape(defaulttexturedir) .. "cdb_viewonline.png;" .. web_elem_name .. "]"
formspec[#formspec + 1] = fgettext("View") formspec[#formspec + 1] = "tooltip[" .. web_elem_name ..
formspec[#formspec + 1] = "]" fgettext("View more information in a web browser") .. tooltip_colors
formspec[#formspec + 1] = "container_end[]" formspec[#formspec + 1] = "container_end[]"
-- description -- description
local description_width = W - 0.375*5 - 0.85 - 2*0.7
formspec[#formspec + 1] = "textarea[1.855,0.3;" formspec[#formspec + 1] = "textarea[1.855,0.3;"
formspec[#formspec + 1] = tostring(description_width) formspec[#formspec + 1] = tostring(description_width)
formspec[#formspec + 1] = ",0.8;;;" formspec[#formspec + 1] = ",0.8;;;"
@ -504,6 +833,13 @@ function store.handle_submit(this, fields)
return true return true
end end
if fields.clear then
search_string = ""
cur_page = 1
store.filter_packages("")
return true
end
if fields.back then if fields.back then
this:delete() this:delete()
return true return true
@ -563,15 +899,47 @@ function store.handle_submit(this, fields)
assert(package) assert(package)
if fields["install_" .. i] then if fields["install_" .. i] then
queue_download(package) local install_parent
if package.type == "mod" then
install_parent = core.get_modpath()
elseif package.type == "game" then
install_parent = core.get_gamepath()
elseif package.type == "txp" then
install_parent = core.get_texturepath()
else
error("Unknown package type: " .. package.type)
end
local function on_confirm()
local deps = get_raw_dependencies(package)
if deps and has_hard_deps(deps) then
local dlg = install_dialog.create(package, deps)
dlg:set_parent(this)
this:hide()
dlg:show()
else
queue_download(package)
end
end
if not package.path and core.is_dir(install_parent .. DIR_DELIM .. package.name) then
local dlg = confirm_overwrite.create(package, on_confirm)
dlg:set_parent(this)
this:hide()
dlg:show()
else
on_confirm()
end
return true return true
end end
if fields["uninstall_" .. i] then if fields["uninstall_" .. i] then
local dlg_delmod = create_delete_content_dlg(package) local dlg = create_delete_content_dlg(package)
dlg_delmod:set_parent(this) dlg:set_parent(this)
this:hide() this:hide()
dlg_delmod:show() dlg:show()
return true return true
end end

View File

@ -98,7 +98,7 @@ local function create_world_formspec(dialogdata)
-- Error out when no games found -- Error out when no games found
if #pkgmgr.games == 0 then if #pkgmgr.games == 0 then
return "size[12.25,3,true]" .. return "size[12.25,3,true]" ..
"box[0,0;12,2;#ff8800]" .. "box[0,0;12,2;" .. mt_color_orange .. "]" ..
"textarea[0.3,0;11.7,2;;;".. "textarea[0.3,0;11.7,2;;;"..
fgettext("You have no games installed.") .. "\n" .. fgettext("You have no games installed.") .. "\n" ..
fgettext("Download one from minetest.net") .. "]" .. fgettext("Download one from minetest.net") .. "]" ..

View File

@ -19,6 +19,7 @@ mt_color_grey = "#AAAAAA"
mt_color_blue = "#6389FF" mt_color_blue = "#6389FF"
mt_color_green = "#72FF63" mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191" mt_color_dark_green = "#25C191"
mt_color_orange = "#FF8800"
local menupath = core.get_mainmenu_path() local menupath = core.get_mainmenu_path()
local basepath = core.get_builtin_path() local basepath = core.get_builtin_path()
@ -105,6 +106,16 @@ local function init_globals()
if last_tab and tv_main.current_tab ~= last_tab then if last_tab and tv_main.current_tab ~= last_tab then
tv_main:set_tab(last_tab) tv_main:set_tab(last_tab)
end end
-- In case the folder of the last selected game has been deleted,
-- display "Minetest" as a header
if tv_main.current_tab == "local" then
local game = pkgmgr.find_by_gameid(core.settings:get("menu_last_game"))
if game == nil then
mm_texture.reset()
end
end
ui.set_default("maintab") ui.set_default("maintab")
tv_main:show() tv_main:show()

View File

@ -109,9 +109,10 @@ return {
cbf_formspec = function(tabview, name, tabdata) cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png" local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version() local version = core.get_version()
return "image[0.5,1;" .. core.formspec_escape(logofile) .. "]" .. local fs = "image[0.75,0.5;2.2,2.2;" .. core.formspec_escape(logofile) .. "]" ..
"label[0.5,2.8;" .. version.project .. " " .. version.string .. "]" .. "style[label_button;border=false]" ..
"button[0.5,3;2,2;homepage;minetest.net]" .. "button[0.5,2;2.5,2;label_button;" .. version.project .. " " .. version.string .. "]" ..
"button[0.75,2.75;2,2;homepage;minetest.net]" ..
"tablecolumns[color;text]" .. "tablecolumns[color;text]" ..
"tableoptions[background=#00000000;highlight=#00000000;border=false]" .. "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
"table[3.5,-0.25;8.5,6.05;list_credits;" .. "table[3.5,-0.25;8.5,6.05;list_credits;" ..
@ -126,10 +127,23 @@ return {
"#FFFF00," .. fgettext("Previous Contributors") .. ",," .. "#FFFF00," .. fgettext("Previous Contributors") .. ",," ..
buildCreditList(previous_contributors) .. "," .. buildCreditList(previous_contributors) .. "," ..
";1]" ";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, end,
cbf_button_handler = function(this, fields, name, tabdata) cbf_button_handler = function(this, fields, name, tabdata)
if fields.homepage then if fields.homepage then
core.open_url("https://www.minetest.net") core.open_url("https://www.minetest.net")
end end
if fields.userdata then
core.open_dir(core.get_user_path())
end
end, end,
} }

View File

@ -18,6 +18,7 @@
local enable_gamebar = PLATFORM ~= "Android" local enable_gamebar = PLATFORM ~= "Android"
local current_game, singleplayer_refresh_gamebar local current_game, singleplayer_refresh_gamebar
if enable_gamebar then if enable_gamebar then
function current_game() function current_game()
local last_game_id = core.settings:get("menu_last_game") local last_game_id = core.settings:get("menu_last_game")

View File

@ -34,7 +34,8 @@ local function get_formspec(tabview, name, tabdata)
local retval = local retval =
-- Search -- Search
"field[0.15,0.075;5.91,1;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" .. "field[0.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") "image_button[6.97,-.165;.83,.83;" .. core.formspec_escape(defaulttexturedir .. "refresh.png")
.. ";btn_mp_refresh;]" .. .. ";btn_mp_refresh;]" ..
@ -243,6 +244,12 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true return true
end 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 if fields.btn_mp_search or fields.key_enter_field == "te_search" then
tabdata.fav_selected = 1 tabdata.fav_selected = 1
local input = fields.te_search:lower() local input = fields.te_search:lower()

View File

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

View File

@ -152,6 +152,9 @@ joystick_type (Joystick type) enum auto auto,generic,xbox
# when holding down a joystick button combination. # when holding down a joystick button combination.
repeat_joystick_button_time (Joystick button repetition interval) float 0.17 0.001 repeat_joystick_button_time (Joystick button repetition interval) float 0.17 0.001
# The deadzone of the joystick
joystick_deadzone (Joystick deadzone) int 2048
# The sensitivity of the joystick axes for moving the # The sensitivity of the joystick axes for moving the
# ingame view frustum around. # ingame view frustum around.
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170 joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170
@ -1060,6 +1063,13 @@ full_block_send_enable_min_time_from_building (Delay in sending blocks after bui
# client number. # client number.
max_packets_per_iteration (Max. packets per iteration) int 1024 max_packets_per_iteration (Max. packets per iteration) int 1024
# ZLib compression level to use when sending mapblocks to the client.
# -1 - Zlib's default compression level
# 0 - no compresson, fastest
# 9 - best compression, slowest
# (levels 1-3 use Zlib's "fast" method, 4-9 use the normal method)
map_compression_level_net (Map Compression Level for Network Transfer) int -1 -1 9
[*Game] [*Game]
# Default game when creating a new world. # Default game when creating a new world.
@ -1252,6 +1262,13 @@ max_objects_per_block (Maximum objects per block) int 64
# See https://www.sqlite.org/pragma.html#pragma_synchronous # See https://www.sqlite.org/pragma.html#pragma_synchronous
sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2 sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
# ZLib compression level to use when saving mapblocks to disk.
# -1 - Zlib's default compression level
# 0 - no compresson, fastest
# 9 - best compression, slowest
# (levels 1-3 use Zlib's "fast" method, 4-9 use the normal method)
map_compression_level_disk (Map Compression Level for Disk Storage) int 3 -1 9
# Length of a server tick and the interval at which objects are generally updated over # Length of a server tick and the interval at which objects are generally updated over
# network. # network.
dedicated_server_step (Dedicated server step) float 0.09 dedicated_server_step (Dedicated server step) float 0.09
@ -2200,6 +2217,7 @@ contentdb_url (ContentDB URL) string https://content.minetest.net
contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default contentdb_flag_blacklist (ContentDB Flag Blacklist) string nonfree, desktop_default
# Maximum number of concurrent downloads. Downloads exceeding this limit will be queued. # Maximum number of concurrent downloads. Downloads exceeding this limit will be queued.
# This should be lower than curl_parallel_limit.
contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3
[Cheat Menu] [Cheat Menu]

View File

@ -16,13 +16,17 @@ varying vec3 vPosition;
// precision must be considered). // precision must be considered).
varying vec3 worldPosition; varying vec3 worldPosition;
varying lowp vec4 varColor; varying lowp vec4 varColor;
centroid varying mediump vec2 varTexCoord; #ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec; varying vec3 eyeVec;
const float fogStart = FOG_START; const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart); const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
#ifdef ENABLE_TONE_MAPPING #if ENABLE_TONE_MAPPING
/* Hable's UC2 Tone mapping parameters /* Hable's UC2 Tone mapping parameters
A = 0.22; A = 0.22;
@ -73,7 +77,7 @@ void main(void)
vec4 col = vec4(color.rgb * varColor.rgb, 1.0); vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
#ifdef ENABLE_TONE_MAPPING #if ENABLE_TONE_MAPPING
col = applyToneMapping(col); col = applyToneMapping(col);
#endif #endif

View File

@ -19,7 +19,11 @@ varying lowp vec4 varColor;
// The centroid keyword ensures that after interpolation the texture coordinates // The centroid keyword ensures that after interpolation the texture coordinates
// lie within the same bounds when MSAA is en- and disabled. // lie within the same bounds when MSAA is en- and disabled.
// This fixes the stripes problem with nearest-neighbour textures and MSAA. // 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; varying vec3 eyeVec;
// Color of the light emitted by the light sources. // Color of the light emitted by the light sources.

View File

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

View File

@ -7,7 +7,11 @@ varying vec3 vNormal;
varying vec3 vPosition; varying vec3 vPosition;
varying vec3 worldPosition; varying vec3 worldPosition;
varying lowp vec4 varColor; varying lowp vec4 varColor;
centroid varying mediump vec2 varTexCoord; #ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec; varying vec3 eyeVec;
varying float vIDiff; varying float vIDiff;

View File

@ -2114,6 +2114,22 @@ Examples
list[current_player;craft;3,0;3,3;] list[current_player;craft;3,0;3,3;]
list[current_player;craftpreview;7,1;1,1;] list[current_player;craftpreview;7,1;1,1;]
Version History
---------------
* FORMSPEC VERSION 1:
* (too much)
* FORMSPEC VERSION 2:
* Forced real coordinates
* background9[]: 9-slice scaling parameters
* FORMSPEC VERSION 3:
* Formspec elements are drawn in the order of definition
* bgcolor[]: use 3 parameters (bgcolor, formspec (now an enum), fbgcolor)
* box[] and image[] elements enable clipping by default
* new element: scroll_container[]
* FORMSPEC VERSION 4:
* Allow dropdown indexing events
Elements Elements
-------- --------
@ -2125,6 +2141,7 @@ Elements
* Clients older than this version can neither show newer elements nor display * Clients older than this version can neither show newer elements nor display
elements with new arguments correctly. elements with new arguments correctly.
* Available since feature `formspec_version_element`. * Available since feature `formspec_version_element`.
* See also: [Version History]
### `size[<W>,<H>,<fixed_size>]` ### `size[<W>,<H>,<fixed_size>]`
@ -2277,7 +2294,7 @@ Elements
* `frame duration`: Milliseconds between each frame. `0` means the frames don't advance. * `frame duration`: Milliseconds between each frame. `0` means the frames don't advance.
* `frame start` (Optional): The index of the frame to start on. Default `1`. * `frame start` (Optional): The index of the frame to start on. Default `1`.
### `model[<X>,<Y>;<W>,<H>;<name>;<mesh>;<textures>;<rotation X,Y>;<continuous>;<mouse control>]` ### `model[<X>,<Y>;<W>,<H>;<name>;<mesh>;<textures>;<rotation X,Y>;<continuous>;<mouse control>;<frame loop range>]`
* Show a mesh model. * Show a mesh model.
* `name`: Element name that can be used for styling * `name`: Element name that can be used for styling
@ -2288,6 +2305,9 @@ Elements
The axes are euler angles in degrees. The axes are euler angles in degrees.
* `continuous` (Optional): Whether the rotation is continuous. Default `false`. * `continuous` (Optional): Whether the rotation is continuous. Default `false`.
* `mouse control` (Optional): Whether the model can be controlled with the mouse. Default `true`. * `mouse control` (Optional): Whether the model can be controlled with the mouse. Default `true`.
* `frame loop range` (Optional): Range of the animation frames.
* Defaults to the full range of all available frames.
* Syntax: `<begin>,<end>`
### `item_image[<X>,<Y>;<W>,<H>;<item name>]` ### `item_image[<X>,<Y>;<W>,<H>;<item name>]`
@ -2789,6 +2809,7 @@ Some types may inherit styles from parent types.
* image_button * image_button
* item_image_button * item_image_button
* label * label
* model
* pwdfield, inherits from field * pwdfield, inherits from field
* scrollbar * scrollbar
* tabheader * tabheader
@ -4188,6 +4209,8 @@ Callbacks:
* Called when the object is instantiated. * Called when the object is instantiated.
* `dtime_s` is the time passed since the object was unloaded, which can be * `dtime_s` is the time passed since the object was unloaded, which can be
used for updating the entity state. used for updating the entity state.
* `on_deactivate(self)
* Called when the object is about to get removed or unloaded.
* `on_step(self, dtime)` * `on_step(self, dtime)`
* Called on every server tick, after movement and collision processing. * Called on every server tick, after movement and collision processing.
`dtime` is usually 0.1 seconds, as per the `dedicated_server_step` setting `dtime` is usually 0.1 seconds, as per the `dedicated_server_step` setting
@ -4308,11 +4331,14 @@ Utilities
* `minetest.get_current_modname()`: returns the currently loading mod's name, * `minetest.get_current_modname()`: returns the currently loading mod's name,
when loading a mod. when loading a mod.
* `minetest.get_modpath(modname)`: returns e.g. * `minetest.get_modpath(modname)`: returns the directory path for a mod,
`"/home/user/.minetest/usermods/modname"`. e.g. `"/home/user/.minetest/usermods/modname"`.
* Useful for loading additional `.lua` modules or static data from mod * Returns nil if the mod is not enabled or does not exist (not installed).
* `minetest.get_modnames()`: returns a list of installed mods * Works regardless of whether the mod has been loaded yet.
* Return a list of installed mods, sorted alphabetically * Useful for loading additional `.lua` modules or static data from a mod,
or checking if a mod is enabled.
* `minetest.get_modnames()`: returns a list of enabled mods, sorted alphabetically.
* Does not include disabled mods, even if they are installed.
* `minetest.get_worldpath()`: returns e.g. `"/home/user/.minetest/world"` * `minetest.get_worldpath()`: returns e.g. `"/home/user/.minetest/world"`
* Useful for storing custom data * Useful for storing custom data
* `minetest.is_singleplayer()` * `minetest.is_singleplayer()`
@ -4872,6 +4898,9 @@ Environment access
* `minetest.get_objects_inside_radius(pos, radius)`: returns a list of * `minetest.get_objects_inside_radius(pos, radius)`: returns a list of
ObjectRefs. ObjectRefs.
* `radius`: using an euclidean metric * `radius`: using an euclidean metric
* `minetest.get_objects_in_area(pos1, pos2)`: returns a list of
ObjectRefs.
* `pos1` and `pos2` are the min and max positions of the area to search.
* `minetest.set_timeofday(val)` * `minetest.set_timeofday(val)`
* `val` is between `0` and `1`; `0` for midnight, `0.5` for midday * `val` is between `0` and `1`; `0` for midnight, `0.5` for midday
* `minetest.get_timeofday()` * `minetest.get_timeofday()`
@ -7614,6 +7643,13 @@ Used by `minetest.register_node`.
-- intensity: 1.0 = mid range of regular TNT. -- intensity: 1.0 = mid range of regular TNT.
-- If defined, called when an explosion touches the node, instead of -- If defined, called when an explosion touches the node, instead of
-- removing the node. -- removing the node.
mod_origin = "modname",
-- stores which mod actually registered a node
-- if it can not find a source, returns "??"
-- useful for getting what mod truly registered something
-- example: if a node is registered as ":othermodname:nodename",
-- nodename will show "othermodname", but mod_orgin will say "modname"
} }
Crafting recipes Crafting recipes

View File

@ -43,10 +43,14 @@ core.get_max_supp_proto()
core.open_url(url) core.open_url(url)
^ opens the URL in a web browser, returns false on failure. ^ opens the URL in a web browser, returns false on failure.
^ Must begin with http:// or https:// ^ Must begin with http:// or https://
core.open_dir(path)
^ opens the path in the system file browser/explorer, returns false on failure.
^ Must be an existing directory.
core.get_version() (possible in async calls) core.get_version() (possible in async calls)
^ returns current core version ^ returns current core version
Filesystem Filesystem
---------- ----------
@ -63,6 +67,8 @@ core.copy_dir(source,destination,keep_soure) (possible in async calls)
^ destination folder ^ destination folder
^ keep_source DEFAULT true --> if set to false source is deleted after copying ^ keep_source DEFAULT true --> if set to false source is deleted after copying
^ returns true/false ^ returns true/false
core.is_dir(path) (possible in async calls)
^ returns true if path is a valid dir
core.extract_zip(zipfile,destination) [unzip within path required] core.extract_zip(zipfile,destination) [unzip within path required]
^ zipfile to extract ^ zipfile to extract
^ destination folder to extract to ^ destination folder to extract to
@ -207,6 +213,9 @@ Content and Packages
Content - an installed mod, modpack, game, or texture pack (txt) Content - an installed mod, modpack, game, or texture pack (txt)
Package - content which is downloadable from the content db, may or may not be installed. Package - content which is downloadable from the content db, may or may not be installed.
* core.get_user_path() (possible in async calls)
* returns path to global user data,
the directory that contains user-provided mods, worlds, games, and texture packs.
* core.get_modpath() (possible in async calls) * core.get_modpath() (possible in async calls)
* returns path to global modpath * returns path to global modpath
* core.get_clientmodpath() (possible in async calls) * core.get_clientmodpath() (possible in async calls)

View File

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

View File

@ -94,3 +94,32 @@ minetest.register_entity("testentities:upright_animated", {
self.object:set_sprite({x=0, y=0}, 4, 1.0, false) self.object:set_sprite({x=0, y=0}, 4, 1.0, false)
end, end,
}) })
minetest.register_entity("testentities:nametag", {
initial_properties = {
visual = "sprite",
textures = { "testentities_sprite.png" },
},
on_activate = function(self, staticdata)
if staticdata ~= "" then
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,
})

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

View File

@ -1,5 +1,3 @@
cmake_minimum_required(VERSION 2.4 FATAL_ERROR)
project(lua C) project(lua C)
set(LUA_VERSION_MAJOR 5) set(LUA_VERSION_MAJOR 5)
@ -15,9 +13,8 @@ set(LIBS)
if(APPLE) if(APPLE)
set(DEFAULT_POSIX TRUE) set(DEFAULT_POSIX TRUE)
set(DEFAULT_DLOPEN ON) set(DEFAULT_DLOPEN OFF)
# use this on Mac OS X 10.3- set(COMMON_CFLAGS "${COMMON_CFLAGS} -DLUA_USE_MACOSX")
option(LUA_USE_MACOSX "Mac OS X 10.3-" OFF)
elseif(UNIX OR CYGWIN) elseif(UNIX OR CYGWIN)
set(DEFAULT_POSIX TRUE) set(DEFAULT_POSIX TRUE)
elseif(WIN32) elseif(WIN32)
@ -32,12 +29,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(DEFAULT_DLOPEN ON) set(DEFAULT_DLOPEN ON)
endif() 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}) option(LUA_USE_DLOPEN "Enable dlopen support." ${DEFAULT_DLOPEN})
mark_as_advanced(LUA_USE_DLOPEN) mark_as_advanced(LUA_USE_DLOPEN)

View File

@ -129,6 +129,9 @@
# type: float min: 0.001 # type: float min: 0.001
# repeat_joystick_button_time = 0.17 # repeat_joystick_button_time = 0.17
# The deadzone of the joystick
# joystick_deadzone = 2048
# The sensitivity of the joystick axes for moving the # The sensitivity of the joystick axes for moving the
# ingame view frustum around. # ingame view frustum around.
# type: float # type: float

View File

@ -3,9 +3,9 @@ Priority: extra
Standards-Version: 3.6.2 Standards-Version: 3.6.2
Package: minetest-staging Package: minetest-staging
Version: 0.4.15-DATEPLACEHOLDER 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> 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-Git: https://github.com/minetest/minetest.git
Vcs-Browser: https://github.com/minetest/minetest.git Vcs-Browser: https://github.com/minetest/minetest.git
Architecture: amd64 Architecture: amd64

View File

@ -1,5 +1,3 @@
cmake_minimum_required(VERSION 2.6)
project(minetest) project(minetest)
INCLUDE(CheckIncludeFiles) INCLUDE(CheckIncludeFiles)
@ -124,27 +122,6 @@ option(ENABLE_FREETYPE "Enable FreeType2 (TrueType fonts and basic unicode suppo
set(USE_FREETYPE FALSE) set(USE_FREETYPE FALSE)
if(ENABLE_FREETYPE) 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) find_package(Freetype)
if(FREETYPE_FOUND) if(FREETYPE_FOUND)
message(STATUS "Freetype enabled.") message(STATUS "Freetype enabled.")

View File

@ -691,10 +691,11 @@ void Camera::drawNametags()
core::matrix4 trans = m_cameranode->getProjectionMatrix(); core::matrix4 trans = m_cameranode->getProjectionMatrix();
trans *= m_cameranode->getViewMatrix(); trans *= m_cameranode->getViewMatrix();
for (std::list<Nametag *>::const_iterator gui::IGUIFont *font = g_fontengine->getFont();
i = m_nametags.begin(); video::IVideoDriver *driver = RenderingEngine::get_video_driver();
i != m_nametags.end(); ++i) { v2u32 screensize = driver->getScreenSize();
Nametag *nametag = *i;
for (const Nametag *nametag : m_nametags) {
if (nametag->nametag_color.getAlpha() == 0) { if (nametag->nametag_color.getAlpha() == 0) {
// Enforce hiding nametag, // Enforce hiding nametag,
// because if freetype is enabled, a grey // because if freetype is enabled, a grey
@ -707,21 +708,29 @@ void Camera::drawNametags()
if (transformed_pos[3] > 0) { if (transformed_pos[3] > 0) {
std::wstring nametag_colorless = std::wstring nametag_colorless =
unescape_translate(utf8_to_wide(nametag->nametag_text)); unescape_translate(utf8_to_wide(nametag->nametag_text));
core::dimension2d<u32> textsize = core::dimension2d<u32> textsize = font->getDimension(
g_fontengine->getFont()->getDimension(
nametag_colorless.c_str()); nametag_colorless.c_str());
f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f : f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
core::reciprocal(transformed_pos[3]); core::reciprocal(transformed_pos[3]);
v2u32 screensize = RenderingEngine::get_video_driver()->getScreenSize();
v2s32 screen_pos; v2s32 screen_pos;
screen_pos.X = screensize.X * screen_pos.X = screensize.X *
(0.5 * transformed_pos[0] * zDiv + 0.5) - textsize.Width / 2; (0.5 * transformed_pos[0] * zDiv + 0.5) - textsize.Width / 2;
screen_pos.Y = screensize.Y * screen_pos.Y = screensize.Y *
(0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2; (0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2;
core::rect<s32> size(0, 0, textsize.Width, textsize.Height); 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(), translate_string(utf8_to_wide(nametag->nametag_text)).c_str(),
size + screen_pos, nametag->nametag_color); size + screen_pos, textColor);
} }
} }
} }

View File

@ -51,12 +51,8 @@ public:
~CAOShaderConstantSetter() override = default; ~CAOShaderConstantSetter() override = default;
void onSetConstants(video::IMaterialRendererServices *services, void onSetConstants(video::IMaterialRendererServices *services) override
bool is_highlevel) override
{ {
if (!is_highlevel)
return;
// Ambient color // Ambient color
video::SColorf emissive_color(m_emissive_color); video::SColorf emissive_color(m_emissive_color);

View File

@ -290,6 +290,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
*/ */
u32 vertex_count = 0; u32 vertex_count = 0;
u32 drawcall_count = 0;
// For limiting number of mesh animations per frame // For limiting number of mesh animations per frame
u32 mesh_animate_count = 0; u32 mesh_animate_count = 0;
@ -391,6 +392,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
} }
driver->setMaterial(list.m); driver->setMaterial(list.m);
drawcall_count += list.bufs.size();
for (auto &pair : list.bufs) { for (auto &pair : list.bufs) {
scene::IMeshBuffer *buf = pair.second; 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 + "vertices drawn [#]", vertex_count);
g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
} }
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step, static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,

View File

@ -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. // This is the child node's rotation. It is only used for automatic_rotate.
v3f local_rot = node->getRotation(); v3f local_rot = node->getRotation();
local_rot.Y = modulo360f(local_rot.Y - dtime * core::RADTODEG * 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 && 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 float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI
+ m_prop.automatic_face_movement_dir_offset; + m_prop.automatic_face_movement_dir_offset;
float max_rotation_per_sec = float max_rotation_per_sec =

View File

@ -519,7 +519,7 @@ bool Game::createClient(const GameStartData &start_data)
return false; return false;
} }
GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory( auto *scsf = new GameGlobalShaderConstantSetterFactory(
&m_flags.force_fog_off, &runData.fog_range, client); &m_flags.force_fog_off, &runData.fog_range, client);
shader_src->addShaderConstantSetterFactory(scsf); shader_src->addShaderConstantSetterFactory(scsf);
@ -529,20 +529,14 @@ bool Game::createClient(const GameStartData &start_data)
/* Camera /* Camera
*/ */
camera = new Camera(*draw_control, client); camera = new Camera(*draw_control, client);
if (!camera || !camera->successfullyCreated(*error_message)) if (!camera->successfullyCreated(*error_message))
return false; return false;
client->setCamera(camera); client->setCamera(camera);
/* Clouds /* Clouds
*/ */
if (m_cache_enable_clouds) { if (m_cache_enable_clouds)
clouds = new Clouds(smgr, -1, time(0)); clouds = new Clouds(smgr, -1, time(0));
if (!clouds) {
*error_message = "Memory allocation error (clouds)";
errorstream << *error_message << std::endl;
return false;
}
}
/* Skybox /* Skybox
*/ */
@ -550,12 +544,6 @@ bool Game::createClient(const GameStartData &start_data)
scsf->setSky(sky); scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop 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 /* Pre-calculated values
*/ */
video::ITexture *t = texture_src->getTexture("crack_anylength.png"); 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); 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(); mapper = client->getMinimap();
if (mapper && client->modsLoaded()) if (mapper && client->modsLoaded())
@ -682,9 +664,6 @@ bool Game::connectToServer(const GameStartData &start_data,
itemdef_manager, nodedef_manager, sound, eventmgr, itemdef_manager, nodedef_manager, sound, eventmgr,
connect_address.isIPv6(), m_game_ui.get()); connect_address.isIPv6(), m_game_ui.get());
if (!client)
return false;
client->m_simple_singleplayer_mode = simple_singleplayer_mode; client->m_simple_singleplayer_mode = simple_singleplayer_mode;
infostream << "Connecting to server at "; infostream << "Connecting to server at ";
@ -2415,8 +2394,8 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
wasKeyDown(KeyType::DIG); wasKeyDown(KeyType::DIG);
wasKeyDown(KeyType::PLACE); wasKeyDown(KeyType::PLACE);
input->joystick.clearWasKeyDown(KeyType::DIG); input->joystick.clearWasKeyPressed(KeyType::DIG);
input->joystick.clearWasKeyDown(KeyType::PLACE); input->joystick.clearWasKeyPressed(KeyType::PLACE);
input->joystick.clearWasKeyReleased(KeyType::DIG); input->joystick.clearWasKeyReleased(KeyType::DIG);
input->joystick.clearWasKeyReleased(KeyType::PLACE); input->joystick.clearWasKeyReleased(KeyType::PLACE);

View File

@ -203,7 +203,7 @@ struct LocalFormspecHandler : public TextDest
return; return;
} }
if (m_client && m_client->modsLoaded()) if (m_client->modsLoaded())
m_client->getScript()->on_formspec_input(m_formname, fields); m_client->getScript()->on_formspec_input(m_formname, fields);
} }
@ -492,12 +492,8 @@ public:
g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this); g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
} }
virtual void onSetConstants(video::IMaterialRendererServices *services, void onSetConstants(video::IMaterialRendererServices *services) override
bool is_highlevel)
{ {
if (!is_highlevel)
return;
// Background color // Background color
video::SColor bgcolor = m_sky->getBgColor(); video::SColor bgcolor = m_sky->getBgColor();
video::SColorf bgcolorf(bgcolor); video::SColorf bgcolorf(bgcolor);
@ -604,7 +600,7 @@ public:
virtual IShaderConstantSetter* create() virtual IShaderConstantSetter* create()
{ {
GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter( auto *scs = new GameGlobalShaderConstantSetter(
m_sky, m_force_fog_off, m_fog_range, m_client); m_sky, m_force_fog_off, m_fog_range, m_client);
if (!m_sky) if (!m_sky)
created_nosky.push_back(scs); created_nosky.push_back(scs);
@ -643,7 +639,6 @@ struct GameRunData {
bool btn_down_for_dig; bool btn_down_for_dig;
bool dig_instantly; bool dig_instantly;
bool digging_blocked; bool digging_blocked;
bool left_punch;
bool reset_jump_timer; bool reset_jump_timer;
float nodig_delay_timer; float nodig_delay_timer;
float dig_time; float dig_time;

View File

@ -100,7 +100,7 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
if (g_settings->getBool("enable_shaders")) { if (g_settings->getBool("enable_shaders")) {
IShaderSource *shdrsrc = client->getShaderSource(); IShaderSource *shdrsrc = client->getShaderSource();
u16 shader_id = shdrsrc->getShader( 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; m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
} else { } else {
m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@ -1055,9 +1055,9 @@ void drawItemStack(
if (def.type == ITEM_TOOL && item.wear != 0) { if (def.type == ITEM_TOOL && item.wear != 0) {
// Draw a progressbar // Draw a progressbar
float barheight = rect.getHeight() / 16; float barheight = static_cast<float>(rect.getHeight()) / 16;
float barpad_x = rect.getWidth() / 16; float barpad_x = static_cast<float>(rect.getWidth()) / 16;
float barpad_y = rect.getHeight() / 16; float barpad_y = static_cast<float>(rect.getHeight()) / 16;
core::rect<s32> progressrect( core::rect<s32> progressrect(
rect.UpperLeftCorner.X + barpad_x, rect.UpperLeftCorner.X + barpad_x,

View File

@ -290,7 +290,7 @@ public:
} }
virtual bool wasKeyPressed(GameKeyType k) 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) virtual bool wasKeyReleased(GameKeyType k)
{ {

View File

@ -37,7 +37,7 @@ bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
{ {
s16 ax_val = ev.Axis[axis_to_compare]; 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 // spares many characters
@ -48,7 +48,7 @@ JoystickLayout create_default_layout()
{ {
JoystickLayout jlo; JoystickLayout jlo;
jlo.axes_dead_border = 1024; jlo.axes_deadzone = g_settings->getU16("joystick_deadzone");
const JoystickAxisLayout axes[JA_COUNT] = { const JoystickAxisLayout axes[JA_COUNT] = {
{0, 1}, // JA_SIDEWARD_MOVE {0, 1}, // JA_SIDEWARD_MOVE
@ -93,14 +93,14 @@ JoystickLayout create_default_layout()
// Now about the buttons simulated by the axes // Now about the buttons simulated by the axes
// Movement buttons, important for vessels // Movement buttons, important for vessels
JLO_A_PB(KeyType::FORWARD, 1, 1, 1024); JLO_A_PB(KeyType::FORWARD, 1, 1, jlo.axes_deadzone);
JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024); JLO_A_PB(KeyType::BACKWARD, 1, -1, jlo.axes_deadzone);
JLO_A_PB(KeyType::LEFT, 0, 1, 1024); JLO_A_PB(KeyType::LEFT, 0, 1, jlo.axes_deadzone);
JLO_A_PB(KeyType::RIGHT, 0, -1, 1024); JLO_A_PB(KeyType::RIGHT, 0, -1, jlo.axes_deadzone);
// Scroll buttons // Scroll buttons
JLO_A_PB(KeyType::HOTBAR_PREV, 2, -1, 1024); JLO_A_PB(KeyType::HOTBAR_PREV, 2, -1, jlo.axes_deadzone);
JLO_A_PB(KeyType::HOTBAR_NEXT, 5, -1, 1024); JLO_A_PB(KeyType::HOTBAR_NEXT, 5, -1, jlo.axes_deadzone);
return jlo; return jlo;
} }
@ -109,7 +109,7 @@ JoystickLayout create_xbox_layout()
{ {
JoystickLayout jlo; JoystickLayout jlo;
jlo.axes_dead_border = 7000; jlo.axes_deadzone = 7000;
const JoystickAxisLayout axes[JA_COUNT] = { const JoystickAxisLayout axes[JA_COUNT] = {
{0, 1}, // JA_SIDEWARD_MOVE {0, 1}, // JA_SIDEWARD_MOVE
@ -146,10 +146,10 @@ JoystickLayout create_xbox_layout()
JLO_B_PB(KeyType::FREEMOVE, 1 << 16, 1 << 16); // down JLO_B_PB(KeyType::FREEMOVE, 1 << 16, 1 << 16); // down
// Movement buttons, important for vessels // Movement buttons, important for vessels
JLO_A_PB(KeyType::FORWARD, 1, 1, 1024); JLO_A_PB(KeyType::FORWARD, 1, 1, jlo.axes_deadzone);
JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024); JLO_A_PB(KeyType::BACKWARD, 1, -1, jlo.axes_deadzone);
JLO_A_PB(KeyType::LEFT, 0, 1, 1024); JLO_A_PB(KeyType::LEFT, 0, 1, jlo.axes_deadzone);
JLO_A_PB(KeyType::RIGHT, 0, -1, 1024); JLO_A_PB(KeyType::RIGHT, 0, -1, jlo.axes_deadzone);
return jlo; 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++) { for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
if (keys_pressed[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_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; m_past_pressed_time[i] = m_internal_time;
} }
} else if (m_pressed_keys[i]) { } else if (m_keys_down[i]) {
m_past_released_keys[i] = true; 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++) { 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]; m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
} }
return true; return true;
} }
void JoystickController::clear() void JoystickController::clear()
{ {
m_pressed_keys.reset(); m_keys_pressed.reset();
m_past_pressed_keys.reset(); m_keys_down.reset();
m_past_released_keys.reset(); m_past_keys_pressed.reset();
m_keys_released.reset();
memset(m_axes_vals, 0, sizeof(m_axes_vals)); memset(m_axes_vals, 0, sizeof(m_axes_vals));
} }
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis) s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
{ {
s16 v = m_axes_vals[axis]; s16 v = m_axes_vals[axis];
if (((v > 0) && (v < m_layout.axes_dead_border)) || if (abs(v) < m_layout.axes_deadzone)
((v < 0) && (v > -m_layout.axes_dead_border)))
return 0; return 0;
return v; return v;
} }

View File

@ -96,7 +96,7 @@ struct JoystickLayout {
std::vector<JoystickButtonCmb> button_keys; std::vector<JoystickButtonCmb> button_keys;
std::vector<JoystickAxisCmb> axis_keys; std::vector<JoystickAxisCmb> axis_keys;
JoystickAxisLayout axes[JA_COUNT]; JoystickAxisLayout axes[JA_COUNT];
s16 axes_dead_border; s16 axes_deadzone;
}; };
class JoystickController { class JoystickController {
@ -111,37 +111,32 @@ public:
bool wasKeyDown(GameKeyType b) bool wasKeyDown(GameKeyType b)
{ {
bool r = m_past_pressed_keys[b]; bool r = m_past_keys_pressed[b];
m_past_pressed_keys[b] = false; m_past_keys_pressed[b] = false;
return r; return r;
} }
bool getWasKeyDown(GameKeyType b)
{
return m_past_pressed_keys[b];
}
void clearWasKeyDown(GameKeyType b)
{
m_past_pressed_keys[b] = false;
}
bool wasKeyReleased(GameKeyType b) bool wasKeyReleased(GameKeyType b)
{ {
bool r = m_past_released_keys[b]; return m_keys_released[b];
m_past_released_keys[b] = false;
return r;
}
bool getWasKeyReleased(GameKeyType b)
{
return m_past_pressed_keys[b];
} }
void clearWasKeyReleased(GameKeyType b) void clearWasKeyReleased(GameKeyType b)
{ {
m_past_pressed_keys[b] = false; m_keys_released[b] = false;
}
bool wasKeyPressed(GameKeyType b)
{
return m_keys_pressed[b];
}
void clearWasKeyPressed(GameKeyType b)
{
m_keys_pressed[b] = false;
} }
bool isKeyDown(GameKeyType b) bool isKeyDown(GameKeyType b)
{ {
return m_pressed_keys[b]; return m_keys_down[b];
} }
s16 getAxis(JoystickAxis axis) s16 getAxis(JoystickAxis axis)
@ -162,12 +157,13 @@ private:
u8 m_joystick_id = 0; 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_internal_time;
f32 m_past_pressed_time[KeyType::INTERNAL_ENUM_COUNT]; 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_keys_pressed;
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_released_keys; std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_released;
}; };

View File

@ -1269,13 +1269,13 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
MapBlockMesh::~MapBlockMesh() MapBlockMesh::~MapBlockMesh()
{ {
for (scene::IMesh *m : m_mesh) { for (scene::IMesh *m : m_mesh) {
if (m_enable_vbo && m) if (m_enable_vbo) {
for (u32 i = 0; i < m->getMeshBufferCount(); i++) { for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
scene::IMeshBuffer *buf = m->getMeshBuffer(i); scene::IMeshBuffer *buf = m->getMeshBuffer(i);
RenderingEngine::get_video_driver()->removeHardwareBuffer(buf); RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
} }
}
m->drop(); m->drop();
m = NULL;
} }
delete m_minimap_mapblock; delete m_minimap_mapblock;
} }

View File

@ -612,7 +612,7 @@ void Minimap::drawMinimap(core::rect<s32> rect) {
material.TextureLayer[1].Texture = data->heightmap_texture; material.TextureLayer[1].Texture = data->heightmap_texture;
if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) { 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; material.MaterialType = m_shdrsrc->getShaderInfo(sid).material;
} else { } else {
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;

View File

@ -36,7 +36,7 @@ void RenderingCoreInterlaced::initMaterial()
mat.UseMipMaps = false; mat.UseMipMaps = false;
mat.ZBuffer = false; mat.ZBuffer = false;
mat.ZWriteEnable = 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; mat.MaterialType = s->getShaderInfo(shader).material;
for (int k = 0; k < 3; ++k) { for (int k = 0; k < 3; ++k) {
mat.TextureLayer[k].AnisotropicFilter = false; mat.TextureLayer[k].AnisotropicFilter = false;

View File

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iterator> #include <iterator>
#include "shader.h" #include "shader.h"
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "irr_ptr.h"
#include "debug.h" #include "debug.h"
#include "filesys.h" #include "filesys.h"
#include "util/container.h" #include "util/container.h"
@ -189,19 +190,14 @@ private:
class ShaderCallback : public video::IShaderConstantSetCallBack class ShaderCallback : public video::IShaderConstantSetCallBack
{ {
std::vector<IShaderConstantSetter*> m_setters; std::vector<std::unique_ptr<IShaderConstantSetter>> m_setters;
public: public:
ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories) template <typename Factories>
ShaderCallback(const Factories &factories)
{ {
for (IShaderConstantSetterFactory *factory : factories) for (auto &&factory : factories)
m_setters.push_back(factory->create()); m_setters.push_back(std::unique_ptr<IShaderConstantSetter>(factory->create()));
}
~ShaderCallback()
{
for (IShaderConstantSetter *setter : m_setters)
delete setter;
} }
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
@ -209,15 +205,13 @@ public:
video::IVideoDriver *driver = services->getVideoDriver(); video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver != NULL); sanity_check(driver != NULL);
bool is_highlevel = userData; for (auto &&setter : m_setters)
setter->onSetConstants(services);
for (IShaderConstantSetter *setter : m_setters)
setter->onSetConstants(services, is_highlevel);
} }
virtual void OnSetMaterial(const video::SMaterial& material) override virtual void OnSetMaterial(const video::SMaterial& material) override
{ {
for (IShaderConstantSetter *setter : m_setters) for (auto &&setter : m_setters)
setter->onSetMaterial(material); setter->onSetMaterial(material);
} }
}; };
@ -252,47 +246,39 @@ public:
{} {}
~MainShaderConstantSetter() = default; ~MainShaderConstantSetter() = default;
virtual void onSetConstants(video::IMaterialRendererServices *services, virtual void onSetConstants(video::IMaterialRendererServices *services) override
bool is_highlevel)
{ {
video::IVideoDriver *driver = services->getVideoDriver(); video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver); sanity_check(driver);
// Set world matrix // Set world matrix
core::matrix4 world = driver->getTransform(video::ETS_WORLD); core::matrix4 world = driver->getTransform(video::ETS_WORLD);
if (is_highlevel) m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
else
services->setVertexShaderConstant(world.pointer(), 4, 4);
// Set clip matrix // Set clip matrix
core::matrix4 worldView; core::matrix4 worldView;
worldView = driver->getTransform(video::ETS_VIEW); worldView = driver->getTransform(video::ETS_VIEW);
worldView *= world; worldView *= world;
core::matrix4 worldViewProj; core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION); worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= worldView; worldViewProj *= worldView;
if (is_highlevel) m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
else
services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
#if ENABLE_GLES #if ENABLE_GLES
if (is_highlevel) { core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0); m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services); m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
core::matrix4 normal; core::matrix4 normal;
worldView.getTransposed(normal); worldView.getTransposed(normal);
sanity_check(normal.makeInverse()); sanity_check(normal.makeInverse());
float m[9] = { float m[9] = {
normal[0], normal[1], normal[2], normal[0], normal[1], normal[2],
normal[4], normal[5], normal[6], normal[4], normal[5], normal[6],
normal[8], normal[9], normal[10], normal[8], normal[9], normal[10],
}; };
m_normal.set(m, services); m_normal.set(m, services);
}
#endif #endif
} }
}; };
@ -314,7 +300,6 @@ class ShaderSource : public IWritableShaderSource
{ {
public: public:
ShaderSource(); ShaderSource();
~ShaderSource();
/* /*
- If shader material specified by name is found from cache, - 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. The id 0 points to a null shader. Its material is EMT_SOLID.
*/ */
u32 getShaderIdDirect(const std::string &name, 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 If shader specified by the name pointed by the id doesn't
@ -336,26 +321,26 @@ public:
*/ */
u32 getShader(const std::string &name, 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. // Processes queued shader requests from other threads.
// Shall be called from the main thread. // Shall be called from the main thread.
void processQueue(); void processQueue() override;
// Insert a shader program into the cache without touching the // Insert a shader program into the cache without touching the
// filesystem. Shall be called from the main thread. // filesystem. Shall be called from the main thread.
void insertSourceShader(const std::string &name_of_shader, 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 // Rebuild shaders from the current set of source shaders
// Shall be called from the main thread. // 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: private:
@ -377,10 +362,11 @@ private:
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue; RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
// Global constant setter factories // Global constant setter factories
std::vector<IShaderConstantSetterFactory *> m_setter_factories; std::vector<std::unique_ptr<IShaderConstantSetterFactory>> m_setter_factories;
// Shader callbacks // Generate shader given the shader name.
std::vector<ShaderCallback *> m_callbacks; ShaderInfo generateShader(const std::string &name,
MaterialType material_type, NodeDrawType drawtype);
}; };
IWritableShaderSource *createShaderSource() IWritableShaderSource *createShaderSource()
@ -388,22 +374,6 @@ IWritableShaderSource *createShaderSource()
return new ShaderSource(); 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() ShaderSource::ShaderSource()
{ {
m_main_thread = std::this_thread::get_id(); m_main_thread = std::this_thread::get_id();
@ -415,18 +385,8 @@ ShaderSource::ShaderSource()
addShaderConstantSetterFactory(new MainShaderConstantSetterFactory()); 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, u32 ShaderSource::getShader(const std::string &name,
const u8 material_type, const u8 drawtype) MaterialType material_type, NodeDrawType drawtype)
{ {
/* /*
Get shader Get shader
@ -468,7 +428,7 @@ u32 ShaderSource::getShader(const std::string &name,
This method generates all the shaders This method generates all the shaders
*/ */
u32 ShaderSource::getShaderIdDirect(const std::string &name, 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; //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
@ -495,8 +455,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
return 0; return 0;
} }
ShaderInfo info = generate_shader(name, material_type, drawtype, ShaderInfo info = generateShader(name, material_type, drawtype);
m_callbacks, m_setter_factories, &m_sourcecache);
/* /*
Add shader to caches (add dummy shaders too) Add shader to caches (add dummy shaders too)
@ -560,18 +519,14 @@ void ShaderSource::rebuildShaders()
for (ShaderInfo &i : m_shaderinfo_cache) { for (ShaderInfo &i : m_shaderinfo_cache) {
ShaderInfo *info = &i; ShaderInfo *info = &i;
if (!info->name.empty()) { if (!info->name.empty()) {
*info = generate_shader(info->name, info->material_type, *info = generateShader(info->name, info->material_type, info->drawtype);
info->drawtype, m_callbacks,
m_setter_factories, &m_sourcecache);
} }
} }
} }
ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype, ShaderInfo ShaderSource::generateShader(const std::string &name,
std::vector<ShaderCallback *> &callbacks, MaterialType material_type, NodeDrawType drawtype)
const std::vector<IShaderConstantSetterFactory *> &setter_factories,
SourceShaderCache *sourcecache)
{ {
ShaderInfo shaderinfo; ShaderInfo shaderinfo;
shaderinfo.name = name; shaderinfo.name = name;
@ -604,64 +559,27 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
return shaderinfo; return shaderinfo;
video::IVideoDriver *driver = RenderingEngine::get_video_driver(); video::IVideoDriver *driver = RenderingEngine::get_video_driver();
if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
return shaderinfo;
}
video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices(); video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
if(!gpu){
errorstream<<"generate_shader(): "
"failed to generate \""<<name<<"\", "
"GPU programming not supported."
<<std::endl;
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;
// Create shaders header // Create shaders header
bool use_gles = false; bool use_gles = false;
#if ENABLE_GLES #if ENABLE_GLES
use_gles = driver->getDriverType() == video::EDT_OGLES2; use_gles = driver->getDriverType() == video::EDT_OGLES2;
#endif #endif
std::string shaders_header, vertex_header, pixel_header; // geometry shaders arent 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) { if (use_gles) {
shaders_header = shaders_header << R"(
"#version 100\n" #version 100
; )";
vertex_header = R"( vertex_header = R"(
uniform highp mat4 mWorldView; uniform highp mat4 mWorldView;
uniform highp mat4 mWorldViewProj; 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 inVertexTangent;
attribute mediump vec4 inVertexBinormal; attribute mediump vec4 inVertexBinormal;
)"; )";
pixel_header = R"( fragment_header = R"(
precision mediump float; precision mediump float;
)"; )";
} else { } else {
shaders_header = R"( shaders_header << R"(
#version 120 #version 120
#define lowp #define lowp
#define mediump #define mediump
@ -708,224 +626,97 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
use_discard = true; use_discard = true;
#endif #endif
if (use_discard && shaderinfo.base_material != video::EMT_SOLID) if (use_discard && shaderinfo.base_material != video::EMT_SOLID)
shaders_header += "#define USE_DISCARD\n"; shaders_header << "#define USE_DISCARD 1\n";
static const char* drawTypes[] = { #define PROVIDE(constant) shaders_header << "#define " #constant " " << (int)constant << "\n"
"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++){ PROVIDE(NDT_NORMAL);
shaders_header += "#define "; PROVIDE(NDT_AIRLIKE);
shaders_header += drawTypes[i]; PROVIDE(NDT_LIQUID);
shaders_header += " "; PROVIDE(NDT_FLOWINGLIQUID);
shaders_header += itos(i); PROVIDE(NDT_GLASSLIKE);
shaders_header += "\n"; 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";
} }
static const char* materialTypes[] = { shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
"TILE_MATERIAL_BASIC", shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
"TILE_MATERIAL_ALPHA", shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n";
"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 FOG_START " << core::clamp(g_settings->getFloat("fog_start"), 0.0f, 0.99f) << "\n";
shaders_header += "#define ";
shaders_header += materialTypes[i]; std::string common_header = shaders_header.str();
shaders_header += " ";
shaders_header += itos(i); std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
shaders_header += "\n"; 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();
} }
shaders_header += "#define MATERIAL_TYPE "; irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
shaders_header += itos(material_type); infostream<<"Compiling high level shaders for "<<name<<std::endl;
shaders_header += "\n"; s32 shadermat = gpu->addHighLevelShaderMaterial(
shaders_header += "#define DRAW_TYPE "; vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
shaders_header += itos(drawtype); fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
shaders_header += "\n"; geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
cb.get(), shaderinfo.base_material, 1);
if (g_settings->getBool("enable_waving_water")){ if (shadermat == -1) {
shaders_header += "#define ENABLE_WAVING_WATER 1\n"; errorstream<<"generate_shader(): "
shaders_header += "#define WATER_WAVE_HEIGHT "; "failed to generate \""<<name<<"\", "
shaders_header += std::to_string(g_settings->getFloat("water_wave_height")); "addHighLevelShaderMaterial failed."
shaders_header += "\n"; <<std::endl;
shaders_header += "#define WATER_WAVE_LENGTH "; dumpShaderProgram(warningstream, "Vertex", vertex_shader);
shaders_header += std::to_string(g_settings->getFloat("water_wave_length")); dumpShaderProgram(warningstream, "Fragment", fragment_shader);
shaders_header += "\n"; dumpShaderProgram(warningstream, "Geometry", geometry_shader);
shaders_header += "#define WATER_WAVE_SPEED "; return shaderinfo;
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;
}
}
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 // Apply the newly created material type
shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat; shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
return shaderinfo; 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, void dumpShaderProgram(std::ostream &output_stream,
const std::string &program_type, const std::string &program) const std::string &program_type, const std::string &program)
{ {

View File

@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IMaterialRendererServices.h> #include <IMaterialRendererServices.h>
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include <string> #include <string>
#include "tile.h"
#include "nodedef.h"
class IGameDef; class IGameDef;
@ -46,8 +48,8 @@ struct ShaderInfo {
std::string name = ""; std::string name = "";
video::E_MATERIAL_TYPE base_material = video::EMT_SOLID; video::E_MATERIAL_TYPE base_material = video::EMT_SOLID;
video::E_MATERIAL_TYPE material = video::EMT_SOLID; video::E_MATERIAL_TYPE material = video::EMT_SOLID;
u8 drawtype = 0; NodeDrawType drawtype = NDT_NORMAL;
u8 material_type = 0; MaterialType material_type = TILE_MATERIAL_BASIC;
ShaderInfo() = default; ShaderInfo() = default;
virtual ~ShaderInfo() = default; virtual ~ShaderInfo() = default;
@ -65,8 +67,7 @@ namespace irr { namespace video {
class IShaderConstantSetter { class IShaderConstantSetter {
public: public:
virtual ~IShaderConstantSetter() = default; virtual ~IShaderConstantSetter() = default;
virtual void onSetConstants(video::IMaterialRendererServices *services, virtual void onSetConstants(video::IMaterialRendererServices *services) = 0;
bool is_highlevel) = 0;
virtual void onSetMaterial(const video::SMaterial& material) virtual void onSetMaterial(const video::SMaterial& material)
{ } { }
}; };
@ -128,10 +129,10 @@ public:
virtual ~IShaderSource() = default; virtual ~IShaderSource() = default;
virtual u32 getShaderIdDirect(const std::string &name, 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 ShaderInfo getShaderInfo(u32 id){return ShaderInfo();}
virtual u32 getShader(const std::string &name, 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 { class IWritableShaderSource : public IShaderSource {
@ -139,16 +140,12 @@ public:
IWritableShaderSource() = default; IWritableShaderSource() = default;
virtual ~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 processQueue()=0;
virtual void insertSourceShader(const std::string &name_of_shader, virtual void insertSourceShader(const std::string &name_of_shader,
const std::string &filename, const std::string &program)=0; const std::string &filename, const std::string &program)=0;
virtual void rebuildShaders()=0; virtual void rebuildShaders()=0;
/// @note Takes ownership of @p setter.
virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0; virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0;
}; };

View File

@ -65,7 +65,7 @@ Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) :
// Create materials // Create materials
m_materials[0] = baseMaterial(); 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].Lighting = true;
m_materials[0].ColorMaterial = video::ECM_NONE; m_materials[0].ColorMaterial = video::ECM_NONE;

View File

@ -1633,6 +1633,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
/* IMPORTANT: When changing this, getTextureForMesh() needs to be /* IMPORTANT: When changing this, getTextureForMesh() needs to be
* updated too. */ * 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. // Apply the "clean transparent" filter, if configured.
if (g_settings->getBool("texture_clean_transparent")) if (g_settings->getBool("texture_clean_transparent"))
imageCleanTransparent(baseimg, 127); imageCleanTransparent(baseimg, 127);

View File

@ -347,6 +347,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("joystick_type", ""); settings->setDefault("joystick_type", "");
settings->setDefault("repeat_joystick_button_time", "0.17"); settings->setDefault("repeat_joystick_button_time", "0.17");
settings->setDefault("joystick_frustum_sensitivity", "170"); settings->setDefault("joystick_frustum_sensitivity", "170");
settings->setDefault("joystick_deadzone", "2048");
// Main menu // Main menu
settings->setDefault("main_menu_path", ""); 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_per_10sec", "8.0");
settings->setDefault("chat_message_limit_trigger_kick", "50"); settings->setDefault("chat_message_limit_trigger_kick", "50");
settings->setDefault("sqlite_synchronous", "2"); 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("full_block_send_enable_min_time_from_building", "2.0");
settings->setDefault("dedicated_server_step", "0.09"); settings->setDefault("dedicated_server_step", "0.09");
settings->setDefault("active_block_mgmt_interval", "2.0"); 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("fps_max_unfocused", "10");
settings->setDefault("max_objects_per_block", "20"); settings->setDefault("max_objects_per_block", "20");
settings->setDefault("sqlite_synchronous", "1"); 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("server_map_save_interval", "15");
settings->setDefault("client_mapblock_limit", "1000"); settings->setDefault("client_mapblock_limit", "1000");
settings->setDefault("active_block_range", "2"); settings->setDefault("active_block_range", "2");

View File

@ -295,31 +295,26 @@ bool RecursiveDelete(const std::string &path)
infostream<<"Removing \""<<path<<"\""<<std::endl; infostream<<"Removing \""<<path<<"\""<<std::endl;
//return false;
pid_t child_pid = fork(); pid_t child_pid = fork();
if(child_pid == 0) if(child_pid == 0)
{ {
// Child // Child
char argv_data[3][10000]; const char *argv[4] = {
#ifdef __ANDROID__ #ifdef __ANDROID__
strcpy(argv_data[0], "/system/bin/rm"); "/system/bin/rm",
#else #else
strcpy(argv_data[0], "/bin/rm"); "/bin/rm",
#endif #endif
strcpy(argv_data[1], "-rf"); "-rf",
strncpy(argv_data[2], path.c_str(), sizeof(argv_data[2]) - 1); path.c_str(),
char *argv[4]; NULL
argv[0] = argv_data[0]; };
argv[1] = argv_data[1];
argv[2] = argv_data[2];
argv[3] = NULL;
verbosestream<<"Executing '"<<argv[0]<<"' '"<<argv[1]<<"' '" verbosestream<<"Executing '"<<argv[0]<<"' '"<<argv[1]<<"' '"
<<argv[2]<<"'"<<std::endl; <<argv[2]<<"'"<<std::endl;
execv(argv[0], argv); execv(argv[0], const_cast<char**>(argv));
// Execv shouldn't return. Failed. // Execv shouldn't return. Failed.
_exit(1); _exit(1);
@ -331,7 +326,6 @@ bool RecursiveDelete(const std::string &path)
pid_t tpid; pid_t tpid;
do{ do{
tpid = wait(&child_status); tpid = wait(&child_status);
//if(tpid != child_pid) process_terminated(tpid);
}while(tpid != child_pid); }while(tpid != child_pid);
return (child_status == 0); return (child_status == 0);
} }

View File

@ -8,6 +8,7 @@ set(gui_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/guiButtonItemImage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiButtonItemImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp

95
src/gui/guiEditBox.cpp Normal file
View File

@ -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;
}

103
src/gui/guiEditBox.h Normal file
View File

@ -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);
};

View File

@ -22,16 +22,14 @@ optional? dragging selected text
numerical numerical
*/ */
//! constructor //! constructor
GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool border, GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool border,
IGUIEnvironment* environment, IGUIElement* parent, s32 id, IGUIEnvironment* environment, IGUIElement* parent, s32 id,
const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar) const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
: IGUIEditBox(environment, parent, id, rectangle), m_mouse_marking(false), : GUIEditBox(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_border(border), m_background(true), m_mark_begin(0), m_mark_end(0), m_last_break_font(0),
m_override_color(video::SColor(101, 255, 255, 255)), m_override_font(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_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_passwordchar(L'*'), m_halign(EGUIA_UPPERLEFT), m_valign(EGUIA_CENTER),
m_current_text_rect(0, 0, 1, 1), m_frame_rect(rectangle), m_current_text_rect(0, 0, 1, 1), m_frame_rect(rectangle),
m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable), m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable),
@ -69,9 +67,6 @@ GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool borde
//! destructor //! destructor
GUIEditBoxWithScrollBar::~GUIEditBoxWithScrollBar() GUIEditBoxWithScrollBar::~GUIEditBoxWithScrollBar()
{ {
if (m_override_font)
m_override_font->drop();
if (m_operator) if (m_operator)
m_operator->drop(); 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 //! Turns the border on or off
void GUIEditBoxWithScrollBar::setDrawBorder(bool border) void GUIEditBoxWithScrollBar::setDrawBorder(bool border)
{ {
@ -140,24 +87,6 @@ void GUIEditBoxWithScrollBar::setDrawBackground(bool draw)
m_background = 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() 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) 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 //! Gets the area of the text in the edit box
//! \return Returns the size in pixels of the text //! \return Returns the size in pixels of the text
core::dimension2du GUIEditBoxWithScrollBar::getTextDimension() core::dimension2du GUIEditBoxWithScrollBar::getTextDimension()

View File

@ -5,15 +5,10 @@
#ifndef GUIEDITBOXWITHSCROLLBAR_HEADER #ifndef GUIEDITBOXWITHSCROLLBAR_HEADER
#define GUIEDITBOXWITHSCROLLBAR_HEADER #define GUIEDITBOXWITHSCROLLBAR_HEADER
#include "IGUIEditBox.h" #include "guiEditBox.h"
#include "IOSOperator.h"
#include "guiScrollBar.h"
#include <vector> #include <vector>
using namespace irr; class GUIEditBoxWithScrollBar : public GUIEditBox
using namespace irr::gui;
class GUIEditBoxWithScrollBar : public IGUIEditBox
{ {
public: public:
@ -25,61 +20,13 @@ public:
//! destructor //! destructor
virtual ~GUIEditBoxWithScrollBar(); 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 //! Sets whether to draw the background
virtual void setDrawBackground(bool draw); virtual void setDrawBackground(bool draw);
//! Turns the border on or off //! Turns the border on or off
virtual void setDrawBorder(bool border); 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 //! Gets the size area of the text in the edit box
//! \return Returns the size in pixels of the text //! \return Returns the size in pixels of the text
@ -137,7 +84,7 @@ public:
protected: protected:
//! Breaks the single text line. //! Breaks the single text line.
void breakText(); virtual void breakText();
//! sets the area of the given line //! sets the area of the given line
void setTextRect(s32 line); void setTextRect(s32 line);
//! returns the line number that the cursor is on //! returns the line number that the cursor is on
@ -164,12 +111,11 @@ protected:
bool m_mouse_marking; bool m_mouse_marking;
bool m_border; bool m_border;
bool m_background; bool m_background;
bool m_override_color_enabled;
s32 m_mark_begin; s32 m_mark_begin;
s32 m_mark_end; s32 m_mark_end;
video::SColor m_override_color; gui::IGUIFont *m_last_break_font;
gui::IGUIFont *m_override_font, *m_last_break_font;
IOSOperator* m_operator; IOSOperator* m_operator;
u32 m_blink_start_time; u32 m_blink_start_time;
@ -177,7 +123,7 @@ protected:
s32 m_hscroll_pos, m_vscroll_pos; // scroll position in characters s32 m_hscroll_pos, m_vscroll_pos; // scroll position in characters
u32 m_max; u32 m_max;
bool m_word_wrap, m_multiline, m_autoscroll, m_passwordbox; bool m_passwordbox;
wchar_t m_passwordchar; wchar_t m_passwordchar;
EGUI_ALIGNMENT m_halign, m_valign; EGUI_ALIGNMENT m_halign, m_valign;

View File

@ -70,7 +70,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MY_CHECKPOS(a,b) \ #define MY_CHECKPOS(a,b) \
if (v_pos.size() != 2) { \ if (v_pos.size() != 2) { \
errorstream<< "Invalid pos for element " << a << "specified: \"" \ errorstream<< "Invalid pos for element " << a << " specified: \"" \
<< parts[b] << "\"" << std::endl; \ << parts[b] << "\"" << std::endl; \
return; \ return; \
} }
@ -78,7 +78,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MY_CHECKGEOM(a,b) \ #define MY_CHECKGEOM(a,b) \
if (v_geom.size() != 2) { \ if (v_geom.size() != 2) { \
errorstream<< "Invalid geometry for element " << a << \ errorstream<< "Invalid geometry for element " << a << \
"specified: \"" << parts[b] << "\"" << std::endl; \ " specified: \"" << parts[b] << "\"" << std::endl; \
return; \ return; \
} }
/* /*
@ -2725,7 +2725,7 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
{ {
std::vector<std::string> parts = split(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)) { m_formspec_version <= FORMSPEC_API_VERSION)) {
errorstream << "Invalid model element (" << parts.size() << "): '" << element errorstream << "Invalid model element (" << parts.size() << "): '" << element
<< "'" << std::endl; << "'" << std::endl;
@ -2733,8 +2733,8 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
} }
// Avoid length checks by resizing // Avoid length checks by resizing
if (parts.size() < 8) if (parts.size() < 9)
parts.resize(8); parts.resize(9);
std::vector<std::string> v_pos = split(parts[0], ','); std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ','); 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], ','); std::vector<std::string> vec_rot = split(parts[5], ',');
bool inf_rotation = is_yes(parts[6]); bool inf_rotation = is_yes(parts[6]);
bool mousectrl = is_yes(parts[7]) || parts[7].empty(); // default true 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_CHECKPOS("model", 0);
MY_CHECKGEOM("model", 1); MY_CHECKGEOM("model", 1);
@ -2786,7 +2787,7 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
auto meshnode = e->setMesh(mesh); auto meshnode = e->setMesh(mesh);
for (u32 i = 0; i < textures.size() && i < meshnode->getMaterialCount(); ++i) 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) if (vec_rot.size() >= 2)
e->setRotation(v2f(stof(vec_rot[0]), stof(vec_rot[1]))); 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->enableContinuousRotation(inf_rotation);
e->enableMouseControl(mousectrl); 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); auto style = getStyleForElement("model", spec.fname);
e->setStyles(style); e->setStyles(style);
e->drop(); e->drop();
@ -3707,7 +3718,8 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
{ {
EnrichedString ntext(text); EnrichedString ntext(text);
ntext.setDefaultColor(color); ntext.setDefaultColor(color);
ntext.setBackground(bgcolor); if (!ntext.hasBackground())
ntext.setBackground(bgcolor);
setStaticText(m_tooltip_element, ntext); setStaticText(m_tooltip_element, ntext);

View File

@ -152,6 +152,15 @@ void GUIScene::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &sty
setBackgroundColor(style.getColor(StyleSpec::BGCOLOR, m_bgcolor)); 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 */ /* Camera control functions */
inline void GUIScene::calcOptimalDistance() inline void GUIScene::calcOptimalDistance()

View File

@ -36,6 +36,7 @@ public:
scene::IAnimatedMeshSceneNode *setMesh(scene::IAnimatedMesh *mesh = nullptr); scene::IAnimatedMeshSceneNode *setMesh(scene::IAnimatedMesh *mesh = nullptr);
void setTexture(u32 idx, video::ITexture *texture); void setTexture(u32 idx, video::ITexture *texture);
void setBackgroundColor(const video::SColor &color) noexcept { m_bgcolor = color; }; 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 enableMouseControl(bool enable) noexcept { m_mouse_ctrl = enable; };
void setRotation(v2f rot) noexcept { m_custom_rot = rot; }; void setRotation(v2f rot) noexcept { m_custom_rot = rot; };
void enableContinuousRotation(bool enable) noexcept { m_inf_rot = enable; }; void enableContinuousRotation(bool enable) noexcept { m_inf_rot = enable; };

View File

@ -59,7 +59,7 @@ namespace gui
intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border, intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
IGUIEnvironment* environment, IGUIElement* parent, s32 id, IGUIEnvironment* environment, IGUIElement* parent, s32 id,
const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar) const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
: IGUIEditBox(environment, parent, id, rectangle), : GUIEditBox(environment, parent, id, rectangle),
Border(border), FrameRect(rectangle), Border(border), FrameRect(rectangle),
m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable) m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable)
{ {
@ -108,9 +108,6 @@ intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
//! destructor //! destructor
intlGUIEditBox::~intlGUIEditBox() intlGUIEditBox::~intlGUIEditBox()
{ {
if (OverrideFont)
OverrideFont->drop();
if (Operator) if (Operator)
Operator->drop(); Operator->drop();
@ -118,52 +115,6 @@ intlGUIEditBox::~intlGUIEditBox()
m_vscrollbar->drop(); 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 //! Turns the border on or off
void intlGUIEditBox::setDrawBorder(bool border) 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() void intlGUIEditBox::updateAbsolutePosition()
{ {
core::rect<s32> oldAbsoluteRect(AbsoluteRect); 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) void intlGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar)
{ {
PasswordBox = passwordBox; PasswordBox = passwordBox;
@ -464,7 +374,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
case KEY_END: case KEY_END:
{ {
s32 p = Text.size(); s32 p = Text.size();
if (WordWrap || MultiLine) if (m_word_wrap || m_multiline)
{ {
p = getLineFromPos(CursorPos); p = getLineFromPos(CursorPos);
p = BrokenTextPositions[p] + (s32)BrokenText[p].size(); p = BrokenTextPositions[p] + (s32)BrokenText[p].size();
@ -492,7 +402,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
{ {
s32 p = 0; s32 p = 0;
if (WordWrap || MultiLine) if (m_word_wrap || m_multiline)
{ {
p = getLineFromPos(CursorPos); p = getLineFromPos(CursorPos);
p = BrokenTextPositions[p]; p = BrokenTextPositions[p];
@ -514,7 +424,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
} }
break; break;
case KEY_RETURN: case KEY_RETURN:
if (MultiLine) if (m_multiline)
{ {
inputChar(L'\n'); inputChar(L'\n');
return true; return true;
@ -567,7 +477,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
BlinkStartTime = porting::getTimeMs(); BlinkStartTime = porting::getTimeMs();
break; break;
case KEY_UP: case KEY_UP:
if (MultiLine || (WordWrap && BrokenText.size() > 1) ) if (m_multiline || (m_word_wrap && BrokenText.size() > 1) )
{ {
s32 lineNo = getLineFromPos(CursorPos); s32 lineNo = getLineFromPos(CursorPos);
s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd); s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd);
@ -598,7 +508,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
} }
break; break;
case KEY_DOWN: case KEY_DOWN:
if (MultiLine || (WordWrap && BrokenText.size() > 1) ) if (m_multiline || (m_word_wrap && BrokenText.size() > 1) )
{ {
s32 lineNo = getLineFromPos(CursorPos); s32 lineNo = getLineFromPos(CursorPos);
s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd); s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd);
@ -791,8 +701,8 @@ void intlGUIEditBox::draw()
// draw the text // draw the text
IGUIFont* font = OverrideFont; IGUIFont* font = m_override_font;
if (!OverrideFont) if (!m_override_font)
font = skin->getFont(); font = skin->getFont();
s32 cursorLine = 0; s32 cursorLine = 0;
@ -813,7 +723,7 @@ void intlGUIEditBox::draw()
core::stringw s, s2; core::stringw s, s2;
// get mark position // 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 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin; const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0; const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0;
@ -822,14 +732,14 @@ void intlGUIEditBox::draw()
// Save the override color information. // Save the override color information.
// Then, alter it if the edit box is disabled. // Then, alter it if the edit box is disabled.
const bool prevOver = OverrideColorEnabled; const bool prevOver = m_override_color_enabled;
const video::SColor prevColor = OverrideColor; const video::SColor prevColor = m_override_color;
if (!Text.empty()) { if (!Text.empty()) {
if (!IsEnabled && !OverrideColorEnabled) if (!IsEnabled && !m_override_color_enabled)
{ {
OverrideColorEnabled = true; m_override_color_enabled = true;
OverrideColor = skin->getColor(EGDC_GRAY_TEXT); m_override_color = skin->getColor(EGDC_GRAY_TEXT);
} }
for (s32 i=0; i < lineCount; ++i) for (s32 i=0; i < lineCount; ++i)
@ -870,7 +780,7 @@ void intlGUIEditBox::draw()
// draw normal text // draw normal text
font->draw(txtLine->c_str(), CurrentTextRect, 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); false, true, &localClipRect);
// draw mark and marked text // draw mark and marked text
@ -914,20 +824,20 @@ void intlGUIEditBox::draw()
if (!s.empty()) if (!s.empty())
font->draw(s.c_str(), CurrentTextRect, 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); false, true, &localClipRect);
} }
} }
// Return the override color information to its previous settings. // Return the override color information to its previous settings.
OverrideColorEnabled = prevOver; m_override_color_enabled = prevOver;
OverrideColor = prevColor; m_override_color = prevColor;
} }
// draw cursor // draw cursor
if (WordWrap || MultiLine) if (m_word_wrap || m_multiline)
{ {
cursorLine = getLineFromPos(CursorPos); cursorLine = getLineFromPos(CursorPos);
txtLine = &BrokenText[cursorLine]; txtLine = &BrokenText[cursorLine];
@ -943,7 +853,7 @@ void intlGUIEditBox::draw()
CurrentTextRect.UpperLeftCorner.X += charcursorpos; CurrentTextRect.UpperLeftCorner.X += charcursorpos;
font->draw(L"_", CurrentTextRect, 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); 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 //! Gets the area of the text in the edit box
//! \return Returns the size in pixels of the text //! \return Returns the size in pixels of the text
core::dimension2du intlGUIEditBox::getTextDimension() core::dimension2du intlGUIEditBox::getTextDimension()
@ -1096,12 +990,12 @@ bool intlGUIEditBox::processMouse(const SEvent& event)
s32 intlGUIEditBox::getCursorPos(s32 x, s32 y) s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
{ {
IGUIFont* font = OverrideFont; IGUIFont* font = m_override_font;
IGUISkin* skin = Environment->getSkin(); IGUISkin* skin = Environment->getSkin();
if (!OverrideFont) if (!m_override_font)
font = skin->getFont(); 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; core::stringw *txtLine = NULL;
s32 startPos = 0; s32 startPos = 0;
@ -1118,8 +1012,8 @@ s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
// is it inside this region? // is it inside this region?
if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) { if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) {
// we've found the clicked line // we've found the clicked line
txtLine = (WordWrap || MultiLine) ? &BrokenText[curr_line_idx] : &Text; txtLine = (m_word_wrap || m_multiline) ? &BrokenText[curr_line_idx] : &Text;
startPos = (WordWrap || MultiLine) ? BrokenTextPositions[curr_line_idx] : 0; startPos = (m_word_wrap || m_multiline) ? BrokenTextPositions[curr_line_idx] : 0;
break; break;
} }
} }
@ -1144,14 +1038,14 @@ void intlGUIEditBox::breakText()
{ {
IGUISkin* skin = Environment->getSkin(); IGUISkin* skin = Environment->getSkin();
if ((!WordWrap && !MultiLine) || !skin) if ((!m_word_wrap && !m_multiline) || !skin)
return; return;
BrokenText.clear(); // need to reallocate :/ BrokenText.clear(); // need to reallocate :/
BrokenTextPositions.set_used(0); BrokenTextPositions.set_used(0);
IGUIFont* font = OverrideFont; IGUIFont* font = m_override_font;
if (!OverrideFont) if (!m_override_font)
font = skin->getFont(); font = skin->getFont();
if (!font) if (!font)
@ -1190,7 +1084,7 @@ void intlGUIEditBox::breakText()
} }
// don't break if we're not a multi-line edit box // don't break if we're not a multi-line edit box
if (!MultiLine) if (!m_multiline)
lineBreak = false; lineBreak = false;
if (c == L' ' || c == 0 || i == (size-1)) if (c == L' ' || c == 0 || i == (size-1))
@ -1201,7 +1095,7 @@ void intlGUIEditBox::breakText()
s32 whitelgth = font->getDimension(whitespace.c_str()).Width; s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
s32 worldlgth = font->getDimension(word.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 // break to next line
length = worldlgth; length = worldlgth;
@ -1260,14 +1154,14 @@ void intlGUIEditBox::setTextRect(s32 line)
if (!skin) if (!skin)
return; return;
IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont(); IGUIFont* font = m_override_font ? m_override_font : skin->getFont();
if (!font) if (!font)
return; return;
// get text dimension // get text dimension
const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1; const u32 lineCount = (m_word_wrap || m_multiline) ? BrokenText.size() : 1;
if (WordWrap || MultiLine) if (m_word_wrap || m_multiline)
{ {
d = font->getDimension(BrokenText[line].c_str()); d = font->getDimension(BrokenText[line].c_str());
} }
@ -1328,7 +1222,7 @@ void intlGUIEditBox::setTextRect(s32 line)
s32 intlGUIEditBox::getLineFromPos(s32 pos) s32 intlGUIEditBox::getLineFromPos(s32 pos)
{ {
if (!WordWrap && !MultiLine) if (!m_word_wrap && !m_multiline)
return 0; return 0;
s32 i=0; s32 i=0;
@ -1387,7 +1281,7 @@ void intlGUIEditBox::inputChar(wchar_t c)
void intlGUIEditBox::calculateScrollPos() void intlGUIEditBox::calculateScrollPos()
{ {
if (!AutoScroll) if (!m_autoscroll)
return; return;
// calculate horizontal scroll position // calculate horizontal scroll position
@ -1395,18 +1289,18 @@ void intlGUIEditBox::calculateScrollPos()
setTextRect(cursLine); setTextRect(cursLine);
// don't do horizontal scrolling when wordwrap is enabled. // don't do horizontal scrolling when wordwrap is enabled.
if (!WordWrap) if (!m_word_wrap)
{ {
// get cursor position // get cursor position
IGUISkin* skin = Environment->getSkin(); IGUISkin* skin = Environment->getSkin();
if (!skin) if (!skin)
return; return;
IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont(); IGUIFont* font = m_override_font ? m_override_font : skin->getFont();
if (!font) if (!font)
return; return;
core::stringw *txtLine = MultiLine ? &BrokenText[cursLine] : &Text; core::stringw *txtLine = m_multiline ? &BrokenText[cursLine] : &Text;
s32 cPos = MultiLine ? CursorPos - BrokenTextPositions[cursLine] : CursorPos; s32 cPos = m_multiline ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos + s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos +
font->getDimension(txtLine->subString(0, cPos).c_str()).Width; font->getDimension(txtLine->subString(0, cPos).c_str()).Width;
@ -1423,7 +1317,7 @@ void intlGUIEditBox::calculateScrollPos()
// todo: adjust scrollbar // todo: adjust scrollbar
} }
if (!WordWrap && !MultiLine) if (!m_word_wrap && !m_multiline)
return; return;
// vertical scroll position // vertical scroll position
@ -1468,8 +1362,8 @@ void intlGUIEditBox::createVScrollBar()
{ {
s32 fontHeight = 1; s32 fontHeight = 1;
if (OverrideFont) { if (m_override_font) {
fontHeight = OverrideFont->getDimension(L"").Height; fontHeight = m_override_font->getDimension(L"").Height;
} else { } else {
if (IGUISkin* skin = Environment->getSkin()) { if (IGUISkin* skin = Environment->getSkin()) {
if (IGUIFont* font = skin->getFont()) { if (IGUIFont* font = skin->getFont()) {
@ -1520,7 +1414,7 @@ void intlGUIEditBox::updateVScrollBar()
m_vscrollbar->setPageSize(s32(getTextDimension().Height)); m_vscrollbar->setPageSize(s32(getTextDimension().Height));
} }
if (!m_vscrollbar->isVisible() && MultiLine) { if (!m_vscrollbar->isVisible() && m_multiline) {
AbsoluteRect.LowerRightCorner.X -= m_scrollbar_width; AbsoluteRect.LowerRightCorner.X -= m_scrollbar_width;
m_vscrollbar->setVisible(true); m_vscrollbar->setVisible(true);
@ -1548,20 +1442,20 @@ void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeRea
{ {
// IGUIEditBox::serializeAttributes(out,options); // IGUIEditBox::serializeAttributes(out,options);
out->addBool ("OverrideColorEnabled",OverrideColorEnabled ); out->addBool ("OverrideColorEnabled", m_override_color_enabled );
out->addColor ("OverrideColor", OverrideColor); out->addColor ("OverrideColor", m_override_color);
// out->addFont("OverrideFont",OverrideFont); // out->addFont("OverrideFont",m_override_font);
out->addInt ("MaxChars", Max); out->addInt ("MaxChars", Max);
out->addBool ("WordWrap", WordWrap); out->addBool ("WordWrap", m_word_wrap);
out->addBool ("MultiLine", MultiLine); out->addBool ("MultiLine", m_multiline);
out->addBool ("AutoScroll", AutoScroll); out->addBool ("AutoScroll", m_autoscroll);
out->addBool ("PasswordBox", PasswordBox); out->addBool ("PasswordBox", PasswordBox);
core::stringw ch = L" "; core::stringw ch = L" ";
ch[0] = PasswordChar; ch[0] = PasswordChar;
out->addString("PasswordChar", ch.c_str()); out->addString("PasswordChar", ch.c_str());
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames); out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames); out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
out->addBool ("Writable", m_writable); out->addBool ("Writable", m_writable);
IGUIEditBox::serializeAttributes(out,options); IGUIEditBox::serializeAttributes(out,options);
} }

View File

@ -7,16 +7,15 @@
#include "IrrCompileConfig.h" #include "IrrCompileConfig.h"
//#ifdef _IRR_COMPILE_WITH_GUI_ //#ifdef _IRR_COMPILE_WITH_GUI_
#include <IGUIEditBox.h> #include "guiEditBox.h"
#include "irrArray.h" #include "irrArray.h"
#include "IOSOperator.h" #include "IOSOperator.h"
#include "guiScrollBar.h"
namespace irr namespace irr
{ {
namespace gui namespace gui
{ {
class intlGUIEditBox : public IGUIEditBox class intlGUIEditBox : public GUIEditBox
{ {
public: public:
@ -28,32 +27,6 @@ namespace gui
//! destructor //! destructor
virtual ~intlGUIEditBox(); 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 //! Sets whether to draw the background
virtual void setDrawBackground(bool draw); virtual void setDrawBackground(bool draw);
@ -64,30 +37,6 @@ namespace gui
virtual bool isDrawBorderEnabled() const { return Border; } 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 //! Gets the size area of the text in the edit box
//! \return Returns the size in pixels of the text //! \return Returns the size in pixels of the text
virtual core::dimension2du getTextDimension(); virtual core::dimension2du getTextDimension();
@ -143,7 +92,7 @@ namespace gui
protected: protected:
//! Breaks the single text line. //! Breaks the single text line.
void breakText(); virtual void breakText();
//! sets the area of the given line //! sets the area of the given line
void setTextRect(s32 line); void setTextRect(s32 line);
//! returns the line number that the cursor is on //! returns the line number that the cursor is on
@ -169,12 +118,9 @@ namespace gui
bool MouseMarking = false; bool MouseMarking = false;
bool Border; bool Border;
bool OverrideColorEnabled = false;
s32 MarkBegin = 0; s32 MarkBegin = 0;
s32 MarkEnd = 0; s32 MarkEnd = 0;
video::SColor OverrideColor = video::SColor(101,255,255,255);
gui::IGUIFont *OverrideFont = nullptr;
gui::IGUIFont *LastBreakFont = nullptr; gui::IGUIFont *LastBreakFont = nullptr;
IOSOperator *Operator = nullptr; IOSOperator *Operator = nullptr;
@ -184,9 +130,6 @@ namespace gui
s32 VScrollPos = 0; // scroll position in characters s32 VScrollPos = 0; // scroll position in characters
u32 Max = 0; u32 Max = 0;
bool WordWrap = false;
bool MultiLine = false;
bool AutoScroll = true;
bool PasswordBox = false; bool PasswordBox = false;
wchar_t PasswordChar = L'*'; wchar_t PasswordChar = L'*';
EGUI_ALIGNMENT HAlign = EGUIA_UPPERLEFT; EGUI_ALIGNMENT HAlign = EGUIA_UPPERLEFT;

View File

@ -881,8 +881,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5.0f / 2.0f; 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); bool inside_joystick = (dxj * dxj + dyj * dyj <= button_size * button_size * 1.5 * 1.5);
if (m_joystick_has_really_moved || if (m_joystick_has_really_moved || inside_joystick ||
(!m_joystick_has_really_moved && inside_joystick) ||
(!m_fixed_joystick && (!m_fixed_joystick &&
distance_sq > m_touchscreen_threshold * m_touchscreen_threshold)) { distance_sq > m_touchscreen_threshold * m_touchscreen_threshold)) {
m_joystick_has_really_moved = true; m_joystick_has_really_moved = true;

View File

@ -356,7 +356,7 @@ namespace gui
load_flags = FT_LOAD_DEFAULT | FT_LOAD_RENDER; load_flags = FT_LOAD_DEFAULT | FT_LOAD_RENDER;
if (!useHinting()) load_flags |= FT_LOAD_NO_HINTING; if (!useHinting()) load_flags |= FT_LOAD_NO_HINTING;
if (!useAutoHinting()) load_flags |= FT_LOAD_NO_AUTOHINT; 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; else load_flags |= FT_LOAD_TARGET_NORMAL;
} }
u32 getWidthFromCharacter(wchar_t c) const; u32 getWidthFromCharacter(wchar_t c) const;

View File

@ -1331,7 +1331,7 @@ public:
{ {
u32 i; u32 i;
const uchar16_t* oa = other.c_str(); 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]) if (array[i] != oa[i])
return false; return false;
@ -1350,7 +1350,7 @@ public:
if (!str) if (!str)
return false; return false;
u32 i; 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]) if (array[i] != str[i])
return false; return false;

View File

@ -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_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 { try {
// If directory exists, check contents and load if possible // If directory exists, check contents and load if possible
if (fs::PathExists(m_savedir)) { if (fs::PathExists(m_savedir)) {
@ -1863,10 +1865,10 @@ void ServerMap::endSave()
bool ServerMap::saveBlock(MapBlock *block) 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(); v3s16 p3d = block->getPos();
@ -1886,7 +1888,7 @@ bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db)
*/ */
std::ostringstream o(std::ios_base::binary); std::ostringstream o(std::ios_base::binary);
o.write((char*) &version, 1); o.write((char*) &version, 1);
block->serialize(o, version, true); block->serialize(o, version, true, compression_level);
bool ret = db->saveBlock(p3d, o.str()); bool ret = db->saveBlock(p3d, o.str());
if (ret) { if (ret) {

View File

@ -382,7 +382,7 @@ public:
MapgenParams *getMapgenParams(); MapgenParams *getMapgenParams();
bool saveBlock(MapBlock *block); 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); MapBlock* loadBlock(v3s16 p);
// Database version // Database version
void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false); void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
@ -417,6 +417,7 @@ private:
std::string m_savedir; std::string m_savedir;
bool m_map_saving_enabled; bool m_map_saving_enabled;
int m_map_compression_level;
#if 0 #if 0
// Chunk size in MapSectors // Chunk size in MapSectors
// If 0, chunks are disabled. // If 0, chunks are disabled.

View File

@ -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)) if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapBlock format not supported"); 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, content_width);
writeU8(os, params_width); writeU8(os, params_width);
MapNode::serializeBulk(os, version, tmp_nodes, nodecount, MapNode::serializeBulk(os, version, tmp_nodes, nodecount,
content_width, params_width, true); content_width, params_width, compression_level);
delete[] tmp_nodes; delete[] tmp_nodes;
} }
else else
@ -404,7 +404,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
writeU8(os, content_width); writeU8(os, content_width);
writeU8(os, params_width); writeU8(os, params_width);
MapNode::serializeBulk(os, version, data, nodecount, 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); std::ostringstream oss(std::ios_base::binary);
m_node_metadata.serialize(oss, version, disk); 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 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) if(params_width != 2)
throw SerializationError("MapBlock::deSerialize(): invalid params_width"); throw SerializationError("MapBlock::deSerialize(): invalid params_width");
MapNode::deSerializeBulk(is, version, data, nodecount, MapNode::deSerializeBulk(is, version, data, nodecount,
content_width, params_width, true); content_width, params_width);
/* /*
NodeMetadata NodeMetadata

View File

@ -482,7 +482,7 @@ public:
// These don't write or read version by itself // These don't write or read version by itself
// Set disk to true for on-disk format, false for over-the-network format // Set disk to true for on-disk format, false for over-the-network format
// Precondition: version >= SER_FMT_VER_LOWEST_WRITE // 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 // If disk == true: In addition to doing other things, will add
// unknown blocks from id-name mapping to wndef // unknown blocks from id-name mapping to wndef
void deSerialize(std::istream &is, u8 version, bool disk); void deSerialize(std::istream &is, u8 version, bool disk);

View File

@ -297,7 +297,7 @@ int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
int iters = 256; int iters = 256;
while (iters > 0 && y <= max_spawn_y) { while (iters > 0 && y <= max_spawn_y) {
if (!getMountainTerrainAtPoint(p.X, y + 1, p.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 return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
// y + 1 due to biome 'dust' // y + 1 due to biome 'dust'

View File

@ -334,7 +334,7 @@ bool Schematic::deserializeFromMts(std::istream *is,
schemdata = new MapNode[nodecount]; schemdata = new MapNode[nodecount];
MapNode::deSerializeBulk(ss, SER_FMT_VER_HIGHEST_READ, schemdata, 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 // Fix probability values for nodes that were ignore; removed in v2
if (version < 2) { if (version < 2) {
@ -376,7 +376,7 @@ bool Schematic::serializeToMts(std::ostream *os,
// compressed bulk node data // compressed bulk node data
MapNode::serializeBulk(ss, SER_FMT_VER_HIGHEST_WRITE, 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; return true;
} }

View File

@ -406,7 +406,8 @@ treegen::error make_ltree(MMVManip &vmanip, v3s16 p0,
v3f(position.X, position.Y, position.Z - 1), v3f(position.X, position.Y, position.Z - 1),
tree_definition tree_definition
); );
} if (!stack_orientation.empty()) { }
if (!stack_orientation.empty()) {
s16 size = 1; s16 size = 1;
for (x = -size; x <= size; x++) for (x = -size; x <= size; x++)
for (y = -size; y <= size; y++) for (y = -size; y <= size; y++)

View File

@ -706,7 +706,7 @@ void MapNode::deSerialize(u8 *source, u8 version)
} }
void MapNode::serializeBulk(std::ostream &os, int version, void MapNode::serializeBulk(std::ostream &os, int version,
const MapNode *nodes, u32 nodecount, 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)) if (!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported"); throw VersionMismatchException("ERROR: MapNode format not supported");
@ -737,10 +737,7 @@ void MapNode::serializeBulk(std::ostream &os, int version,
Compress data to output stream Compress data to output stream
*/ */
if (compressed) compressZlib(databuf, databuf_size, os, compression_level);
compressZlib(databuf, databuf_size, os);
else
os.write((const char*) &databuf[0], databuf_size);
delete [] databuf; delete [] databuf;
} }
@ -748,7 +745,7 @@ void MapNode::serializeBulk(std::ostream &os, int version,
// Deserialize bulk node data // Deserialize bulk node data
void MapNode::deSerializeBulk(std::istream &is, int version, void MapNode::deSerializeBulk(std::istream &is, int version,
MapNode *nodes, u32 nodecount, MapNode *nodes, u32 nodecount,
u8 content_width, u8 params_width, bool compressed) u8 content_width, u8 params_width)
{ {
if(!ser_ver_supported(version)) if(!ser_ver_supported(version))
throw VersionMismatchException("ERROR: MapNode format not supported"); throw VersionMismatchException("ERROR: MapNode format not supported");
@ -760,24 +757,13 @@ void MapNode::deSerializeBulk(std::istream &is, int version,
// Uncompress or read data // Uncompress or read data
u32 len = nodecount * (content_width + params_width); u32 len = nodecount * (content_width + params_width);
SharedBuffer<u8> databuf(len); std::ostringstream os(std::ios_base::binary);
if(compressed) decompressZlib(is, os);
{ std::string s = os.str();
std::ostringstream os(std::ios_base::binary); if(s.size() != len)
decompressZlib(is, os); throw SerializationError("deSerializeBulkNodes: "
std::string s = os.str(); "decompress resulted in invalid size");
if(s.size() != len) const u8 *databuf = reinterpret_cast<const u8*>(s.c_str());
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");
}
// Deserialize content // Deserialize content
if(content_width == 1) if(content_width == 1)

View File

@ -292,10 +292,10 @@ struct MapNode
// compressed = true to zlib-compress output // compressed = true to zlib-compress output
static void serializeBulk(std::ostream &os, int version, static void serializeBulk(std::ostream &os, int version,
const MapNode *nodes, u32 nodecount, 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, static void deSerializeBulk(std::istream &is, int version,
MapNode *nodes, u32 nodecount, MapNode *nodes, u32 nodecount,
u8 content_width, u8 params_width, bool compressed); u8 content_width, u8 params_width);
private: private:
// Deprecated serialization methods // Deprecated serialization methods

View File

@ -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 #define PASSWORD_SIZE 28 // Maximum password length. Allows for
// base64-encoded SHA-1 (27+\0). // base64-encoded SHA-1 (27+\0).
/* // See also: Formspec Version History in doc/lua_api.txt
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
*/
#define FORMSPEC_API_VERSION 4 #define FORMSPEC_API_VERSION 4
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-" #define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"

View File

@ -316,7 +316,7 @@ void Server::handleCommand_Init2(NetworkPacket* pkt)
// Send active objects // Send active objects
{ {
PlayerSAO *sao = getPlayerSAO(peer_id); PlayerSAO *sao = getPlayerSAO(peer_id);
if (client && sao) if (sao)
SendActiveObjectRemoveAdd(client, sao); SendActiveObjectRemoveAdd(client, sao);
} }

View File

@ -617,7 +617,7 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer,
bool has_scale = tiledef.scale > 0; bool has_scale = tiledef.scale > 0;
bool use_autoscale = tsettings.autoscale_mode == AUTOSCALE_FORCE || bool use_autoscale = tsettings.autoscale_mode == AUTOSCALE_FORCE ||
(tsettings.autoscale_mode == AUTOSCALE_ENABLE && !has_scale); (tsettings.autoscale_mode == AUTOSCALE_ENABLE && !has_scale);
if (use_autoscale && layer->texture) { if (use_autoscale) {
auto texture_size = layer->texture->getOriginalSize(); auto texture_size = layer->texture->getOriginalSize();
float base_size = tsettings.node_texture_size; float base_size = tsettings.node_texture_size;
float size = std::fmin(texture_size.Width, texture_size.Height); 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; bool is_liquid = false;
u8 material_type = (alpha == 255) ? MaterialType material_type = (alpha == 255) ?
TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
switch (drawtype) { switch (drawtype) {
@ -892,7 +892,7 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
u32 tile_shader = shdsrc->getShader("nodes_shader", material_type, drawtype); 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) if (overlay_material == TILE_MATERIAL_OPAQUE)
overlay_material = TILE_MATERIAL_BASIC; overlay_material = TILE_MATERIAL_BASIC;
else if (overlay_material == TILE_MATERIAL_LIQUID_OPAQUE) else if (overlay_material == TILE_MATERIAL_LIQUID_OPAQUE)
@ -913,7 +913,7 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
tdef[j].backface_culling, tsettings); tdef[j].backface_culling, tsettings);
} }
u8 special_material = material_type; MaterialType special_material = material_type;
if (drawtype == NDT_PLANTLIKE_ROOTED) { if (drawtype == NDT_PLANTLIKE_ROOTED) {
if (waving == 1) if (waving == 1)
special_material = TILE_MATERIAL_WAVING_PLANTS; special_material = TILE_MATERIAL_WAVING_PLANTS;

View File

@ -719,29 +719,48 @@ int mt_snprintf(char *buf, const size_t buf_size, const char *fmt, ...)
return c; 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://") || if (uri.find_first_of("\r\n") != std::string::npos) {
url.find_first_of("\r\n") != std::string::npos) { errorstream << "Unable to open URI as it is invalid, contains new line: " << uri << std::endl;
errorstream << "Invalid url: " << url << std::endl;
return false; return false;
} }
#if defined(_WIN32) #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__) #elif defined(__ANDROID__)
openURLAndroid(url); openURIAndroid(uri);
return true; return true;
#elif defined(__APPLE__) #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, return posix_spawnp(NULL, "open", NULL, NULL, (char**)argv,
(*_NSGetEnviron())) == 0; (*_NSGetEnviron())) == 0;
#else #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; return posix_spawnp(NULL, "xdg-open", NULL, NULL, (char**)argv, environ) == 0;
#endif #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 // Load performance counter frequency only once at startup
#ifdef _WIN32 #ifdef _WIN32

View File

@ -332,7 +332,25 @@ void attachOrCreateConsole();
int mt_snprintf(char *buf, const size_t buf_size, const char *fmt, ...); 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 } // namespace porting

View File

@ -213,13 +213,13 @@ void showInputDialog(const std::string &acceptButton, const std::string &hint,
jacceptButton, jhint, jcurrent, jeditType); 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"); "(Ljava/lang/String;)V");
FATAL_ERROR_IF(url_open == nullptr, 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()); jstring jurl = jnienv->NewStringUTF(url.c_str());
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl); jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);

View File

@ -58,7 +58,7 @@ void initializePathsAndroid();
void showInputDialog(const std::string &acceptButton, void showInputDialog(const std::string &acceptButton,
const std::string &hint, const std::string &current, int editType); 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++ * WORKAROUND for not working callbacks from java -> c++

View File

@ -38,7 +38,7 @@ ScopeProfiler::~ScopeProfiler()
return; return;
float duration_ms = m_timer->stop(true); float duration_ms = m_timer->stop(true);
float duration = duration_ms / 1000.0; float duration = duration_ms;
if (m_profiler) { if (m_profiler) {
switch (m_type) { switch (m_type) {
case SPT_ADD: case SPT_ADD:

View File

@ -103,6 +103,32 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
lua_pop(L, 2); // Pop object and error handler 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) void ScriptApiEntity::luaentity_Remove(u16 id)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER

View File

@ -33,6 +33,7 @@ public:
bool luaentity_Add(u16 id, const char *name); bool luaentity_Add(u16 id, const char *name);
void luaentity_Activate(u16 id, void luaentity_Activate(u16 id,
const std::string &staticdata, u32 dtime_s); const std::string &staticdata, u32 dtime_s);
void luaentity_Deactivate(u16 id);
void luaentity_Remove(u16 id); void luaentity_Remove(u16 id);
std::string luaentity_GetStaticdata(u16 id); std::string luaentity_GetStaticdata(u16 id);
void luaentity_GetProperties(u16 id, void luaentity_GetProperties(u16 id,

View File

@ -401,10 +401,9 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
lua_pushfstring(L, "%s: %s", path, strerror(errno)); lua_pushfstring(L, "%s: %s", path, strerror(errno));
return false; return false;
} }
chunk_name = new char[strlen(display_name) + 2]; size_t len = strlen(display_name) + 2;
chunk_name[0] = '@'; chunk_name = new char[len];
chunk_name[1] = '\0'; snprintf(chunk_name, len, "@%s", display_name);
strcat(chunk_name, display_name);
} }
size_t start = 0; size_t start = 0;

View File

@ -743,6 +743,31 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
return 1; 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) // set_timeofday(val)
// val = 0...1 // val = 0...1
int ModApiEnvMod::l_set_timeofday(lua_State *L) 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_node_timer);
API_FCT(get_connected_players); API_FCT(get_connected_players);
API_FCT(get_player_by_name); API_FCT(get_player_by_name);
API_FCT(get_objects_in_area);
API_FCT(get_objects_inside_radius); API_FCT(get_objects_inside_radius);
API_FCT(set_timeofday); API_FCT(set_timeofday);
API_FCT(get_timeofday); API_FCT(get_timeofday);

View File

@ -115,6 +115,9 @@ private:
// get_objects_inside_radius(pos, radius) // get_objects_inside_radius(pos, radius)
static int l_get_objects_inside_radius(lua_State *L); 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) // set_timeofday(val)
// val = 0...1 // val = 0...1
static int l_set_timeofday(lua_State *L); static int l_set_timeofday(lua_State *L);

View File

@ -686,6 +686,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) int ModApiMainMenu::l_get_modpath(lua_State *L)
{ {
@ -795,6 +803,15 @@ int ModApiMainMenu::l_copy_dir(lua_State *L)
return 1; return 1;
} }
/******************************************************************************/
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) int ModApiMainMenu::l_extract_zip(lua_State *L)
{ {
@ -1070,7 +1087,15 @@ int ModApiMainMenu::l_get_max_supp_proto(lua_State *L)
int ModApiMainMenu::l_open_url(lua_State *L) int ModApiMainMenu::l_open_url(lua_State *L)
{ {
std::string url = luaL_checkstring(L, 1); 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; return 1;
} }
@ -1116,6 +1141,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(set_background); API_FCT(set_background);
API_FCT(set_topleft_text); API_FCT(set_topleft_text);
API_FCT(get_mapgen_names); API_FCT(get_mapgen_names);
API_FCT(get_user_path);
API_FCT(get_modpath); API_FCT(get_modpath);
API_FCT(get_clientmodpath); API_FCT(get_clientmodpath);
API_FCT(get_gamepath); API_FCT(get_gamepath);
@ -1125,6 +1151,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(create_dir); API_FCT(create_dir);
API_FCT(delete_dir); API_FCT(delete_dir);
API_FCT(copy_dir); API_FCT(copy_dir);
API_FCT(is_dir);
API_FCT(extract_zip); API_FCT(extract_zip);
API_FCT(may_modify_path); API_FCT(may_modify_path);
API_FCT(get_mainmenu_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_min_supp_proto);
API_FCT(get_max_supp_proto); API_FCT(get_max_supp_proto);
API_FCT(open_url); API_FCT(open_url);
API_FCT(open_dir);
API_FCT(do_async_callback); API_FCT(do_async_callback);
} }
@ -1147,6 +1175,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(get_games); API_FCT(get_games);
API_FCT(get_favorites); API_FCT(get_favorites);
API_FCT(get_mapgen_names); API_FCT(get_mapgen_names);
API_FCT(get_user_path);
API_FCT(get_modpath); API_FCT(get_modpath);
API_FCT(get_clientmodpath); API_FCT(get_clientmodpath);
API_FCT(get_gamepath); API_FCT(get_gamepath);
@ -1156,6 +1185,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(create_dir); API_FCT(create_dir);
API_FCT(delete_dir); API_FCT(delete_dir);
API_FCT(copy_dir); API_FCT(copy_dir);
API_FCT(is_dir);
//API_FCT(extract_zip); //TODO remove dependency to GuiEngine //API_FCT(extract_zip); //TODO remove dependency to GuiEngine
API_FCT(may_modify_path); API_FCT(may_modify_path);
API_FCT(download_file); API_FCT(download_file);

View File

@ -112,6 +112,8 @@ private:
static int l_get_mainmenu_path(lua_State *L); 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_modpath(lua_State *L);
static int l_get_clientmodpath(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_copy_dir(lua_State *L);
static int l_is_dir(lua_State *L);
static int l_extract_zip(lua_State *L); static int l_extract_zip(lua_State *L);
static int l_may_modify_path(lua_State *L); static int l_may_modify_path(lua_State *L);
@ -148,6 +152,8 @@ private:
// other // other
static int l_open_url(lua_State *L); static int l_open_url(lua_State *L);
static int l_open_dir(lua_State *L);
// async // async
static int l_do_async_callback(lua_State *L); static int l_do_async_callback(lua_State *L);

View File

@ -110,7 +110,7 @@ int ObjectRef::l_remove(lua_State *L)
sao->clearParentAttachment(); sao->clearParentAttachment();
verbosestream << "ObjectRef::l_remove(): id=" << sao->getId() << std::endl; verbosestream << "ObjectRef::l_remove(): id=" << sao->getId() << std::endl;
sao->m_pending_removal = true; sao->markForRemoval();
return 0; return 0;
} }
@ -1409,7 +1409,7 @@ int ObjectRef::l_set_physics_override(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
PlayerSAO *playersao = (PlayerSAO *) getobject(ref); PlayerSAO *playersao = getplayersao(ref);
if (playersao == nullptr) if (playersao == nullptr)
return 0; return 0;
@ -1449,7 +1449,7 @@ int ObjectRef::l_get_physics_override(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
PlayerSAO *playersao = (PlayerSAO *)getobject(ref); PlayerSAO *playersao = getplayersao(ref);
if (playersao == nullptr) if (playersao == nullptr)
return 0; return 0;

View File

@ -239,15 +239,6 @@ int ModApiUtil::l_is_yes(lua_State *L)
return 1; 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() // get_builtin_path()
int ModApiUtil::l_get_builtin_path(lua_State *L) 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(get_password_hash);
API_FCT(is_yes); API_FCT(is_yes);
API_FCT(is_nan);
API_FCT(get_builtin_path); API_FCT(get_builtin_path);
@ -526,7 +516,6 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(write_json); API_FCT(write_json);
API_FCT(is_yes); API_FCT(is_yes);
API_FCT(is_nan);
API_FCT(compress); API_FCT(compress);
API_FCT(decompress); API_FCT(decompress);

View File

@ -65,9 +65,6 @@ private:
// is_yes(arg) // is_yes(arg)
static int l_is_yes(lua_State *L); static int l_is_yes(lua_State *L);
// is_nan(arg)
static int l_is_nan(lua_State *L);
// get_builtin_path() // get_builtin_path()
static int l_get_builtin_path(lua_State *L); static int l_get_builtin_path(lua_State *L);

View File

@ -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 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); std::ostringstream os(std::ios_base::binary);
block->serialize(os, ver, false); block->serialize(os, ver, false, net_compression_level);
block->serializeNetworkSpecific(os); block->serializeNetworkSpecific(os);
std::string s = os.str(); std::string s = os.str();

View File

@ -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, void ActiveObjectMgr::getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius,
f32 player_radius, std::set<u16> &current_objects, f32 player_radius, std::set<u16> &current_objects,
std::queue<u16> &added_objects) std::queue<u16> &added_objects)

View File

@ -38,6 +38,9 @@ public:
void getObjectsInsideRadius(const v3f &pos, float radius, void getObjectsInsideRadius(const v3f &pos, float radius,
std::vector<ServerActiveObject *> &result, std::vector<ServerActiveObject *> &result,
std::function<bool(ServerActiveObject *obj)> include_obj_cb); 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, void getAddedActiveObjectsAroundPos(const v3f &player_pos, f32 radius,
f32 player_radius, std::set<u16> &current_objects, f32 player_radius, std::set<u16> &current_objects,

View File

@ -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) void LuaEntitySAO::step(float dtime, bool send_recommended)
{ {
if(!m_properties_sent) if(!m_properties_sent)
@ -302,7 +311,7 @@ u16 LuaEntitySAO::punch(v3f dir,
{ {
if (!m_registered) { if (!m_registered) {
// Delete unknown LuaEntities when punched // Delete unknown LuaEntities when punched
m_pending_removal = true; markForRemoval();
return 0; return 0;
} }
@ -335,7 +344,7 @@ u16 LuaEntitySAO::punch(v3f dir,
clearParentAttachment(); clearParentAttachment();
clearChildAttachments(); clearChildAttachments();
m_env->getScriptIface()->luaentity_on_death(m_id, puncher); m_env->getScriptIface()->luaentity_on_death(m_id, puncher);
m_pending_removal = true; markForRemoval();
} }
actionstream << puncher->getDescription() << " (id=" << puncher->getId() << actionstream << puncher->getDescription() << " (id=" << puncher->getId() <<

View File

@ -71,6 +71,11 @@ public:
bool getSelectionBox(aabb3f *toset) const; bool getSelectionBox(aabb3f *toset) const;
bool collideWithObjects() const; bool collideWithObjects() const;
protected:
void dispatchScriptDeactivate();
virtual void onMarkedForDeactivation() { dispatchScriptDeactivate(); }
virtual void onMarkedForRemoval() { dispatchScriptDeactivate(); }
private: private:
std::string getPropertyPacket(); std::string getPropertyPacket();
void sendPosition(bool do_interpolate, bool is_movement_end); void sendPosition(bool do_interpolate, bool is_movement_end);

View File

@ -531,7 +531,7 @@ bool PlayerSAO::setWieldedItem(const ItemStack &item)
void PlayerSAO::disconnected() void PlayerSAO::disconnected()
{ {
m_peer_id = PEER_ID_INEXISTENT; m_peer_id = PEER_ID_INEXISTENT;
m_pending_removal = true; markForRemoval();
} }
void PlayerSAO::unlinkPlayerSessionAndSave() void PlayerSAO::unlinkPlayerSessionAndSave()

View File

@ -73,3 +73,19 @@ void ServerActiveObject::dumpAOMessagesToQueue(std::queue<ActiveObjectMessage> &
m_messages_out.pop(); 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;
}
}

View File

@ -70,6 +70,10 @@ public:
virtual bool environmentDeletes() const virtual bool environmentDeletes() const
{ return true; } { return true; }
// Safely mark the object for removal or deactivation
void markForRemoval();
void markForDeactivation();
// Create a certain type of ServerActiveObject // Create a certain type of ServerActiveObject
static ServerActiveObject* create(ActiveObjectType type, static ServerActiveObject* create(ActiveObjectType type,
ServerEnvironment *env, u16 id, v3f pos, ServerEnvironment *env, u16 id, v3f pos,
@ -213,25 +217,6 @@ public:
*/ */
u16 m_known_by_count = 0; 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: A getter that unifies the above to answer the question:
"Can the environment still interact with this object?" "Can the environment still interact with this object?"
@ -239,6 +224,9 @@ public:
inline bool isGone() const inline bool isGone() const
{ return m_pending_removal || m_pending_deactivation; } { 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 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); v3s16 m_static_block = v3s16(1337,1337,1337);
protected: protected:
virtual void onMarkedForDeactivation() {}
virtual void onMarkedForRemoval() {}
virtual void onAttach(int parent_id) {} virtual void onAttach(int parent_id) {}
virtual void onDetach(int parent_id) {} virtual void onDetach(int parent_id) {}
@ -257,6 +248,27 @@ protected:
v3f m_base_position; v3f m_base_position;
std::unordered_set<u32> m_attached_particle_spawners; 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 Queue of messages to be sent to the client
*/ */

View File

@ -1164,7 +1164,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
// If known by some client, don't delete immediately // If known by some client, don't delete immediately
if (obj->m_known_by_count > 0) { if (obj->m_known_by_count > 0) {
obj->m_pending_removal = true; obj->markForRemoval();
return false; return false;
} }
@ -1792,7 +1792,7 @@ void ServerEnvironment::removeRemovedObjects()
/* /*
Delete static data from block if removed Delete static data from block if removed
*/ */
if (obj->m_pending_removal) if (obj->isPendingRemoval())
deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false); deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
// If still known by clients, don't actually remove. On some future // 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 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); MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
if (block) { if (block) {
const auto i = block->m_static_objects.m_active.find(id); 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 && if (!force_delete && obj->m_static_exists &&
!m_active_blocks.contains(obj->m_static_block) && !m_active_blocks.contains(obj->m_static_block) &&
m_active_blocks.contains(blockpos_o)) { m_active_blocks.contains(blockpos_o)) {
// Delete from block where object was located // Delete from block where object was located
deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false); deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
@ -2068,6 +2069,10 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
force_delete = true; 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. If known by some client, set pending deactivation.
Otherwise delete it immediately. Otherwise delete it immediately.
@ -2077,7 +2082,6 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
<< "object id=" << id << " is known by clients" << "object id=" << id << " is known by clients"
<< "; not deleting yet" << std::endl; << "; not deleting yet" << std::endl;
obj->m_pending_deactivation = true;
return false; return false;
} }

View File

@ -332,6 +332,13 @@ public:
return m_ao_manager.getObjectsInsideRadius(pos, radius, objects, include_obj_cb); 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 // Clear objects, loading and going through every MapBlock
void clearObjects(ClearObjectsMode mode); void clearObjects(ClearObjectsMode mode);

View File

@ -1015,10 +1015,10 @@ void srp_user_process_challenge(struct SRPUser *usr,
goto cleanup_and_exit; goto cleanup_and_exit;
*bytes_M = usr->M; *bytes_M = usr->M;
if (len_M) *len_M = hash_length(usr->hash_alg); *len_M = hash_length(usr->hash_alg);
} else { } else {
*bytes_M = NULL; *bytes_M = NULL;
if (len_M) *len_M = 0; *len_M = 0;
} }
cleanup_and_exit: cleanup_and_exit:

View File

@ -633,7 +633,7 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
color_name = value; color_name = value;
} }
color_name = lowercase(value); color_name = lowercase(color_name);
std::map<const std::string, unsigned>::const_iterator it; std::map<const std::string, unsigned>::const_iterator it;
it = named_colors.colors.find(color_name); it = named_colors.colors.find(color_name);

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