Merge branch 'master' of https://github.com/minetest/minetest
9
.editorconfig
Executable file
@ -0,0 +1,9 @@
|
||||
[*]
|
||||
end_of_line = lf
|
||||
|
||||
[*.{cpp,h,lua,txt,glsl,md,c,cmake,java,gradle}]
|
||||
charset = utf8
|
||||
indent_size = 4
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
110
.github/CONTRIBUTING.md
vendored
@ -10,13 +10,31 @@ Contributions are welcome! Here's how you can help:
|
||||
|
||||
## Code
|
||||
|
||||
1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository and [clone](https://help.github.com/articles/cloning-a-repository/) your fork.
|
||||
1. [Fork](https://help.github.com/articles/fork-a-repo/) the repository and
|
||||
[clone](https://help.github.com/articles/cloning-a-repository/) your fork.
|
||||
|
||||
2. Before you start coding, consider opening an [issue at Github](https://github.com/minetest/minetest/issues) to discuss the suitability and implementation of your intended contribution with the core developers. If you are planning to start some very significant coding, you would benefit from first discussing on our IRC development channel [#minetest-dev](http://www.minetest.net/irc/). Note that a proper IRC client is required to speak on this channel.
|
||||
2. Before you start coding, consider opening an
|
||||
[issue at Github](https://github.com/minetest/minetest/issues) to discuss the
|
||||
suitability and implementation of your intended contribution with the core
|
||||
developers.
|
||||
|
||||
Any Pull Request that isn't a bug fix and isn't covered by
|
||||
[the roadmap](../doc/direction.md) will be closed within a week unless it
|
||||
receives a concept approval from a Core Developer. For this reason, it is
|
||||
recommended that you open an issue for any such pull requests before doing
|
||||
the work, to avoid disappointment.
|
||||
|
||||
You may also benefit from discussing on our IRC development channel
|
||||
[#minetest-dev](http://www.minetest.net/irc/). Note that a proper IRC client
|
||||
is required to speak on this channel.
|
||||
|
||||
3. Start coding!
|
||||
- Refer to the [Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt), [Developer Wiki](http://dev.minetest.net/Main_Page) and other [documentation](https://github.com/minetest/minetest/tree/master/doc).
|
||||
- Follow the [C/C++](http://dev.minetest.net/Code_style_guidelines) and [Lua](http://dev.minetest.net/Lua_code_style_guidelines) code style guidelines.
|
||||
- Refer to the
|
||||
[Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt),
|
||||
[Developer Wiki](http://dev.minetest.net/Main_Page) and other
|
||||
[documentation](https://github.com/minetest/minetest/tree/master/doc).
|
||||
- Follow the [C/C++](http://dev.minetest.net/Code_style_guidelines) and
|
||||
[Lua](http://dev.minetest.net/Lua_code_style_guidelines) code style guidelines.
|
||||
- Check your code works as expected and document any changes to the Lua API.
|
||||
|
||||
4. Commit & [push](https://help.github.com/articles/pushing-to-a-remote/) your changes to a new branch (not `master`, one change per branch)
|
||||
@ -33,69 +51,115 @@ Contributions are welcome! Here's how you can help:
|
||||
|
||||
5. Once you are happy with your changes, submit a pull request.
|
||||
- Open the [pull-request form](https://github.com/minetest/minetest/pull/new/master).
|
||||
- Add a description explaining what you've done (or if it's a work-in-progress - what you need to do).
|
||||
- Add a description explaining what you've done (or if it's a
|
||||
work-in-progress - what you need to do).
|
||||
- Make sure to fill out the pull request template.
|
||||
|
||||
### A pull-request is considered merge-able when:
|
||||
|
||||
1. It follows the roadmap in some way and fits the whole picture of the project: [roadmap introduction](http://c55.me/blog/?p=1491), [roadmap continued](https://forum.minetest.net/viewtopic.php?t=9177)
|
||||
1. It follows [the roadmap](../doc/direction.md) in some way and fits the whole
|
||||
picture of the project.
|
||||
2. It works.
|
||||
3. It follows the code style for [C/C++](http://dev.minetest.net/Code_style_guidelines) or [Lua](http://dev.minetest.net/Lua_code_style_guidelines).
|
||||
4. The code's interfaces are well designed, regardless of other aspects that might need more work in the future.
|
||||
3. It follows the code style for
|
||||
[C/C++](http://dev.minetest.net/Code_style_guidelines) or
|
||||
[Lua](http://dev.minetest.net/Lua_code_style_guidelines).
|
||||
4. The code's interfaces are well designed, regardless of other aspects that
|
||||
might need more work in the future.
|
||||
5. It uses protocols and formats which include the required compatibility.
|
||||
|
||||
### Important note about automated GitHub checks
|
||||
|
||||
When you submit a pull request, GitHub automatically runs checks on the Minetest Engine combined with your changes. One of these checks is called 'cpp lint / clang format', which checks code formatting. Because formatting for readability requires human judgement this check often fails and often makes unsuitable formatting requests which make code readability worse.
|
||||
When you submit a pull request, GitHub automatically runs checks on the Minetest
|
||||
Engine combined with your changes. One of these checks is called 'cpp lint /
|
||||
clang format', which checks code formatting. Because formatting for readability
|
||||
requires human judgement this check often fails and often makes unsuitable
|
||||
formatting requests which make code readability worse.
|
||||
|
||||
If this check fails, look at the details to check for any clear mistakes and correct those. However, you should not apply everything ClangFormat requests. Ignore requests that make code readability worse and any other clearly unsuitable requests. Discuss in the pull request with a core developer about how to progress.
|
||||
If this check fails, look at the details to check for any clear mistakes and
|
||||
correct those. However, you should not apply everything ClangFormat requests.
|
||||
Ignore requests that make code readability worse and any other clearly
|
||||
unsuitable requests. Discuss in the pull request with a core developer about how
|
||||
to progress.
|
||||
|
||||
## Issues
|
||||
|
||||
If you experience an issue, we would like to know the details - especially when a stable release is on the way.
|
||||
If you experience an issue, we would like to know the details - especially when
|
||||
a stable release is on the way.
|
||||
|
||||
1. Do a quick search on GitHub to check if the issue has already been reported.
|
||||
2. Is it an issue with the Minetest *engine*? If not, report it [elsewhere](http://www.minetest.net/development/#reporting-issues).
|
||||
3. [Open an issue](https://github.com/minetest/minetest/issues/new) and describe the issue you are having - you could include:
|
||||
2. Is it an issue with the Minetest *engine*? If not, report it
|
||||
[elsewhere](http://www.minetest.net/development/#reporting-issues).
|
||||
3. [Open an issue](https://github.com/minetest/minetest/issues/new) and describe
|
||||
the issue you are having - you could include:
|
||||
- Error logs (check the bottom of the `debug.txt` file).
|
||||
- Screenshots.
|
||||
- Ways you have tried to solve the issue, and whether they worked or not.
|
||||
- Your Minetest version and the content (games, mods or texture packs) you have installed.
|
||||
- Your platform (e.g. Windows 10 or Ubuntu 15.04 x64).
|
||||
|
||||
After reporting you should aim to answer questions or clarifications as this helps pinpoint the cause of the issue (if you don't do this your issue may be closed after 1 month).
|
||||
After reporting you should aim to answer questions or clarifications as this
|
||||
helps pinpoint the cause of the issue (if you don't do this your issue may be
|
||||
closed after 1 month).
|
||||
|
||||
## Feature requests
|
||||
|
||||
Feature requests are welcome but take a moment to see if your idea follows the roadmap in some way and fits the whole picture of the project: [roadmap introduction](http://c55.me/blog/?p=1491), [roadmap continued](https://forum.minetest.net/viewtopic.php?t=9177). You should provide a clear explanation with as much detail as possible.
|
||||
Feature requests are welcome but take a moment to see if your idea follows
|
||||
[the roadmap](../doc/direction.md) in some way and fits the whole picture of
|
||||
the project. You should provide a clear explanation with as much detail as
|
||||
possible.
|
||||
|
||||
## Translations
|
||||
|
||||
The core translations of Minetest are performed using Weblate. You can access the project page with a list of current languages [here](https://hosted.weblate.org/projects/minetest/minetest/).
|
||||
The core translations of Minetest are performed using Weblate. You can access
|
||||
the project page with a list of current languages
|
||||
[here](https://hosted.weblate.org/projects/minetest/minetest/).
|
||||
|
||||
Builtin (the component which contains things like server messages, chat command descriptions, privilege descriptions) is translated separately; it needs to be translated by editing a `.tr` text file. See [Translation](https://dev.minetest.net/Translation) for more information.
|
||||
Builtin (the component which contains things like server messages, chat command
|
||||
descriptions, privilege descriptions) is translated separately; it needs to be
|
||||
translated by editing a `.tr` text file. See
|
||||
[Translation](https://dev.minetest.net/Translation) for more information.
|
||||
|
||||
## Donations
|
||||
|
||||
If you'd like to monetarily support Minetest development, you can find donation methods on [our website](http://www.minetest.net/development/#donate).
|
||||
If you'd like to monetarily support Minetest development, you can find donation
|
||||
methods on [our website](http://www.minetest.net/development/#donate).
|
||||
|
||||
# Maintaining
|
||||
|
||||
*This is a concise version of the [Rules & Guidelines](http://dev.minetest.net/Category:Rules_and_Guidelines) on the developer wiki.*
|
||||
* This is a concise version of the
|
||||
[Rules & Guidelines](http://dev.minetest.net/Category:Rules_and_Guidelines) on the developer wiki.*
|
||||
|
||||
These notes are for those who have push access Minetest (core developers / maintainers).
|
||||
|
||||
- See the [project organisation](http://dev.minetest.net/Organisation) for the people involved.
|
||||
|
||||
## Concept approvals and roadmaps
|
||||
|
||||
If a Pull Request is not a bug fix:
|
||||
|
||||
* If it matches a goal in [the roadmap](../doc/direction.md), then the PR should
|
||||
be labelled as "Roadmap" and the goal stated by number in the description.
|
||||
* If it doesn't match a goal, then it needs to receive a concept approval within
|
||||
a week of being opened to remain open. This 1 week deadline does not apply to
|
||||
PRs opened before the roadmap was adopted; instead, they may remain open or be
|
||||
closed as needed. Use the "Concept Approved" label. Issues can be marked as
|
||||
"Concept Approved" to give preapproval to future PRs.
|
||||
|
||||
## Reviewing pull requests
|
||||
|
||||
Pull requests should be reviewed and, if appropriate, checked if they achieve their intended purpose. You can show that you are in the process of, or will review the pull request by commenting *"Looks good"* or something similar.
|
||||
Pull requests should be reviewed and, if appropriate, checked if they achieve
|
||||
their intended purpose. You can show that you are in the process of, or will
|
||||
review the pull request by commenting *"Looks good"* or something similar.
|
||||
|
||||
**If the pull-request is not [merge-able](#a-pull-request-is-considered-merge-able-when):**
|
||||
|
||||
Submit a comment explaining to the author what they need to change to make the pull-request merge-able.
|
||||
Submit a comment explaining to the author what they need to change to make the
|
||||
pull-request merge-able.
|
||||
|
||||
- If the author comments or makes changes to the pull-request, it can be reviewed again.
|
||||
- If no response is made from the author within 1 month (when improvements are suggested or a question is asked), it can be closed.
|
||||
- If the author comments or makes changes to the pull-request, it can be
|
||||
reviewed again.
|
||||
- If no response is made from the author within 1 month (when improvements are
|
||||
suggested or a question is asked), it can be closed.
|
||||
|
||||
**If the pull-request is [merge-able](#a-pull-request-is-considered-merge-able-when):**
|
||||
|
||||
|
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -3,6 +3,7 @@ Add compact, short information about your PR for easier understanding:
|
||||
- Goal of the PR
|
||||
- How does the PR work?
|
||||
- Does it resolve any reported issue?
|
||||
- Does this relate to a goal in [the roadmap](../doc/direction.md)?
|
||||
- If not a bug fix, why is this PR needed? What usecases does it solve?
|
||||
|
||||
## To do
|
||||
|
12
.github/workflows/android.yml
vendored
@ -8,7 +8,7 @@ on:
|
||||
- 'lib/**.cpp'
|
||||
- 'src/**.[ch]'
|
||||
- 'src/**.cpp'
|
||||
- 'build/android/**'
|
||||
- 'android/**'
|
||||
- '.github/workflows/android.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
@ -16,7 +16,7 @@ on:
|
||||
- 'lib/**.cpp'
|
||||
- 'src/**.[ch]'
|
||||
- 'src/**.cpp'
|
||||
- 'build/android/**'
|
||||
- 'android/**'
|
||||
- '.github/workflows/android.yml'
|
||||
|
||||
jobs:
|
||||
@ -28,15 +28,17 @@ jobs:
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Install deps
|
||||
run: sudo apt-get update; sudo apt-get install -y --no-install-recommends gettext
|
||||
- name: Build with Gradle
|
||||
run: cd build/android; ./gradlew assemblerelease
|
||||
run: cd android; ./gradlew assemblerelease
|
||||
- name: Save armeabi artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Minetest-armeabi-v7a.apk
|
||||
path: build/android/app/build/outputs/apk/release/app-armeabi-v7a-release-unsigned.apk
|
||||
path: android/app/build/outputs/apk/release/app-armeabi-v7a-release-unsigned.apk
|
||||
- name: Save arm64 artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Minetest-arm64-v8a.apk
|
||||
path: build/android/app/build/outputs/apk/release/app-arm64-v8a-release-unsigned.apk
|
||||
path: android/app/build/outputs/apk/release/app-arm64-v8a-release-unsigned.apk
|
||||
|
5
.github/workflows/build.yml
vendored
@ -180,7 +180,8 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build docker image
|
||||
run: |
|
||||
docker build .
|
||||
docker build . -t minetest:latest
|
||||
docker run --rm minetest:latest /usr/local/bin/minetestserver --version
|
||||
|
||||
win32:
|
||||
name: "MinGW cross-compiler (32-bit)"
|
||||
@ -227,7 +228,7 @@ jobs:
|
||||
env:
|
||||
VCPKG_VERSION: 0bf3923f9fab4001c00f0f429682a0853b5749e0
|
||||
# 2020.11
|
||||
vcpkg_packages: irrlicht zlib curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit
|
||||
vcpkg_packages: irrlicht zlib zstd curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
66
.github/workflows/macos.yml
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
name: macos
|
||||
|
||||
# build on c/cpp changes or workflow changes
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'lib/**.[ch]'
|
||||
- 'lib/**.cpp'
|
||||
- 'src/**.[ch]'
|
||||
- 'src/**.cpp'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'cmake/Modules/**'
|
||||
- '.github/workflows/macos.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'lib/**.[ch]'
|
||||
- 'lib/**.cpp'
|
||||
- 'src/**.[ch]'
|
||||
- 'src/**.cpp'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'cmake/Modules/**'
|
||||
- '.github/workflows/macos.yml'
|
||||
|
||||
env:
|
||||
IRRLICHT_TAG: 1.9.0mt3
|
||||
MINETEST_GAME_REPO: https://github.com/minetest/minetest_game.git
|
||||
MINETEST_GAME_BRANCH: master
|
||||
MINETEST_GAME_NAME: minetest_game
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-10.15
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install deps
|
||||
run: |
|
||||
pkgs=(cmake freetype gettext gmp hiredis jpeg jsoncpp leveldb libogg libpng libvorbis luajit zstd)
|
||||
brew update
|
||||
brew install ${pkgs[@]}
|
||||
brew unlink $(brew ls --formula)
|
||||
brew link ${pkgs[@]}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
git clone -b $MINETEST_GAME_BRANCH $MINETEST_GAME_REPO games/$MINETEST_GAME_NAME
|
||||
rm -rvf games/$MINETEST_GAME_NAME/.git
|
||||
git clone https://github.com/minetest/irrlicht -b $IRRLICHT_TAG lib/irrlichtmt
|
||||
mkdir cmakebuild
|
||||
cd cmakebuild
|
||||
cmake .. \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14 \
|
||||
-DCMAKE_FIND_FRAMEWORK=LAST \
|
||||
-DCMAKE_INSTALL_PREFIX=../build/macos/ \
|
||||
-DRUN_IN_PLACE=FALSE \
|
||||
-DENABLE_FREETYPE=TRUE -DENABLE_GETTEXT=TRUE
|
||||
make -j2
|
||||
make install
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
./build/macos/minetest.app/Contents/MacOS/minetest --run-unittests
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: minetest-macos
|
||||
path: ./build/macos/
|
5
.gitignore
vendored
@ -76,6 +76,7 @@ doc/mkdocs/docs/*.md
|
||||
doc/mkdocs/mkdocs.yml
|
||||
|
||||
## Build files
|
||||
build/
|
||||
CMakeFiles
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
@ -86,6 +87,7 @@ src/test_config.h
|
||||
src/cmake_config.h
|
||||
src/cmake_config_githash.h
|
||||
src/unittest/test_world/world.mt
|
||||
games/devtest/mods/testnodes/textures/testnodes_generated_*.png
|
||||
/locale/
|
||||
.directory
|
||||
*.cbp
|
||||
@ -105,3 +107,6 @@ CMakeDoxy*
|
||||
compile_commands.json
|
||||
*.apk
|
||||
*.zip
|
||||
|
||||
# Optional user provided library folder
|
||||
lib/irrlichtmt
|
||||
|
@ -9,7 +9,7 @@ stages:
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
IRRLICHT_TAG: "1.9.0mt1"
|
||||
IRRLICHT_TAG: "1.9.0mt3"
|
||||
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
|
||||
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
|
||||
|
||||
@ -17,16 +17,12 @@ variables:
|
||||
stage: build
|
||||
before_script:
|
||||
- apt-get update
|
||||
- apt-get -y install build-essential git cmake libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libleveldb-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
|
||||
- DEBIAN_FRONTEND=noninteractive apt-get -y install build-essential git cmake libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libleveldb-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev
|
||||
script:
|
||||
- git clone https://github.com/minetest/irrlicht -b $IRRLICHT_TAG
|
||||
- cd irrlicht
|
||||
- cmake . -DBUILD_SHARED_LIBS=OFF
|
||||
- make -j2
|
||||
- cd ..
|
||||
- git clone https://github.com/minetest/irrlicht -b $IRRLICHT_TAG lib/irrlichtmt
|
||||
- mkdir cmakebuild
|
||||
- cd cmakebuild
|
||||
- cmake -DIRRLICHT_LIBRARY=$PWD/../irrlicht/lib/Linux/libIrrlichtMt.a -DIRRLICHT_INCLUDE_DIR=$PWD/../irrlicht/include -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE ..
|
||||
- cmake -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE ..
|
||||
- make -j2
|
||||
- make install
|
||||
artifacts:
|
||||
@ -49,6 +45,7 @@ variables:
|
||||
- sed -i 's/DATEPLACEHOLDER/'$(date +%y.%m.%d)'/g' build/deb/minetest/DEBIAN/control
|
||||
- sed -i 's/JPEG_PLACEHOLDER/'$JPEG_PKG'/g' build/deb/minetest/DEBIAN/control
|
||||
- sed -i 's/LEVELDB_PLACEHOLDER/'$LEVELDB_PKG'/g' build/deb/minetest/DEBIAN/control
|
||||
- sed -i 's/JSONCPP_PLACEHOLDER/'$JSONCPP_PKG'/g' build/deb/minetest/DEBIAN/control
|
||||
- cd build/deb/ && dpkg-deb -b minetest/ && mv minetest.deb ../../
|
||||
artifacts:
|
||||
expire_in: 90 day
|
||||
@ -58,7 +55,7 @@ variables:
|
||||
.debpkg_install:
|
||||
stage: deploy
|
||||
before_script:
|
||||
- apt-get update
|
||||
- apt-get update -qy
|
||||
script:
|
||||
- apt-get install -y ./*.deb
|
||||
- minetest --version
|
||||
@ -79,6 +76,7 @@ package:debian-9:
|
||||
needs:
|
||||
- build:debian-9
|
||||
variables:
|
||||
JSONCPP_PKG: libjsoncpp1
|
||||
LEVELDB_PKG: libleveldb1v5
|
||||
JPEG_PKG: libjpeg62-turbo
|
||||
|
||||
@ -100,6 +98,7 @@ package:debian-10:
|
||||
needs:
|
||||
- build:debian-10
|
||||
variables:
|
||||
JSONCPP_PKG: libjsoncpp1
|
||||
LEVELDB_PKG: libleveldb1d
|
||||
JPEG_PKG: libjpeg62-turbo
|
||||
|
||||
@ -109,31 +108,32 @@ deploy:debian-10:
|
||||
needs:
|
||||
- package:debian-10
|
||||
|
||||
# Bullseye
|
||||
|
||||
build:debian-11:
|
||||
extends: .build_template
|
||||
image: debian:11
|
||||
|
||||
package:debian-11:
|
||||
extends: .debpkg_template
|
||||
image: debian:11
|
||||
needs:
|
||||
- build:debian-11
|
||||
variables:
|
||||
JSONCPP_PKG: libjsoncpp24
|
||||
LEVELDB_PKG: libleveldb1d
|
||||
JPEG_PKG: libjpeg62-turbo
|
||||
|
||||
deploy:debian-11:
|
||||
extends: .debpkg_install
|
||||
image: debian:11
|
||||
needs:
|
||||
- package:debian-11
|
||||
|
||||
##
|
||||
## Ubuntu
|
||||
##
|
||||
|
||||
# Xenial
|
||||
|
||||
build:ubuntu-16.04:
|
||||
extends: .build_template
|
||||
image: ubuntu:xenial
|
||||
|
||||
package:ubuntu-16.04:
|
||||
extends: .debpkg_template
|
||||
image: ubuntu:xenial
|
||||
needs:
|
||||
- build:ubuntu-16.04
|
||||
variables:
|
||||
LEVELDB_PKG: libleveldb1v5
|
||||
JPEG_PKG: libjpeg-turbo8
|
||||
|
||||
deploy:ubuntu-16.04:
|
||||
extends: .debpkg_install
|
||||
image: ubuntu:xenial
|
||||
needs:
|
||||
- package:ubuntu-16.04
|
||||
|
||||
# Bionic
|
||||
|
||||
build:ubuntu-18.04:
|
||||
@ -146,6 +146,7 @@ package:ubuntu-18.04:
|
||||
needs:
|
||||
- build:ubuntu-18.04
|
||||
variables:
|
||||
JSONCPP_PKG: libjsoncpp1
|
||||
LEVELDB_PKG: libleveldb1v5
|
||||
JPEG_PKG: libjpeg-turbo8
|
||||
|
||||
@ -155,6 +156,28 @@ deploy:ubuntu-18.04:
|
||||
needs:
|
||||
- package:ubuntu-18.04
|
||||
|
||||
# Focal
|
||||
|
||||
build:ubuntu-20.04:
|
||||
extends: .build_template
|
||||
image: ubuntu:focal
|
||||
|
||||
package:ubuntu-20.04:
|
||||
extends: .debpkg_template
|
||||
image: ubuntu:focal
|
||||
needs:
|
||||
- build:ubuntu-20.04
|
||||
variables:
|
||||
JSONCPP_PKG: libjsoncpp1
|
||||
LEVELDB_PKG: libleveldb1d
|
||||
JPEG_PKG: libjpeg-turbo8
|
||||
|
||||
deploy:ubuntu-20.04:
|
||||
extends: .debpkg_install
|
||||
image: ubuntu:focal
|
||||
needs:
|
||||
- package:ubuntu-20.04
|
||||
|
||||
##
|
||||
## Fedora
|
||||
##
|
||||
@ -164,7 +187,7 @@ build:fedora-28:
|
||||
extends: .build_template
|
||||
image: fedora:28
|
||||
before_script:
|
||||
- dnf -y install make git gcc gcc-c++ kernel-devel cmake libjpeg-devel libpng-devel libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel
|
||||
- dnf -y install make git gcc gcc-c++ kernel-devel cmake libjpeg-devel libpng-devel libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel
|
||||
|
||||
##
|
||||
## MinGW for Windows
|
||||
@ -275,7 +298,7 @@ package:appimage-client:
|
||||
- build:ubuntu-18.04
|
||||
before_script:
|
||||
- apt-get update -y
|
||||
- apt-get install -y git wget
|
||||
- apt-get install -y git
|
||||
# Collect files
|
||||
- mkdir AppDir
|
||||
- cp -a artifact/minetest/usr/ AppDir/usr/
|
||||
|
@ -24,18 +24,21 @@ AppDir:
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security main universe
|
||||
|
||||
include:
|
||||
- libirrlicht1.8
|
||||
- libxxf86vm1
|
||||
- libgl1-mesa-glx
|
||||
- libsqlite3-0
|
||||
- libogg0
|
||||
- libvorbis0a
|
||||
- libopenal1
|
||||
- libc6
|
||||
- libcurl3-gnutls
|
||||
- libfreetype6
|
||||
- zlib1g
|
||||
- libgmp10
|
||||
- libgl1
|
||||
- libjpeg-turbo8
|
||||
- libjsoncpp1
|
||||
- libleveldb1v5
|
||||
- libopenal1
|
||||
- libpng16-16
|
||||
- libsqlite3-0
|
||||
- libstdc++6
|
||||
- libvorbisfile3
|
||||
- libx11-6
|
||||
- libxxf86vm1
|
||||
- zlib1g
|
||||
|
||||
files:
|
||||
exclude:
|
||||
|
@ -1,5 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Set policies up to 3.9 since we want to enable the IPO option
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.9)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
else()
|
||||
cmake_policy(VERSION 3.9)
|
||||
endif()
|
||||
|
||||
# This can be read from ${PROJECT_NAME} after project() is called
|
||||
project(minetest)
|
||||
set(PROJECT_NAME_CAPITALIZED "Dragonfire")
|
||||
@ -58,28 +65,44 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||
|
||||
|
||||
# This is done here so that relative search paths are more reasonable
|
||||
find_package(Irrlicht)
|
||||
if(BUILD_CLIENT AND NOT IRRLICHT_FOUND)
|
||||
message(FATAL_ERROR "IrrlichtMt is required to build the client, but it was not found.")
|
||||
elseif(NOT IRRLICHT_INCLUDE_DIR)
|
||||
message(FATAL_ERROR "Irrlicht or IrrlichtMt headers are required to build the server, but none found.")
|
||||
endif()
|
||||
|
||||
include(CheckSymbolExists)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${IRRLICHT_INCLUDE_DIR})
|
||||
unset(HAS_FORKED_IRRLICHT CACHE)
|
||||
check_symbol_exists(IRRLICHT_VERSION_MT "IrrCompileConfig.h" HAS_FORKED_IRRLICHT)
|
||||
if(NOT HAS_FORKED_IRRLICHT)
|
||||
string(CONCAT EXPLANATION_MSG
|
||||
"Irrlicht found, but it is not IrrlichtMt (Minetest's Irrlicht fork). "
|
||||
"The Minetest team has forked Irrlicht to make their own customizations. "
|
||||
"It can be found here: https://github.com/minetest/irrlicht")
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt")
|
||||
message(STATUS "Using user-provided IrrlichtMt at subdirectory 'lib/irrlichtmt'")
|
||||
if(BUILD_CLIENT)
|
||||
message(FATAL_ERROR "${EXPLANATION_MSG}\n"
|
||||
"Building the client with upstream Irrlicht is no longer possible.")
|
||||
# tell IrrlichtMt to create a static library
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared library" FORCE)
|
||||
add_subdirectory(lib/irrlichtmt EXCLUDE_FROM_ALL)
|
||||
unset(BUILD_SHARED_LIBS CACHE)
|
||||
|
||||
if(NOT TARGET IrrlichtMt)
|
||||
message(FATAL_ERROR "IrrlichtMt project is missing a CMake target?!")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "${EXPLANATION_MSG}\n"
|
||||
"The server can still be built with upstream Irrlicht but this is DISCOURAGED.")
|
||||
add_library(IrrlichtMt::IrrlichtMt INTERFACE IMPORTED)
|
||||
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt/include")
|
||||
endif()
|
||||
else()
|
||||
find_package(IrrlichtMt QUIET)
|
||||
if(NOT TARGET IrrlichtMt::IrrlichtMt)
|
||||
string(CONCAT explanation_msg
|
||||
"The Minetest team has forked Irrlicht to make their own customizations. "
|
||||
"It can be found here: https://github.com/minetest/irrlicht\n"
|
||||
"For example use: git clone --depth=1 https://github.com/minetest/irrlicht lib/irrlichtmt\n")
|
||||
if(BUILD_CLIENT)
|
||||
message(FATAL_ERROR "IrrlichtMt is required to build the client, but it was not found.\n${explanation_msg}")
|
||||
endif()
|
||||
|
||||
include(MinetestFindIrrlichtHeaders)
|
||||
if(NOT IRRLICHT_INCLUDE_DIR)
|
||||
message(FATAL_ERROR "Irrlicht or IrrlichtMt headers are required to build the server, but none found.\n${explanation_msg}")
|
||||
endif()
|
||||
message(STATUS "Found Irrlicht headers: ${IRRLICHT_INCLUDE_DIR}")
|
||||
add_library(IrrlichtMt::IrrlichtMt INTERFACE IMPORTED)
|
||||
# Note that we can't use target_include_directories() since that doesn't work for IMPORTED targets before CMake 3.11
|
||||
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${IRRLICHT_INCLUDE_DIR}")
|
||||
else()
|
||||
message(STATUS "Found IrrlichtMt ${IrrlichtMt_VERSION}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
32
Dockerfile
@ -1,4 +1,5 @@
|
||||
FROM alpine:3.13
|
||||
ARG DOCKER_IMAGE=alpine:3.14
|
||||
FROM $DOCKER_IMAGE AS builder
|
||||
|
||||
ENV MINETEST_GAME_VERSION master
|
||||
ENV IRRLICHT_VERSION master
|
||||
@ -19,8 +20,8 @@ COPY textures /usr/src/minetest/textures
|
||||
|
||||
WORKDIR /usr/src/minetest
|
||||
|
||||
RUN apk add --no-cache git build-base cmake sqlite-dev curl-dev zlib-dev \
|
||||
gmp-dev jsoncpp-dev postgresql-dev luajit-dev ca-certificates && \
|
||||
RUN apk add --no-cache git build-base cmake sqlite-dev curl-dev zlib-dev zstd-dev \
|
||||
gmp-dev jsoncpp-dev postgresql-dev ninja luajit-dev ca-certificates && \
|
||||
git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \
|
||||
rm -fr ./games/minetest_game/.git
|
||||
|
||||
@ -31,9 +32,10 @@ RUN git clone --recursive https://github.com/jupp0r/prometheus-cpp/ && \
|
||||
cmake .. \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DENABLE_TESTING=0 && \
|
||||
make -j2 && \
|
||||
make install
|
||||
-DENABLE_TESTING=0 \
|
||||
-GNinja && \
|
||||
ninja && \
|
||||
ninja install
|
||||
|
||||
RUN git clone --depth=1 https://github.com/minetest/irrlicht/ -b ${IRRLICHT_VERSION} && \
|
||||
cp -r irrlicht/include /usr/include/irrlichtmt
|
||||
@ -47,21 +49,23 @@ RUN mkdir build && \
|
||||
-DBUILD_SERVER=TRUE \
|
||||
-DENABLE_PROMETHEUS=TRUE \
|
||||
-DBUILD_UNITTESTS=FALSE \
|
||||
-DBUILD_CLIENT=FALSE && \
|
||||
make -j2 && \
|
||||
make install
|
||||
-DBUILD_CLIENT=FALSE \
|
||||
-GNinja && \
|
||||
ninja && \
|
||||
ninja install
|
||||
|
||||
FROM alpine:3.13
|
||||
ARG DOCKER_IMAGE=alpine:3.14
|
||||
FROM $DOCKER_IMAGE AS runtime
|
||||
|
||||
RUN apk add --no-cache sqlite-libs curl gmp libstdc++ libgcc libpq luajit jsoncpp && \
|
||||
RUN apk add --no-cache sqlite-libs curl gmp libstdc++ libgcc libpq luajit jsoncpp zstd-libs && \
|
||||
adduser -D minetest --uid 30000 -h /var/lib/minetest && \
|
||||
chown -R minetest:minetest /var/lib/minetest
|
||||
|
||||
WORKDIR /var/lib/minetest
|
||||
|
||||
COPY --from=0 /usr/local/share/minetest /usr/local/share/minetest
|
||||
COPY --from=0 /usr/local/bin/minetestserver /usr/local/bin/minetestserver
|
||||
COPY --from=0 /usr/local/share/doc/minetest/minetest.conf.example /etc/minetest/minetest.conf
|
||||
COPY --from=builder /usr/local/share/minetest /usr/local/share/minetest
|
||||
COPY --from=builder /usr/local/bin/minetestserver /usr/local/bin/minetestserver
|
||||
COPY --from=builder /usr/local/share/doc/minetest/minetest.conf.example /etc/minetest/minetest.conf
|
||||
|
||||
USER minetest:minetest
|
||||
|
||||
|
49
README.md
@ -136,25 +136,26 @@ Compiling
|
||||
| CMake | 3.5+ | |
|
||||
| IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
|
||||
| SQLite3 | 3.0+ | |
|
||||
| Zstd | 1.0+ | |
|
||||
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
|
||||
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
|
||||
| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present |
|
||||
|
||||
For Debian/Ubuntu users:
|
||||
|
||||
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev
|
||||
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev
|
||||
|
||||
For Fedora users:
|
||||
|
||||
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel
|
||||
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libvorbis-devel libXxf86vm-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel
|
||||
|
||||
For Arch users:
|
||||
|
||||
sudo pacman -S base-devel libcurl-gnutls cmake libxxf86vm libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses
|
||||
sudo pacman -S base-devel libcurl-gnutls cmake libxxf86vm libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd
|
||||
|
||||
For Alpine users:
|
||||
|
||||
sudo apk add build-base cmake libpng-dev jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev
|
||||
sudo apk add build-base cmake libpng-dev jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev
|
||||
|
||||
#### Download
|
||||
|
||||
@ -177,6 +178,10 @@ Download minetest_game (otherwise only the "Development Test" game is available)
|
||||
|
||||
git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
|
||||
|
||||
Download IrrlichtMt to `lib/irrlichtmt`, it will be used to satisfy the IrrlichtMt dependency that way:
|
||||
|
||||
git clone --depth 1 https://github.com/minetest/irrlicht.git lib/irrlichtmt
|
||||
|
||||
Download source, without using Git:
|
||||
|
||||
wget https://github.com/minetest/minetest/archive/master.tar.gz
|
||||
@ -191,6 +196,14 @@ Download minetest_game, without using Git:
|
||||
mv minetest_game-master minetest_game
|
||||
cd ..
|
||||
|
||||
Download IrrlichtMt, without using Git:
|
||||
|
||||
cd lib/
|
||||
wget https://github.com/minetest/irrlicht/archive/master.tar.gz
|
||||
tar xf master.tar.gz
|
||||
mv irrlicht-master irrlichtmt
|
||||
cd ..
|
||||
|
||||
#### Build
|
||||
|
||||
Build a version that runs directly from the source directory:
|
||||
@ -211,6 +224,10 @@ Run it:
|
||||
- Debug build is slower, but gives much more useful output in a debugger.
|
||||
- If you build a bare server you don't need to have the Irrlicht or IrrlichtMt library installed.
|
||||
- In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlicht/include`.
|
||||
- IrrlichtMt can also be installed somewhere that is not a standard install path.
|
||||
- In that case use `-DCMAKE_PREFIX_PATH=/path/to/install_prefix`
|
||||
- The path must be set so that `$(CMAKE_PREFIX_PATH)/lib/cmake/IrrlichtMt` exists
|
||||
or that `$(CMAKE_PREFIX_PATH)` is the path of an IrrlichtMt build folder.
|
||||
|
||||
### CMake options
|
||||
|
||||
@ -260,8 +277,7 @@ Library specific options:
|
||||
GETTEXT_LIBRARY - Only when building with gettext on Windows; path to libintl.dll.a
|
||||
GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe
|
||||
IRRLICHT_DLL - Only on Windows; path to IrrlichtMt.dll
|
||||
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h
|
||||
IRRLICHT_LIBRARY - Path to libIrrlichtMt.a/libIrrlichtMt.so/libIrrlichtMt.dll.a/IrrlichtMt.lib
|
||||
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h (usable for server build only)
|
||||
LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h
|
||||
LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
|
||||
LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll
|
||||
@ -291,8 +307,11 @@ Library specific options:
|
||||
ZLIB_DLL - Only on Windows; path to zlib1.dll
|
||||
ZLIB_INCLUDE_DIR - Directory that contains zlib.h
|
||||
ZLIB_LIBRARY - Path to libz.a/libz.so/zlib.lib
|
||||
ZSTD_DLL - Only on Windows; path to libzstd.dll
|
||||
ZSTD_INCLUDE_DIR - Directory that contains zstd.h
|
||||
ZSTD_LIBRARY - Path to libzstd.a/libzstd.so/ztd.lib
|
||||
|
||||
### Compiling on Windows
|
||||
### Compiling on Windows using MSVC
|
||||
|
||||
### Requirements
|
||||
|
||||
@ -305,14 +324,12 @@ Library specific options:
|
||||
|
||||
It is highly recommended to use vcpkg as package manager.
|
||||
|
||||
#### a) Using vcpkg to install dependencies
|
||||
|
||||
After you successfully built vcpkg you can easily install the required libraries:
|
||||
```powershell
|
||||
vcpkg install zlib curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit gmp jsoncpp --triplet x64-windows
|
||||
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg sqlite3 freetype luajit gmp jsoncpp --triplet x64-windows
|
||||
```
|
||||
|
||||
- **Note that you currently need to build irrlicht on your own**
|
||||
- **Don't forget about IrrlichtMt.** The easiest way is to clone it to `lib/irrlichtmt` as described in the Linux section.
|
||||
- `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store.
|
||||
- `openal-soft`, `libvorbis` and `libogg` are optional, but required to use sound.
|
||||
- `freetype` is optional, it allows true-type font rendering.
|
||||
@ -323,10 +340,6 @@ There are other optional libraries, but they are not tested if they can build an
|
||||
|
||||
Use `--triplet` to specify the target triplet, e.g. `x64-windows` or `x86-windows`.
|
||||
|
||||
#### b) Compile the dependencies on your own
|
||||
|
||||
This is outdated and not recommended. Follow the instructions on https://dev.minetest.net/Build_Win32_Minetest_including_all_required_libraries#VS2012_Build
|
||||
|
||||
### Compile Minetest
|
||||
|
||||
#### a) Using the vcpkg toolchain and CMake GUI
|
||||
@ -355,12 +368,6 @@ cmake --build . --config Release
|
||||
```
|
||||
Make sure that the right compiler is selected and the path to the vcpkg toolchain is correct.
|
||||
|
||||
#### c) Using your own compiled libraries
|
||||
|
||||
**This is outdated and not recommended**
|
||||
|
||||
Follow the instructions on https://dev.minetest.net/Build_Win32_Minetest_including_all_required_libraries#VS2012_Build
|
||||
|
||||
### Windows Installer using WiX Toolset
|
||||
|
||||
Requirements:
|
||||
|
@ -52,7 +52,7 @@ android {
|
||||
|
||||
task prepareAssets() {
|
||||
def assetsFolder = "build/assets"
|
||||
def projRoot = "../../.."
|
||||
def projRoot = "../.."
|
||||
def gameToCopy = "minetest_game"
|
||||
|
||||
copy {
|
||||
@ -76,10 +76,13 @@ task prepareAssets() {
|
||||
copy {
|
||||
from "${projRoot}/games/${gameToCopy}" into "${assetsFolder}/games/${gameToCopy}"
|
||||
}
|
||||
/*copy {
|
||||
// ToDo: fix broken locales
|
||||
from "${projRoot}/po" into "${assetsFolder}/po"
|
||||
}*/
|
||||
fileTree("${projRoot}/po").include("**/*.po").forEach { poFile ->
|
||||
def moPath = "${assetsFolder}/locale/${poFile.parentFile.name}/LC_MESSAGES/"
|
||||
file(moPath).mkdirs()
|
||||
exec {
|
||||
commandLine 'msgfmt', '-o', "${moPath}/minetest.mo", poFile
|
||||
}
|
||||
}
|
||||
copy {
|
||||
from "${projRoot}/textures" into "${assetsFolder}/textures"
|
||||
}
|
@ -30,7 +30,9 @@ import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
@ -85,9 +87,19 @@ public class GameActivity extends NativeActivity {
|
||||
|
||||
private void showDialogUI(String hint, String current, int editType) {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
EditText editText = new CustomEditText(this);
|
||||
builder.setView(editText);
|
||||
LinearLayout container = new LinearLayout(this);
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
builder.setView(container);
|
||||
AlertDialog alertDialog = builder.create();
|
||||
EditText editText;
|
||||
// For multi-line, do not close the dialog after pressing back button
|
||||
if (editType == 1) {
|
||||
editText = new EditText(this);
|
||||
} else {
|
||||
editText = new CustomEditText(this);
|
||||
}
|
||||
container.addView(editText);
|
||||
editText.setMaxLines(8);
|
||||
editText.requestFocus();
|
||||
editText.setHint(hint);
|
||||
editText.setText(current);
|
||||
@ -103,8 +115,9 @@ public class GameActivity extends NativeActivity {
|
||||
else
|
||||
editText.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
editText.setSelection(editText.getText().length());
|
||||
editText.setOnKeyListener((view, KeyCode, event) -> {
|
||||
if (KeyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
editText.setOnKeyListener((view, keyCode, event) -> {
|
||||
// For multi-line, do not submit the text after pressing Enter key
|
||||
if (keyCode == KeyEvent.KEYCODE_ENTER && editType != 1) {
|
||||
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
|
||||
messageReturnCode = 0;
|
||||
messageReturnValue = editText.getText().toString();
|
||||
@ -113,6 +126,18 @@ public class GameActivity extends NativeActivity {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
// For multi-line, add Done button since Enter key does not submit text
|
||||
if (editType == 1) {
|
||||
Button doneButton = new Button(this);
|
||||
container.addView(doneButton);
|
||||
doneButton.setText(R.string.ime_dialog_done);
|
||||
doneButton.setOnClickListener((view -> {
|
||||
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
|
||||
messageReturnCode = 0;
|
||||
messageReturnValue = editText.getText().toString();
|
||||
alertDialog.dismiss();
|
||||
}));
|
||||
}
|
||||
alertDialog.show();
|
||||
alertDialog.setOnCancelListener(dialog -> {
|
||||
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
Before Width: | Height: | Size: 83 B After Width: | Height: | Size: 83 B |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
@ -6,5 +6,6 @@
|
||||
<string name="not_granted">Required permission wasn\'t granted, Minetest can\'t run without it</string>
|
||||
<string name="notification_title">Loading Minetest</string>
|
||||
<string name="notification_description">Less than 1 minute…</string>
|
||||
<string name="ime_dialog_done">Done</string>
|
||||
|
||||
</resources>
|
0
build/android/gradlew → android/gradlew
vendored
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
219
android/native/jni/Android.mk
Normal file
@ -0,0 +1,219 @@
|
||||
LOCAL_PATH := $(call my-dir)/..
|
||||
|
||||
#LOCAL_ADDRESS_SANITIZER:=true
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Curl
|
||||
LOCAL_SRC_FILES := deps/Android/Curl/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcurl.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Freetype
|
||||
LOCAL_SRC_FILES := deps/Android/Freetype/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libfreetype.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Irrlicht
|
||||
LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlichtMt.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := LevelDB
|
||||
#LOCAL_SRC_FILES := deps/Android/LevelDB/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libleveldb.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := LuaJIT
|
||||
LOCAL_SRC_FILES := deps/Android/LuaJIT/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libluajit.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mbedTLS
|
||||
LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedtls.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mbedx509
|
||||
LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedx509.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mbedcrypto
|
||||
LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedcrypto.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := OpenAL
|
||||
LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := GetText
|
||||
LOCAL_SRC_FILES := deps/Android/GetText/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libintl.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Vorbis
|
||||
LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Zstd
|
||||
LOCAL_SRC_FILES := deps/Android/Zstd/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libzstd.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Minetest
|
||||
|
||||
LOCAL_CFLAGS += \
|
||||
-DJSONCPP_NO_LOCALE_SUPPORT \
|
||||
-DHAVE_TOUCHSCREENGUI \
|
||||
-DENABLE_GLES=1 \
|
||||
-DUSE_CURL=1 \
|
||||
-DUSE_SOUND=1 \
|
||||
-DUSE_FREETYPE=1 \
|
||||
-DUSE_LEVELDB=0 \
|
||||
-DUSE_LUAJIT=1 \
|
||||
-DUSE_GETTEXT=1 \
|
||||
-DVERSION_MAJOR=${versionMajor} \
|
||||
-DVERSION_MINOR=${versionMinor} \
|
||||
-DVERSION_PATCH=${versionPatch} \
|
||||
-DVERSION_EXTRA=${versionExtra} \
|
||||
$(GPROF_DEF)
|
||||
|
||||
ifdef NDEBUG
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
endif
|
||||
|
||||
ifdef GPROF
|
||||
GPROF_DEF := -DGPROF
|
||||
PROFILER_LIBS := android-ndk-profiler
|
||||
LOCAL_CFLAGS += -pg
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
../../src \
|
||||
../../src/script \
|
||||
../../lib/gmp \
|
||||
../../lib/jsoncpp \
|
||||
deps/Android/Curl/include \
|
||||
deps/Android/Freetype/include \
|
||||
deps/Android/Irrlicht/include \
|
||||
deps/Android/LevelDB/include \
|
||||
deps/Android/GetText/include \
|
||||
deps/Android/libiconv/include \
|
||||
deps/Android/libiconv/libcharset/include \
|
||||
deps/Android/LuaJIT/src \
|
||||
deps/Android/OpenAL-Soft/include \
|
||||
deps/Android/sqlite \
|
||||
deps/Android/Vorbis/include \
|
||||
deps/Android/Zstd/include
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(wildcard ../../src/client/*.cpp) \
|
||||
$(wildcard ../../src/client/*/*.cpp) \
|
||||
$(wildcard ../../src/content/*.cpp) \
|
||||
../../src/database/database.cpp \
|
||||
../../src/database/database-dummy.cpp \
|
||||
../../src/database/database-files.cpp \
|
||||
../../src/database/database-sqlite3.cpp \
|
||||
$(wildcard ../../src/gui/*.cpp) \
|
||||
$(wildcard ../../src/irrlicht_changes/*.cpp) \
|
||||
$(wildcard ../../src/mapgen/*.cpp) \
|
||||
$(wildcard ../../src/network/*.cpp) \
|
||||
$(wildcard ../../src/script/*.cpp) \
|
||||
$(wildcard ../../src/script/*/*.cpp) \
|
||||
$(wildcard ../../src/server/*.cpp) \
|
||||
$(wildcard ../../src/threading/*.cpp) \
|
||||
$(wildcard ../../src/util/*.c) \
|
||||
$(wildcard ../../src/util/*.cpp) \
|
||||
../../src/ban.cpp \
|
||||
../../src/chat.cpp \
|
||||
../../src/clientiface.cpp \
|
||||
../../src/collision.cpp \
|
||||
../../src/content_mapnode.cpp \
|
||||
../../src/content_nodemeta.cpp \
|
||||
../../src/convert_json.cpp \
|
||||
../../src/craftdef.cpp \
|
||||
../../src/debug.cpp \
|
||||
../../src/defaultsettings.cpp \
|
||||
../../src/emerge.cpp \
|
||||
../../src/environment.cpp \
|
||||
../../src/face_position_cache.cpp \
|
||||
../../src/filesys.cpp \
|
||||
../../src/gettext.cpp \
|
||||
../../src/httpfetch.cpp \
|
||||
../../src/hud.cpp \
|
||||
../../src/inventory.cpp \
|
||||
../../src/inventorymanager.cpp \
|
||||
../../src/itemdef.cpp \
|
||||
../../src/itemstackmetadata.cpp \
|
||||
../../src/light.cpp \
|
||||
../../src/log.cpp \
|
||||
../../src/main.cpp \
|
||||
../../src/map.cpp \
|
||||
../../src/map_settings_manager.cpp \
|
||||
../../src/mapblock.cpp \
|
||||
../../src/mapnode.cpp \
|
||||
../../src/mapsector.cpp \
|
||||
../../src/metadata.cpp \
|
||||
../../src/modchannels.cpp \
|
||||
../../src/nameidmapping.cpp \
|
||||
../../src/nodedef.cpp \
|
||||
../../src/nodemetadata.cpp \
|
||||
../../src/nodetimer.cpp \
|
||||
../../src/noise.cpp \
|
||||
../../src/objdef.cpp \
|
||||
../../src/object_properties.cpp \
|
||||
../../src/particles.cpp \
|
||||
../../src/pathfinder.cpp \
|
||||
../../src/player.cpp \
|
||||
../../src/porting.cpp \
|
||||
../../src/porting_android.cpp \
|
||||
../../src/profiler.cpp \
|
||||
../../src/raycast.cpp \
|
||||
../../src/reflowscan.cpp \
|
||||
../../src/remoteplayer.cpp \
|
||||
../../src/rollback.cpp \
|
||||
../../src/rollback_interface.cpp \
|
||||
../../src/serialization.cpp \
|
||||
../../src/server.cpp \
|
||||
../../src/serverenvironment.cpp \
|
||||
../../src/serverlist.cpp \
|
||||
../../src/settings.cpp \
|
||||
../../src/staticobject.cpp \
|
||||
../../src/texture_override.cpp \
|
||||
../../src/tileanimation.cpp \
|
||||
../../src/tool.cpp \
|
||||
../../src/translation.cpp \
|
||||
../../src/version.cpp \
|
||||
../../src/voxel.cpp \
|
||||
../../src/voxelalgorithms.cpp
|
||||
|
||||
# LevelDB backend is disabled
|
||||
# ../../src/database/database-leveldb.cpp
|
||||
|
||||
# GMP
|
||||
LOCAL_SRC_FILES += ../../lib/gmp/mini-gmp.c
|
||||
|
||||
# JSONCPP
|
||||
LOCAL_SRC_FILES += ../../lib/jsoncpp/jsoncpp.cpp
|
||||
|
||||
# iconv
|
||||
LOCAL_SRC_FILES += \
|
||||
deps/Android/libiconv/lib/iconv.c \
|
||||
deps/Android/libiconv/libcharset/lib/localcharset.c
|
||||
|
||||
# SQLite3
|
||||
LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c
|
||||
|
||||
LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT GetText Zstd android_native_app_glue $(PROFILER_LIBS) #LevelDB
|
||||
|
||||
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
ifdef GPROF
|
||||
$(call import-module,android-ndk-profiler)
|
||||
endif
|
||||
$(call import-module,android/native_app_glue)
|
@ -1,206 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)/..
|
||||
|
||||
#LOCAL_ADDRESS_SANITIZER:=true
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Curl
|
||||
LOCAL_SRC_FILES := deps/Android/Curl/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcurl.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Freetype
|
||||
LOCAL_SRC_FILES := deps/Android/Freetype/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libfreetype.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Irrlicht
|
||||
LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlichtMt.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := LevelDB
|
||||
#LOCAL_SRC_FILES := deps/Android/LevelDB/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libleveldb.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := LuaJIT
|
||||
LOCAL_SRC_FILES := deps/Android/LuaJIT/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libluajit.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mbedTLS
|
||||
LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedtls.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mbedx509
|
||||
LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedx509.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := mbedcrypto
|
||||
LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedcrypto.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := OpenAL
|
||||
LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Vorbis
|
||||
LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := Minetest
|
||||
|
||||
LOCAL_CFLAGS += \
|
||||
-DJSONCPP_NO_LOCALE_SUPPORT \
|
||||
-DHAVE_TOUCHSCREENGUI \
|
||||
-DENABLE_GLES=1 \
|
||||
-DUSE_CURL=1 \
|
||||
-DUSE_SOUND=1 \
|
||||
-DUSE_FREETYPE=1 \
|
||||
-DUSE_LEVELDB=0 \
|
||||
-DUSE_LUAJIT=1 \
|
||||
-DVERSION_MAJOR=${versionMajor} \
|
||||
-DVERSION_MINOR=${versionMinor} \
|
||||
-DVERSION_PATCH=${versionPatch} \
|
||||
-DVERSION_EXTRA=${versionExtra} \
|
||||
$(GPROF_DEF)
|
||||
|
||||
ifdef NDEBUG
|
||||
LOCAL_CFLAGS += -DNDEBUG=1
|
||||
endif
|
||||
|
||||
ifdef GPROF
|
||||
GPROF_DEF := -DGPROF
|
||||
PROFILER_LIBS := android-ndk-profiler
|
||||
LOCAL_CFLAGS += -pg
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
../../../src \
|
||||
../../../src/script \
|
||||
../../../lib/gmp \
|
||||
../../../lib/jsoncpp \
|
||||
deps/Android/Curl/include \
|
||||
deps/Android/Freetype/include \
|
||||
deps/Android/Irrlicht/include \
|
||||
deps/Android/LevelDB/include \
|
||||
deps/Android/libiconv/include \
|
||||
deps/Android/libiconv/libcharset/include \
|
||||
deps/Android/LuaJIT/src \
|
||||
deps/Android/OpenAL-Soft/include \
|
||||
deps/Android/sqlite \
|
||||
deps/Android/Vorbis/include
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(wildcard ../../../src/client/*.cpp) \
|
||||
$(wildcard ../../../src/client/*/*.cpp) \
|
||||
$(wildcard ../../../src/content/*.cpp) \
|
||||
../../../src/database/database.cpp \
|
||||
../../../src/database/database-dummy.cpp \
|
||||
../../../src/database/database-files.cpp \
|
||||
../../../src/database/database-sqlite3.cpp \
|
||||
$(wildcard ../../../src/gui/*.cpp) \
|
||||
$(wildcard ../../../src/irrlicht_changes/*.cpp) \
|
||||
$(wildcard ../../../src/mapgen/*.cpp) \
|
||||
$(wildcard ../../../src/network/*.cpp) \
|
||||
$(wildcard ../../../src/script/*.cpp) \
|
||||
$(wildcard ../../../src/script/*/*.cpp) \
|
||||
$(wildcard ../../../src/server/*.cpp) \
|
||||
$(wildcard ../../../src/threading/*.cpp) \
|
||||
$(wildcard ../../../src/util/*.c) \
|
||||
$(wildcard ../../../src/util/*.cpp) \
|
||||
../../../src/ban.cpp \
|
||||
../../../src/chat.cpp \
|
||||
../../../src/clientiface.cpp \
|
||||
../../../src/collision.cpp \
|
||||
../../../src/content_mapnode.cpp \
|
||||
../../../src/content_nodemeta.cpp \
|
||||
../../../src/convert_json.cpp \
|
||||
../../../src/craftdef.cpp \
|
||||
../../../src/debug.cpp \
|
||||
../../../src/defaultsettings.cpp \
|
||||
../../../src/emerge.cpp \
|
||||
../../../src/environment.cpp \
|
||||
../../../src/face_position_cache.cpp \
|
||||
../../../src/filesys.cpp \
|
||||
../../../src/gettext.cpp \
|
||||
../../../src/httpfetch.cpp \
|
||||
../../../src/hud.cpp \
|
||||
../../../src/inventory.cpp \
|
||||
../../../src/inventorymanager.cpp \
|
||||
../../../src/itemdef.cpp \
|
||||
../../../src/itemstackmetadata.cpp \
|
||||
../../../src/light.cpp \
|
||||
../../../src/log.cpp \
|
||||
../../../src/main.cpp \
|
||||
../../../src/map.cpp \
|
||||
../../../src/map_settings_manager.cpp \
|
||||
../../../src/mapblock.cpp \
|
||||
../../../src/mapnode.cpp \
|
||||
../../../src/mapsector.cpp \
|
||||
../../../src/metadata.cpp \
|
||||
../../../src/modchannels.cpp \
|
||||
../../../src/nameidmapping.cpp \
|
||||
../../../src/nodedef.cpp \
|
||||
../../../src/nodemetadata.cpp \
|
||||
../../../src/nodetimer.cpp \
|
||||
../../../src/noise.cpp \
|
||||
../../../src/objdef.cpp \
|
||||
../../../src/object_properties.cpp \
|
||||
../../../src/particles.cpp \
|
||||
../../../src/pathfinder.cpp \
|
||||
../../../src/player.cpp \
|
||||
../../../src/porting.cpp \
|
||||
../../../src/porting_android.cpp \
|
||||
../../../src/profiler.cpp \
|
||||
../../../src/raycast.cpp \
|
||||
../../../src/reflowscan.cpp \
|
||||
../../../src/remoteplayer.cpp \
|
||||
../../../src/rollback.cpp \
|
||||
../../../src/rollback_interface.cpp \
|
||||
../../../src/serialization.cpp \
|
||||
../../../src/server.cpp \
|
||||
../../../src/serverenvironment.cpp \
|
||||
../../../src/serverlist.cpp \
|
||||
../../../src/settings.cpp \
|
||||
../../../src/staticobject.cpp \
|
||||
../../../src/texture_override.cpp \
|
||||
../../../src/tileanimation.cpp \
|
||||
../../../src/tool.cpp \
|
||||
../../../src/translation.cpp \
|
||||
../../../src/version.cpp \
|
||||
../../../src/voxel.cpp \
|
||||
../../../src/voxelalgorithms.cpp
|
||||
|
||||
# LevelDB backend is disabled
|
||||
# ../../../src/database/database-leveldb.cpp
|
||||
|
||||
# GMP
|
||||
LOCAL_SRC_FILES += ../../../lib/gmp/mini-gmp.c
|
||||
|
||||
# JSONCPP
|
||||
LOCAL_SRC_FILES += ../../../lib/jsoncpp/jsoncpp.cpp
|
||||
|
||||
# iconv
|
||||
LOCAL_SRC_FILES += \
|
||||
deps/Android/libiconv/lib/iconv.c \
|
||||
deps/Android/libiconv/libcharset/lib/localcharset.c
|
||||
|
||||
# SQLite3
|
||||
LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c
|
||||
|
||||
LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT android_native_app_glue $(PROFILER_LIBS) #LevelDB
|
||||
|
||||
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
ifdef GPROF
|
||||
$(call import-module,android-ndk-profiler)
|
||||
endif
|
||||
$(call import-module,android/native_app_glue)
|
@ -1,16 +1,10 @@
|
||||
|
||||
core.log("info", "Initializing Asynchronous environment")
|
||||
|
||||
function core.job_processor(serialized_func, serialized_param)
|
||||
local func = loadstring(serialized_func)
|
||||
function core.job_processor(func, serialized_param)
|
||||
local param = core.deserialize(serialized_param)
|
||||
local retval = nil
|
||||
|
||||
if type(func) == "function" then
|
||||
retval = core.serialize(func(param))
|
||||
else
|
||||
core.log("error", "ASYNC WORKER: Unable to deserialize function")
|
||||
end
|
||||
local retval = core.serialize(func(param))
|
||||
|
||||
return retval or core.serialize(nil)
|
||||
end
|
||||
|
@ -1,8 +1,8 @@
|
||||
local death_formspec = ""
|
||||
.. "size[11,5.5]"
|
||||
.. "bgcolor[#320000b4;true]"
|
||||
.. "label[4.85,1.35;" .. "You died" .. "]"
|
||||
.. "button_exit[2,3;3,0.5;btn_respawn;" .. "Respawn" .. "]"
|
||||
.. "label[4.85,1.35;" .. fgettext("You died") .. "]"
|
||||
.. "button_exit[2,3;3,0.5;btn_respawn;" .. fgettext("Respawn") .. "]"
|
||||
.. "button_exit[6,3;3,0.5;btn_ghost_mode;" .. "Ghost Mode" .. "]"
|
||||
.. "set_focus[btn_respawn;true]"
|
||||
|
||||
|
@ -209,14 +209,7 @@ end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function math.hypot(x, y)
|
||||
local t
|
||||
x = math.abs(x)
|
||||
y = math.abs(y)
|
||||
t = math.min(x, y)
|
||||
x = math.max(x, y)
|
||||
if x == 0 then return 0 end
|
||||
t = t / x
|
||||
return x * math.sqrt(1 + t * t)
|
||||
return math.sqrt(x * x + y * y)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -432,21 +425,19 @@ function core.string_to_pos(value)
|
||||
return nil
|
||||
end
|
||||
|
||||
local p = {}
|
||||
p.x, p.y, p.z = string.match(value, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
if p.x and p.y and p.z then
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
return p
|
||||
local x, y, z = string.match(value, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
if x and y and z then
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
z = tonumber(z)
|
||||
return vector.new(x, y, z)
|
||||
end
|
||||
p = {}
|
||||
p.x, p.y, p.z = string.match(value, "^%( *([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) *%)$")
|
||||
if p.x and p.y and p.z then
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
return p
|
||||
x, y, z = string.match(value, "^%( *([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) *%)$")
|
||||
if x and y and z then
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
z = tonumber(z)
|
||||
return vector.new(x, y, z)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
@ -1,4 +1,5 @@
|
||||
_G.core = {}
|
||||
dofile("builtin/common/vector.lua")
|
||||
dofile("builtin/common/misc_helpers.lua")
|
||||
|
||||
describe("string", function()
|
||||
@ -55,8 +56,8 @@ end)
|
||||
|
||||
describe("pos", function()
|
||||
it("from string", function()
|
||||
assert.same({ x = 10, y = 5.1, z = -2}, core.string_to_pos("10.0, 5.1, -2"))
|
||||
assert.same({ x = 10, y = 5.1, z = -2}, core.string_to_pos("( 10.0, 5.1, -2)"))
|
||||
assert.equal(vector.new(10, 5.1, -2), core.string_to_pos("10.0, 5.1, -2"))
|
||||
assert.equal(vector.new(10, 5.1, -2), core.string_to_pos("( 10.0, 5.1, -2)"))
|
||||
assert.is_nil(core.string_to_pos("asd, 5, -2)"))
|
||||
end)
|
||||
|
||||
|
@ -3,6 +3,7 @@ _G.core = {}
|
||||
_G.setfenv = require 'busted.compatibility'.setfenv
|
||||
|
||||
dofile("builtin/common/serialize.lua")
|
||||
dofile("builtin/common/vector.lua")
|
||||
|
||||
describe("serialize", function()
|
||||
it("works", function()
|
||||
@ -53,4 +54,16 @@ describe("serialize", function()
|
||||
assert.is_nil(test_out.func)
|
||||
assert.equals(test_out.foo, "bar")
|
||||
end)
|
||||
|
||||
it("vectors work", function()
|
||||
local v = vector.new(1, 2, 3)
|
||||
assert.same({{x = 1, y = 2, z = 3}}, core.deserialize(core.serialize({v})))
|
||||
assert.same({x = 1, y = 2, z = 3}, core.deserialize(core.serialize(v)))
|
||||
|
||||
-- abuse
|
||||
v = vector.new(1, 2, 3)
|
||||
v.a = "bla"
|
||||
assert.same({x = 1, y = 2, z = 3, a = "bla"},
|
||||
core.deserialize(core.serialize(v)))
|
||||
end)
|
||||
end)
|
||||
|
@ -4,14 +4,20 @@ dofile("builtin/common/vector.lua")
|
||||
describe("vector", function()
|
||||
describe("new()", function()
|
||||
it("constructs", function()
|
||||
assert.same({ x = 0, y = 0, z = 0 }, vector.new())
|
||||
assert.same({ x = 1, y = 2, z = 3 }, vector.new(1, 2, 3))
|
||||
assert.same({ x = 3, y = 2, z = 1 }, vector.new({ x = 3, y = 2, z = 1 }))
|
||||
assert.same({x = 0, y = 0, z = 0}, vector.new())
|
||||
assert.same({x = 1, y = 2, z = 3}, vector.new(1, 2, 3))
|
||||
assert.same({x = 3, y = 2, z = 1}, vector.new({x = 3, y = 2, z = 1}))
|
||||
|
||||
assert.is_true(vector.check(vector.new()))
|
||||
assert.is_true(vector.check(vector.new(1, 2, 3)))
|
||||
assert.is_true(vector.check(vector.new({x = 3, y = 2, z = 1})))
|
||||
|
||||
local input = vector.new({ x = 3, y = 2, z = 1 })
|
||||
local output = vector.new(input)
|
||||
assert.same(input, output)
|
||||
assert.are_not.equal(input, output)
|
||||
assert.equal(input, output)
|
||||
assert.is_false(rawequal(input, output))
|
||||
assert.equal(input, input:new())
|
||||
end)
|
||||
|
||||
it("throws on invalid input", function()
|
||||
@ -25,32 +31,271 @@ describe("vector", function()
|
||||
end)
|
||||
end)
|
||||
|
||||
it("equal()", function()
|
||||
local function assertE(a, b)
|
||||
assert.is_true(vector.equals(a, b))
|
||||
end
|
||||
local function assertNE(a, b)
|
||||
assert.is_false(vector.equals(a, b))
|
||||
end
|
||||
|
||||
assertE({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
||||
assertE({x = -1, y = 0, z = 1}, {x = -1, y = 0, z = 1})
|
||||
local a = { x = 2, y = 4, z = -10 }
|
||||
assertE(a, a)
|
||||
assertNE({x = -1, y = 0, z = 1}, a)
|
||||
it("zero()", function()
|
||||
assert.same({x = 0, y = 0, z = 0}, vector.zero())
|
||||
assert.same(vector.new(), vector.zero())
|
||||
assert.equal(vector.new(), vector.zero())
|
||||
assert.is_true(vector.check(vector.zero()))
|
||||
end)
|
||||
|
||||
it("add()", function()
|
||||
assert.same({ x = 2, y = 4, z = 6 }, vector.add(vector.new(1, 2, 3), { x = 1, y = 2, z = 3 }))
|
||||
it("copy()", function()
|
||||
local v = vector.new(1, 2, 3)
|
||||
assert.same(v, vector.copy(v))
|
||||
assert.same(vector.new(v), vector.copy(v))
|
||||
assert.equal(vector.new(v), vector.copy(v))
|
||||
assert.is_true(vector.check(vector.copy(v)))
|
||||
end)
|
||||
|
||||
it("indexes", function()
|
||||
local some_vector = vector.new(24, 42, 13)
|
||||
assert.equal(24, some_vector[1])
|
||||
assert.equal(24, some_vector.x)
|
||||
assert.equal(42, some_vector[2])
|
||||
assert.equal(42, some_vector.y)
|
||||
assert.equal(13, some_vector[3])
|
||||
assert.equal(13, some_vector.z)
|
||||
|
||||
some_vector[1] = 100
|
||||
assert.equal(100, some_vector.x)
|
||||
some_vector.x = 101
|
||||
assert.equal(101, some_vector[1])
|
||||
|
||||
some_vector[2] = 100
|
||||
assert.equal(100, some_vector.y)
|
||||
some_vector.y = 102
|
||||
assert.equal(102, some_vector[2])
|
||||
|
||||
some_vector[3] = 100
|
||||
assert.equal(100, some_vector.z)
|
||||
some_vector.z = 103
|
||||
assert.equal(103, some_vector[3])
|
||||
end)
|
||||
|
||||
it("direction()", function()
|
||||
local a = vector.new(1, 0, 0)
|
||||
local b = vector.new(1, 42, 0)
|
||||
assert.equal(vector.new(0, 1, 0), vector.direction(a, b))
|
||||
assert.equal(vector.new(0, 1, 0), a:direction(b))
|
||||
end)
|
||||
|
||||
it("distance()", function()
|
||||
local a = vector.new(1, 0, 0)
|
||||
local b = vector.new(3, 42, 9)
|
||||
assert.is_true(math.abs(43 - vector.distance(a, b)) < 1.0e-12)
|
||||
assert.is_true(math.abs(43 - a:distance(b)) < 1.0e-12)
|
||||
assert.equal(0, vector.distance(a, a))
|
||||
assert.equal(0, b:distance(b))
|
||||
end)
|
||||
|
||||
it("length()", function()
|
||||
local a = vector.new(0, 0, -23)
|
||||
assert.equal(0, vector.length(vector.new()))
|
||||
assert.equal(23, vector.length(a))
|
||||
assert.equal(23, a:length())
|
||||
end)
|
||||
|
||||
it("normalize()", function()
|
||||
local a = vector.new(0, 0, -23)
|
||||
assert.equal(vector.new(0, 0, -1), vector.normalize(a))
|
||||
assert.equal(vector.new(0, 0, -1), a:normalize())
|
||||
assert.equal(vector.new(), vector.normalize(vector.new()))
|
||||
end)
|
||||
|
||||
it("floor()", function()
|
||||
local a = vector.new(0.1, 0.9, -0.5)
|
||||
assert.equal(vector.new(0, 0, -1), vector.floor(a))
|
||||
assert.equal(vector.new(0, 0, -1), a:floor())
|
||||
end)
|
||||
|
||||
it("round()", function()
|
||||
local a = vector.new(0.1, 0.9, -0.5)
|
||||
assert.equal(vector.new(0, 1, -1), vector.round(a))
|
||||
assert.equal(vector.new(0, 1, -1), a:round())
|
||||
end)
|
||||
|
||||
it("apply()", function()
|
||||
local i = 0
|
||||
local f = function(x)
|
||||
i = i + 1
|
||||
return x + i
|
||||
end
|
||||
local a = vector.new(0.1, 0.9, -0.5)
|
||||
assert.equal(vector.new(1, 1, 0), vector.apply(a, math.ceil))
|
||||
assert.equal(vector.new(1, 1, 0), a:apply(math.ceil))
|
||||
assert.equal(vector.new(0.1, 0.9, 0.5), vector.apply(a, math.abs))
|
||||
assert.equal(vector.new(0.1, 0.9, 0.5), a:apply(math.abs))
|
||||
assert.equal(vector.new(1.1, 2.9, 2.5), vector.apply(a, f))
|
||||
assert.equal(vector.new(4.1, 5.9, 5.5), a:apply(f))
|
||||
end)
|
||||
|
||||
it("equals()", function()
|
||||
local function assertE(a, b)
|
||||
assert.is_true(vector.equals(a, b))
|
||||
end
|
||||
local function assertNE(a, b)
|
||||
assert.is_false(vector.equals(a, b))
|
||||
end
|
||||
|
||||
assertE({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
||||
assertE({x = -1, y = 0, z = 1}, {x = -1, y = 0, z = 1})
|
||||
assertE({x = -1, y = 0, z = 1}, vector.new(-1, 0, 1))
|
||||
local a = {x = 2, y = 4, z = -10}
|
||||
assertE(a, a)
|
||||
assertNE({x = -1, y = 0, z = 1}, a)
|
||||
|
||||
assert.equal(vector.new(1, 2, 3), vector.new(1, 2, 3))
|
||||
assert.is_true(vector.new(1, 2, 3):equals(vector.new(1, 2, 3)))
|
||||
assert.not_equal(vector.new(1, 2, 3), vector.new(1, 2, 4))
|
||||
assert.is_true(vector.new(1, 2, 3) == vector.new(1, 2, 3))
|
||||
assert.is_false(vector.new(1, 2, 3) == vector.new(1, 3, 3))
|
||||
end)
|
||||
|
||||
it("metatable is same", function()
|
||||
local a = vector.new()
|
||||
local b = vector.new(1, 2, 3)
|
||||
|
||||
assert.equal(true, vector.check(a))
|
||||
assert.equal(true, vector.check(b))
|
||||
|
||||
assert.equal(vector.metatable, getmetatable(a))
|
||||
assert.equal(vector.metatable, getmetatable(b))
|
||||
assert.equal(vector.metatable, a.metatable)
|
||||
end)
|
||||
|
||||
it("sort()", function()
|
||||
local a = vector.new(1, 2, 3)
|
||||
local b = vector.new(0.5, 232, -2)
|
||||
local sorted = {vector.new(0.5, 2, -2), vector.new(1, 232, 3)}
|
||||
assert.same(sorted, {vector.sort(a, b)})
|
||||
assert.same(sorted, {a:sort(b)})
|
||||
end)
|
||||
|
||||
it("angle()", function()
|
||||
assert.equal(math.pi, vector.angle(vector.new(-1, -2, -3), vector.new(1, 2, 3)))
|
||||
assert.equal(math.pi/2, vector.new(0, 1, 0):angle(vector.new(1, 0, 0)))
|
||||
end)
|
||||
|
||||
it("dot()", function()
|
||||
assert.equal(-14, vector.dot(vector.new(-1, -2, -3), vector.new(1, 2, 3)))
|
||||
assert.equal(0, vector.new():dot(vector.new(1, 2, 3)))
|
||||
end)
|
||||
|
||||
it("cross()", function()
|
||||
local a = vector.new(-1, -2, 0)
|
||||
local b = vector.new(1, 2, 3)
|
||||
assert.equal(vector.new(-6, 3, 0), vector.cross(a, b))
|
||||
assert.equal(vector.new(-6, 3, 0), a:cross(b))
|
||||
end)
|
||||
|
||||
it("offset()", function()
|
||||
assert.same({ x = 41, y = 52, z = 63 }, vector.offset(vector.new(1, 2, 3), 40, 50, 60))
|
||||
assert.same({x = 41, y = 52, z = 63}, vector.offset(vector.new(1, 2, 3), 40, 50, 60))
|
||||
assert.equal(vector.new(41, 52, 63), vector.offset(vector.new(1, 2, 3), 40, 50, 60))
|
||||
assert.equal(vector.new(41, 52, 63), vector.new(1, 2, 3):offset(40, 50, 60))
|
||||
end)
|
||||
|
||||
it("is()", function()
|
||||
local some_table1 = {foo = 13, [42] = 1, "bar", 2}
|
||||
local some_table2 = {1, 2, 3}
|
||||
local some_table3 = {x = 1, 2, 3}
|
||||
local some_table4 = {1, 2, z = 3}
|
||||
local old = {x = 1, y = 2, z = 3}
|
||||
local real = vector.new(1, 2, 3)
|
||||
|
||||
assert.is_false(vector.check(nil))
|
||||
assert.is_false(vector.check(1))
|
||||
assert.is_false(vector.check(true))
|
||||
assert.is_false(vector.check("foo"))
|
||||
assert.is_false(vector.check(some_table1))
|
||||
assert.is_false(vector.check(some_table2))
|
||||
assert.is_false(vector.check(some_table3))
|
||||
assert.is_false(vector.check(some_table4))
|
||||
assert.is_false(vector.check(old))
|
||||
assert.is_true(vector.check(real))
|
||||
assert.is_true(real:check())
|
||||
end)
|
||||
|
||||
it("global pairs", function()
|
||||
local out = {}
|
||||
local vec = vector.new(10, 20, 30)
|
||||
for k, v in pairs(vec) do
|
||||
out[k] = v
|
||||
end
|
||||
assert.same({x = 10, y = 20, z = 30}, out)
|
||||
end)
|
||||
|
||||
it("abusing works", function()
|
||||
local v = vector.new(1, 2, 3)
|
||||
v.a = 1
|
||||
assert.equal(1, v.a)
|
||||
|
||||
local a_is_there = false
|
||||
for key, value in pairs(v) do
|
||||
if key == "a" then
|
||||
a_is_there = true
|
||||
assert.equal(value, 1)
|
||||
break
|
||||
end
|
||||
end
|
||||
assert.is_true(a_is_there)
|
||||
end)
|
||||
|
||||
it("add()", function()
|
||||
local a = vector.new(1, 2, 3)
|
||||
local b = vector.new(1, 4, 3)
|
||||
local c = vector.new(2, 6, 6)
|
||||
assert.equal(c, vector.add(a, {x = 1, y = 4, z = 3}))
|
||||
assert.equal(c, vector.add(a, b))
|
||||
assert.equal(c, a:add(b))
|
||||
assert.equal(c, a + b)
|
||||
assert.equal(c, b + a)
|
||||
end)
|
||||
|
||||
it("subtract()", function()
|
||||
local a = vector.new(1, 2, 3)
|
||||
local b = vector.new(2, 4, 3)
|
||||
local c = vector.new(-1, -2, 0)
|
||||
assert.equal(c, vector.subtract(a, {x = 2, y = 4, z = 3}))
|
||||
assert.equal(c, vector.subtract(a, b))
|
||||
assert.equal(c, a:subtract(b))
|
||||
assert.equal(c, a - b)
|
||||
assert.equal(c, -b + a)
|
||||
end)
|
||||
|
||||
it("multiply()", function()
|
||||
local a = vector.new(1, 2, 3)
|
||||
local b = vector.new(2, 4, 3)
|
||||
local c = vector.new(2, 8, 9)
|
||||
local s = 2
|
||||
local d = vector.new(2, 4, 6)
|
||||
assert.equal(c, vector.multiply(a, {x = 2, y = 4, z = 3}))
|
||||
assert.equal(c, vector.multiply(a, b))
|
||||
assert.equal(d, vector.multiply(a, s))
|
||||
assert.equal(d, a:multiply(s))
|
||||
assert.equal(d, a * s)
|
||||
assert.equal(d, s * a)
|
||||
assert.equal(-a, -1 * a)
|
||||
end)
|
||||
|
||||
it("divide()", function()
|
||||
local a = vector.new(1, 2, 3)
|
||||
local b = vector.new(2, 4, 3)
|
||||
local c = vector.new(0.5, 0.5, 1)
|
||||
local s = 2
|
||||
local d = vector.new(0.5, 1, 1.5)
|
||||
assert.equal(c, vector.divide(a, {x = 2, y = 4, z = 3}))
|
||||
assert.equal(c, vector.divide(a, b))
|
||||
assert.equal(d, vector.divide(a, s))
|
||||
assert.equal(d, a:divide(s))
|
||||
assert.equal(d, a / s)
|
||||
assert.equal(d, 1/s * a)
|
||||
assert.equal(-a, a / -1)
|
||||
end)
|
||||
|
||||
it("to_string()", function()
|
||||
local v = vector.new(1, 2, 3.14)
|
||||
assert.same("(1, 2, 3.14)", vector.to_string(v))
|
||||
assert.same("(1, 2, 3.14)", v:to_string())
|
||||
assert.same("(1, 2, 3.14)", tostring(v))
|
||||
end)
|
||||
|
||||
it("from_string()", function()
|
||||
|
@ -1,15 +1,55 @@
|
||||
--[[
|
||||
Vector helpers
|
||||
Note: The vector.*-functions must be able to accept old vectors that had no metatables
|
||||
]]
|
||||
|
||||
-- localize functions
|
||||
local setmetatable = setmetatable
|
||||
|
||||
vector = {}
|
||||
|
||||
local metatable = {}
|
||||
vector.metatable = metatable
|
||||
|
||||
local xyz = {"x", "y", "z"}
|
||||
|
||||
-- only called when rawget(v, key) returns nil
|
||||
function metatable.__index(v, key)
|
||||
return rawget(v, xyz[key]) or vector[key]
|
||||
end
|
||||
|
||||
-- only called when rawget(v, key) returns nil
|
||||
function metatable.__newindex(v, key, value)
|
||||
rawset(v, xyz[key] or key, value)
|
||||
end
|
||||
|
||||
-- constructors
|
||||
|
||||
local function fast_new(x, y, z)
|
||||
return setmetatable({x = x, y = y, z = z}, metatable)
|
||||
end
|
||||
|
||||
function vector.new(a, b, c)
|
||||
if type(a) == "table" then
|
||||
assert(a.x and a.y and a.z, "Invalid vector passed to vector.new()")
|
||||
return {x=a.x, y=a.y, z=a.z}
|
||||
elseif a then
|
||||
assert(b and c, "Invalid arguments for vector.new()")
|
||||
return {x=a, y=b, z=c}
|
||||
if a and b and c then
|
||||
return fast_new(a, b, c)
|
||||
end
|
||||
return {x=0, y=0, z=0}
|
||||
|
||||
-- deprecated, use vector.copy and vector.zero directly
|
||||
if type(a) == "table" then
|
||||
return vector.copy(a)
|
||||
else
|
||||
assert(not a, "Invalid arguments for vector.new()")
|
||||
return vector.zero()
|
||||
end
|
||||
end
|
||||
|
||||
function vector.zero()
|
||||
return fast_new(0, 0, 0)
|
||||
end
|
||||
|
||||
function vector.copy(v)
|
||||
assert(v.x and v.y and v.z, "Invalid vector passed to vector.copy()")
|
||||
return fast_new(v.x, v.y, v.z)
|
||||
end
|
||||
|
||||
function vector.from_string(s, init)
|
||||
@ -27,63 +67,60 @@ end
|
||||
function vector.to_string(v)
|
||||
return string.format("(%g, %g, %g)", v.x, v.y, v.z)
|
||||
end
|
||||
metatable.__tostring = vector.to_string
|
||||
|
||||
function vector.equals(a, b)
|
||||
return a.x == b.x and
|
||||
a.y == b.y and
|
||||
a.z == b.z
|
||||
end
|
||||
metatable.__eq = vector.equals
|
||||
|
||||
-- unary operations
|
||||
|
||||
function vector.length(v)
|
||||
return math.hypot(v.x, math.hypot(v.y, v.z))
|
||||
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
|
||||
end
|
||||
-- Note: we can not use __len because it is already used for primitive table length
|
||||
|
||||
function vector.normalize(v)
|
||||
local len = vector.length(v)
|
||||
if len == 0 then
|
||||
return {x=0, y=0, z=0}
|
||||
return fast_new(0, 0, 0)
|
||||
else
|
||||
return vector.divide(v, len)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.floor(v)
|
||||
return {
|
||||
x = math.floor(v.x),
|
||||
y = math.floor(v.y),
|
||||
z = math.floor(v.z)
|
||||
}
|
||||
return vector.apply(v, math.floor)
|
||||
end
|
||||
|
||||
function vector.round(v)
|
||||
return {
|
||||
x = math.round(v.x),
|
||||
y = math.round(v.y),
|
||||
z = math.round(v.z)
|
||||
}
|
||||
return fast_new(
|
||||
math.round(v.x),
|
||||
math.round(v.y),
|
||||
math.round(v.z)
|
||||
)
|
||||
end
|
||||
|
||||
function vector.apply(v, func)
|
||||
return {
|
||||
x = func(v.x),
|
||||
y = func(v.y),
|
||||
z = func(v.z)
|
||||
}
|
||||
return fast_new(
|
||||
func(v.x),
|
||||
func(v.y),
|
||||
func(v.z)
|
||||
)
|
||||
end
|
||||
|
||||
function vector.distance(a, b)
|
||||
local x = a.x - b.x
|
||||
local y = a.y - b.y
|
||||
local z = a.z - b.z
|
||||
return math.hypot(x, math.hypot(y, z))
|
||||
return math.sqrt(x * x + y * y + z * z)
|
||||
end
|
||||
|
||||
function vector.direction(pos1, pos2)
|
||||
return vector.normalize({
|
||||
x = pos2.x - pos1.x,
|
||||
y = pos2.y - pos1.y,
|
||||
z = pos2.z - pos1.z
|
||||
})
|
||||
return vector.subtract(pos2, pos1):normalize()
|
||||
end
|
||||
|
||||
function vector.angle(a, b)
|
||||
@ -98,70 +135,137 @@ function vector.dot(a, b)
|
||||
end
|
||||
|
||||
function vector.cross(a, b)
|
||||
return {
|
||||
x = a.y * b.z - a.z * b.y,
|
||||
y = a.z * b.x - a.x * b.z,
|
||||
z = a.x * b.y - a.y * b.x
|
||||
}
|
||||
return fast_new(
|
||||
a.y * b.z - a.z * b.y,
|
||||
a.z * b.x - a.x * b.z,
|
||||
a.x * b.y - a.y * b.x
|
||||
)
|
||||
end
|
||||
|
||||
function metatable.__unm(v)
|
||||
return fast_new(-v.x, -v.y, -v.z)
|
||||
end
|
||||
|
||||
-- add, sub, mul, div operations
|
||||
|
||||
function vector.add(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x + b.x,
|
||||
y = a.y + b.y,
|
||||
z = a.z + b.z}
|
||||
return fast_new(
|
||||
a.x + b.x,
|
||||
a.y + b.y,
|
||||
a.z + b.z
|
||||
)
|
||||
else
|
||||
return {x = a.x + b,
|
||||
y = a.y + b,
|
||||
z = a.z + b}
|
||||
return fast_new(
|
||||
a.x + b,
|
||||
a.y + b,
|
||||
a.z + b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__add(a, b)
|
||||
return fast_new(
|
||||
a.x + b.x,
|
||||
a.y + b.y,
|
||||
a.z + b.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.subtract(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x - b.x,
|
||||
y = a.y - b.y,
|
||||
z = a.z - b.z}
|
||||
return fast_new(
|
||||
a.x - b.x,
|
||||
a.y - b.y,
|
||||
a.z - b.z
|
||||
)
|
||||
else
|
||||
return {x = a.x - b,
|
||||
y = a.y - b,
|
||||
z = a.z - b}
|
||||
return fast_new(
|
||||
a.x - b,
|
||||
a.y - b,
|
||||
a.z - b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__sub(a, b)
|
||||
return fast_new(
|
||||
a.x - b.x,
|
||||
a.y - b.y,
|
||||
a.z - b.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.multiply(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x * b.x,
|
||||
y = a.y * b.y,
|
||||
z = a.z * b.z}
|
||||
return fast_new(
|
||||
a.x * b.x,
|
||||
a.y * b.y,
|
||||
a.z * b.z
|
||||
)
|
||||
else
|
||||
return {x = a.x * b,
|
||||
y = a.y * b,
|
||||
z = a.z * b}
|
||||
return fast_new(
|
||||
a.x * b,
|
||||
a.y * b,
|
||||
a.z * b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__mul(a, b)
|
||||
if type(a) == "table" then
|
||||
return fast_new(
|
||||
a.x * b,
|
||||
a.y * b,
|
||||
a.z * b
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a * b.x,
|
||||
a * b.y,
|
||||
a * b.z
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.divide(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x / b.x,
|
||||
y = a.y / b.y,
|
||||
z = a.z / b.z}
|
||||
return fast_new(
|
||||
a.x / b.x,
|
||||
a.y / b.y,
|
||||
a.z / b.z
|
||||
)
|
||||
else
|
||||
return {x = a.x / b,
|
||||
y = a.y / b,
|
||||
z = a.z / b}
|
||||
return fast_new(
|
||||
a.x / b,
|
||||
a.y / b,
|
||||
a.z / b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__div(a, b)
|
||||
-- scalar/vector makes no sense
|
||||
return fast_new(
|
||||
a.x / b,
|
||||
a.y / b,
|
||||
a.z / b
|
||||
)
|
||||
end
|
||||
|
||||
-- misc stuff
|
||||
|
||||
function vector.offset(v, x, y, z)
|
||||
return {x = v.x + x,
|
||||
y = v.y + y,
|
||||
z = v.z + z}
|
||||
return fast_new(
|
||||
v.x + x,
|
||||
v.y + y,
|
||||
v.z + z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.sort(a, b)
|
||||
return {x = math.min(a.x, b.x), y = math.min(a.y, b.y), z = math.min(a.z, b.z)},
|
||||
{x = math.max(a.x, b.x), y = math.max(a.y, b.y), z = math.max(a.z, b.z)}
|
||||
return fast_new(math.min(a.x, b.x), math.min(a.y, b.y), math.min(a.z, b.z)),
|
||||
fast_new(math.max(a.x, b.x), math.max(a.y, b.y), math.max(a.z, b.z))
|
||||
end
|
||||
|
||||
function vector.check(v)
|
||||
return getmetatable(v) == metatable
|
||||
end
|
||||
|
||||
local function sin(x)
|
||||
@ -229,7 +333,7 @@ end
|
||||
|
||||
function vector.dir_to_rotation(forward, up)
|
||||
forward = vector.normalize(forward)
|
||||
local rot = {x = math.asin(forward.y), y = -math.atan2(forward.x, forward.z), z = 0}
|
||||
local rot = vector.new(math.asin(forward.y), -math.atan2(forward.x, forward.z), 0)
|
||||
if not up then
|
||||
return rot
|
||||
end
|
||||
@ -237,7 +341,7 @@ function vector.dir_to_rotation(forward, up)
|
||||
"Invalid vectors passed to vector.dir_to_rotation().")
|
||||
up = vector.normalize(up)
|
||||
-- Calculate vector pointing up with roll = 0, just based on forward vector.
|
||||
local forwup = vector.rotate({x = 0, y = 1, z = 0}, rot)
|
||||
local forwup = vector.rotate(vector.new(0, 1, 0), rot)
|
||||
-- 'forwup' and 'up' are now in a plane with 'forward' as normal.
|
||||
-- The angle between them is the absolute of the roll value we're looking for.
|
||||
rot.z = vector.angle(forwup, up)
|
||||
|
@ -87,6 +87,10 @@ core.builtin_auth_handler = {
|
||||
core.settings:get("default_password")))
|
||||
end
|
||||
|
||||
auth_entry.privileges = privileges
|
||||
|
||||
core_auth.save(auth_entry)
|
||||
|
||||
-- Run grant callbacks
|
||||
for priv, _ in pairs(privileges) do
|
||||
if not auth_entry.privileges[priv] then
|
||||
@ -100,9 +104,6 @@ core.builtin_auth_handler = {
|
||||
core.run_priv_callbacks(name, priv, nil, "revoke")
|
||||
end
|
||||
end
|
||||
|
||||
auth_entry.privileges = privileges
|
||||
core_auth.save(auth_entry)
|
||||
core.notify_authentication_modified(name)
|
||||
end,
|
||||
reload = function()
|
||||
|
@ -212,9 +212,14 @@ core.register_chatcommand("haspriv", {
|
||||
table.insert(players_with_priv, player_name)
|
||||
end
|
||||
end
|
||||
return true, S("Players online with the \"@1\" privilege: @2",
|
||||
param,
|
||||
table.concat(players_with_priv, ", "))
|
||||
if #players_with_priv == 0 then
|
||||
return true, S("No online player has the \"@1\" privilege.",
|
||||
param)
|
||||
else
|
||||
return true, S("Players online with the \"@1\" privilege: @2",
|
||||
param,
|
||||
table.concat(players_with_priv, ", "))
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
@ -250,11 +255,11 @@ local function handle_grant_command(caller, grantname, grantprivstr)
|
||||
if privs_unknown ~= "" then
|
||||
return false, privs_unknown
|
||||
end
|
||||
core.set_player_privs(grantname, privs)
|
||||
for priv, _ in pairs(grantprivs) do
|
||||
-- call the on_grant callbacks
|
||||
core.run_priv_callbacks(grantname, priv, caller, "grant")
|
||||
end
|
||||
core.set_player_privs(grantname, privs)
|
||||
core.log("action", caller..' granted ('..core.privs_to_string(grantprivs, ', ')..') privileges to '..grantname)
|
||||
if grantname ~= caller then
|
||||
core.chat_send_player(grantname,
|
||||
@ -354,13 +359,13 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
|
||||
end
|
||||
|
||||
local revokecount = 0
|
||||
|
||||
core.set_player_privs(revokename, privs)
|
||||
for priv, _ in pairs(revokeprivs) do
|
||||
-- call the on_revoke callbacks
|
||||
core.run_priv_callbacks(revokename, priv, caller, "revoke")
|
||||
revokecount = revokecount + 1
|
||||
end
|
||||
|
||||
core.set_player_privs(revokename, privs)
|
||||
local new_privs = core.get_player_privs(revokename)
|
||||
|
||||
if revokecount == 0 then
|
||||
@ -499,10 +504,10 @@ core.register_chatcommand("remove_player", {
|
||||
-- pos may be a non-integer position
|
||||
local function find_free_position_near(pos)
|
||||
local tries = {
|
||||
{x=1, y=0, z=0},
|
||||
{x=-1, y=0, z=0},
|
||||
{x=0, y=0, z=1},
|
||||
{x=0, y=0, z=-1},
|
||||
vector.new( 1, 0, 0),
|
||||
vector.new(-1, 0, 0),
|
||||
vector.new( 0, 0, 1),
|
||||
vector.new( 0, 0, -1),
|
||||
}
|
||||
for _, d in ipairs(tries) do
|
||||
local p = vector.add(pos, d)
|
||||
@ -737,7 +742,12 @@ core.register_chatcommand("mods", {
|
||||
description = S("List mods installed on the server"),
|
||||
privs = {},
|
||||
func = function(name, param)
|
||||
return true, table.concat(core.get_modnames(), ", ")
|
||||
local mods = core.get_modnames()
|
||||
if #mods == 0 then
|
||||
return true, S("No mods installed.")
|
||||
else
|
||||
return true, table.concat(core.get_modnames(), ", ")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
@ -1053,24 +1063,58 @@ core.register_chatcommand("days", {
|
||||
end
|
||||
})
|
||||
|
||||
local function parse_shutdown_param(param)
|
||||
local delay, reconnect, message
|
||||
local one, two, three
|
||||
one, two, three = param:match("^(%S+) +(%-r) +(.*)")
|
||||
if one and two and three then
|
||||
-- 3 arguments: delay, reconnect and message
|
||||
return one, two, three
|
||||
end
|
||||
-- 2 arguments
|
||||
one, two = param:match("^(%S+) +(.*)")
|
||||
if one and two then
|
||||
if tonumber(one) then
|
||||
delay = one
|
||||
if two == "-r" then
|
||||
reconnect = two
|
||||
else
|
||||
message = two
|
||||
end
|
||||
elseif one == "-r" then
|
||||
reconnect, message = one, two
|
||||
end
|
||||
return delay, reconnect, message
|
||||
end
|
||||
-- 1 argument
|
||||
one = param:match("(.*)")
|
||||
if tonumber(one) then
|
||||
delay = one
|
||||
elseif one == "-r" then
|
||||
reconnect = one
|
||||
else
|
||||
message = one
|
||||
end
|
||||
return delay, reconnect, message
|
||||
end
|
||||
|
||||
core.register_chatcommand("shutdown", {
|
||||
params = S("[<delay_in_seconds> | -1] [reconnect] [<message>]"),
|
||||
description = S("Shutdown server (-1 cancels a delayed shutdown)"),
|
||||
params = S("[<delay_in_seconds> | -1] [-r] [<message>]"),
|
||||
description = S("Shutdown server (-1 cancels a delayed shutdown, -r allows players to reconnect)"),
|
||||
privs = {server=true},
|
||||
func = function(name, param)
|
||||
local delay, reconnect, message
|
||||
delay, param = param:match("^%s*(%S+)(.*)")
|
||||
if param then
|
||||
reconnect, param = param:match("^%s*(%S+)(.*)")
|
||||
local delay, reconnect, message = parse_shutdown_param(param)
|
||||
local bool_reconnect = reconnect == "-r"
|
||||
if not message then
|
||||
message = ""
|
||||
end
|
||||
message = param and param:match("^%s*(.+)") or ""
|
||||
delay = tonumber(delay) or 0
|
||||
|
||||
if delay == 0 then
|
||||
core.log("action", name .. " shuts down server")
|
||||
core.chat_send_all("*** "..S("Server shutting down (operator request)."))
|
||||
end
|
||||
core.request_shutdown(message:trim(), core.is_yes(reconnect), delay)
|
||||
core.request_shutdown(message:trim(), bool_reconnect, delay)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
@ -39,7 +39,7 @@ local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
|
||||
core.register_entity(":__builtin:falling_node", {
|
||||
initial_properties = {
|
||||
visual = "item",
|
||||
visual_size = {x = SCALE, y = SCALE, z = SCALE},
|
||||
visual_size = vector.new(SCALE, SCALE, SCALE),
|
||||
textures = {},
|
||||
physical = true,
|
||||
is_visible = false,
|
||||
@ -96,7 +96,7 @@ core.register_entity(":__builtin:falling_node", {
|
||||
local vsize
|
||||
if def.visual_scale then
|
||||
local s = def.visual_scale
|
||||
vsize = {x = s, y = s, z = s}
|
||||
vsize = vector.new(s, s, s)
|
||||
end
|
||||
self.object:set_properties({
|
||||
is_visible = true,
|
||||
@ -111,15 +111,21 @@ core.register_entity(":__builtin:falling_node", {
|
||||
itemstring = core.itemstring_with_palette(itemstring, node.param2)
|
||||
end
|
||||
-- FIXME: solution needed for paramtype2 == "leveled"
|
||||
local vsize
|
||||
if def.visual_scale then
|
||||
local s = def.visual_scale * SCALE
|
||||
vsize = {x = s, y = s, z = s}
|
||||
-- Calculate size of falling node
|
||||
local s = {}
|
||||
s.x = (def.visual_scale or 1) * SCALE
|
||||
s.y = s.x
|
||||
s.z = s.x
|
||||
-- Compensate for wield_scale
|
||||
if def.wield_scale then
|
||||
s.x = s.x / def.wield_scale.x
|
||||
s.y = s.y / def.wield_scale.y
|
||||
s.z = s.z / def.wield_scale.z
|
||||
end
|
||||
self.object:set_properties({
|
||||
is_visible = true,
|
||||
wield_item = itemstring,
|
||||
visual_size = vsize,
|
||||
visual_size = s,
|
||||
glow = def.light_source,
|
||||
})
|
||||
end
|
||||
@ -158,7 +164,8 @@ core.register_entity(":__builtin:falling_node", {
|
||||
if euler then
|
||||
self.object:set_rotation(euler)
|
||||
end
|
||||
elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" or def.drawtype == "signlike") then
|
||||
elseif (def.drawtype ~= "plantlike" and def.drawtype ~= "plantlike_rooted" and
|
||||
(def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" or def.drawtype == "signlike")) then
|
||||
local rot = node.param2 % 8
|
||||
if (def.drawtype == "signlike" and def.paramtype2 ~= "wallmounted" and def.paramtype2 ~= "colorwallmounted") then
|
||||
-- Change rotation to "floor" by default for non-wallmounted paramtype2
|
||||
@ -227,7 +234,7 @@ core.register_entity(":__builtin:falling_node", {
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
self.object:set_acceleration({x = 0, y = -gravity, z = 0})
|
||||
self.object:set_acceleration(vector.new(0, -gravity, 0))
|
||||
|
||||
local ds = core.deserialize(staticdata)
|
||||
if ds and ds.node then
|
||||
@ -303,7 +310,7 @@ core.register_entity(":__builtin:falling_node", {
|
||||
if self.floats then
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
local bcp = vector.round({x = pos.x, y = pos.y - 0.7, z = pos.z})
|
||||
local bcp = pos:offset(0, -0.7, 0):round()
|
||||
local bcn = core.get_node(bcp)
|
||||
|
||||
local bcd = core.registered_nodes[bcn.name]
|
||||
@ -344,13 +351,12 @@ core.register_entity(":__builtin:falling_node", {
|
||||
-- TODO: this hack could be avoided in the future if objects
|
||||
-- could choose who to collide with
|
||||
local vel = self.object:get_velocity()
|
||||
self.object:set_velocity({
|
||||
x = vel.x,
|
||||
y = player_collision.old_velocity.y,
|
||||
z = vel.z
|
||||
})
|
||||
self.object:set_pos(vector.add(self.object:get_pos(),
|
||||
{x = 0, y = -0.5, z = 0}))
|
||||
self.object:set_velocity(vector.new(
|
||||
vel.x,
|
||||
player_collision.old_velocity.y,
|
||||
vel.z
|
||||
))
|
||||
self.object:set_pos(self.object:get_pos():offset(0, -0.5, 0))
|
||||
end
|
||||
return
|
||||
elseif bcn.name == "ignore" then
|
||||
@ -430,7 +436,7 @@ local function drop_attached_node(p)
|
||||
if def and def.preserve_metadata then
|
||||
local oldmeta = core.get_meta(p):to_table().fields
|
||||
-- Copy pos and node because the callback can modify them.
|
||||
local pos_copy = {x=p.x, y=p.y, z=p.z}
|
||||
local pos_copy = vector.new(p)
|
||||
local node_copy = {name=n.name, param1=n.param1, param2=n.param2}
|
||||
local drop_stacks = {}
|
||||
for k, v in pairs(drops) do
|
||||
@ -455,14 +461,14 @@ end
|
||||
|
||||
function builtin_shared.check_attached_node(p, n)
|
||||
local def = core.registered_nodes[n.name]
|
||||
local d = {x = 0, y = 0, z = 0}
|
||||
local d = vector.new()
|
||||
if def.paramtype2 == "wallmounted" or
|
||||
def.paramtype2 == "colorwallmounted" then
|
||||
-- The fallback vector here is in case 'wallmounted to dir' is nil due
|
||||
-- to voxelmanip placing a wallmounted node without resetting a
|
||||
-- pre-existing param2 value that is out-of-range for wallmounted.
|
||||
-- The fallback vector corresponds to param2 = 0.
|
||||
d = core.wallmounted_to_dir(n.param2) or {x = 0, y = 1, z = 0}
|
||||
d = core.wallmounted_to_dir(n.param2) or vector.new(0, 1, 0)
|
||||
else
|
||||
d.y = -1
|
||||
end
|
||||
@ -482,7 +488,7 @@ end
|
||||
function core.check_single_for_falling(p)
|
||||
local n = core.get_node(p)
|
||||
if core.get_item_group(n.name, "falling_node") ~= 0 then
|
||||
local p_bottom = {x = p.x, y = p.y - 1, z = p.z}
|
||||
local p_bottom = vector.offset(p, 0, -1, 0)
|
||||
-- Only spawn falling node if node below is loaded
|
||||
local n_bottom = core.get_node_or_nil(p_bottom)
|
||||
local d_bottom = n_bottom and core.registered_nodes[n_bottom.name]
|
||||
@ -521,17 +527,17 @@ end
|
||||
-- Down first as likely case, but always before self. The same with sides.
|
||||
-- Up must come last, so that things above self will also fall all at once.
|
||||
local check_for_falling_neighbors = {
|
||||
{x = -1, y = -1, z = 0},
|
||||
{x = 1, y = -1, z = 0},
|
||||
{x = 0, y = -1, z = -1},
|
||||
{x = 0, y = -1, z = 1},
|
||||
{x = 0, y = -1, z = 0},
|
||||
{x = -1, y = 0, z = 0},
|
||||
{x = 1, y = 0, z = 0},
|
||||
{x = 0, y = 0, z = 1},
|
||||
{x = 0, y = 0, z = -1},
|
||||
{x = 0, y = 0, z = 0},
|
||||
{x = 0, y = 1, z = 0},
|
||||
vector.new(-1, -1, 0),
|
||||
vector.new( 1, -1, 0),
|
||||
vector.new( 0, -1, -1),
|
||||
vector.new( 0, -1, 1),
|
||||
vector.new( 0, -1, 0),
|
||||
vector.new(-1, 0, 0),
|
||||
vector.new( 1, 0, 0),
|
||||
vector.new( 0, 0, 1),
|
||||
vector.new( 0, 0, -1),
|
||||
vector.new( 0, 0, 0),
|
||||
vector.new( 0, 1, 0),
|
||||
}
|
||||
|
||||
function core.check_for_falling(p)
|
||||
|
@ -20,6 +20,8 @@ core.features = {
|
||||
direct_velocity_on_players = true,
|
||||
use_texture_alpha_string_modes = true,
|
||||
degrotate_240_steps = true,
|
||||
abm_min_max_y = true,
|
||||
dynamic_add_media_table = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
@ -86,12 +86,6 @@ local function read_file(filename)
|
||||
return core.deserialize(t) or {}
|
||||
end
|
||||
|
||||
local function write_file(filename, table)
|
||||
local f = io.open(filename, "w")
|
||||
f:write(core.serialize(table))
|
||||
f:close()
|
||||
end
|
||||
|
||||
blocks_forceloaded = read_file(wpath.."/force_loaded.txt")
|
||||
for _, __ in pairs(blocks_forceloaded) do
|
||||
total_forceloaded = total_forceloaded + 1
|
||||
@ -106,7 +100,8 @@ end)
|
||||
|
||||
-- persists the currently forceloaded blocks to disk
|
||||
local function persist_forceloaded_blocks()
|
||||
write_file(wpath.."/force_loaded.txt", blocks_forceloaded)
|
||||
local data = core.serialize(blocks_forceloaded)
|
||||
core.safe_file_write(wpath.."/force_loaded.txt", data)
|
||||
end
|
||||
|
||||
-- periodical forceload persistence
|
||||
|
@ -7,8 +7,6 @@ local gamepath = scriptpath .. "game".. DIR_DELIM
|
||||
-- not exposed to outer context
|
||||
local builtin_shared = {}
|
||||
|
||||
dofile(commonpath .. "vector.lua")
|
||||
|
||||
dofile(gamepath .. "constants.lua")
|
||||
assert(loadfile(gamepath .. "item.lua"))(builtin_shared)
|
||||
dofile(gamepath .. "register.lua")
|
||||
|
@ -70,12 +70,12 @@ end
|
||||
|
||||
-- Table of possible dirs
|
||||
local facedir_to_dir = {
|
||||
{x= 0, y=0, z= 1},
|
||||
{x= 1, y=0, z= 0},
|
||||
{x= 0, y=0, z=-1},
|
||||
{x=-1, y=0, z= 0},
|
||||
{x= 0, y=-1, z= 0},
|
||||
{x= 0, y=1, z= 0},
|
||||
vector.new( 0, 0, 1),
|
||||
vector.new( 1, 0, 0),
|
||||
vector.new( 0, 0, -1),
|
||||
vector.new(-1, 0, 0),
|
||||
vector.new( 0, -1, 0),
|
||||
vector.new( 0, 1, 0),
|
||||
}
|
||||
-- Mapping from facedir value to index in facedir_to_dir.
|
||||
local facedir_to_dir_map = {
|
||||
@ -114,12 +114,12 @@ end
|
||||
|
||||
-- table of dirs in wallmounted order
|
||||
local wallmounted_to_dir = {
|
||||
[0] = {x = 0, y = 1, z = 0},
|
||||
{x = 0, y = -1, z = 0},
|
||||
{x = 1, y = 0, z = 0},
|
||||
{x = -1, y = 0, z = 0},
|
||||
{x = 0, y = 0, z = 1},
|
||||
{x = 0, y = 0, z = -1},
|
||||
[0] = vector.new( 0, 1, 0),
|
||||
vector.new( 0, -1, 0),
|
||||
vector.new( 1, 0, 0),
|
||||
vector.new(-1, 0, 0),
|
||||
vector.new( 0, 0, 1),
|
||||
vector.new( 0, 0, -1),
|
||||
}
|
||||
function core.wallmounted_to_dir(wallmounted)
|
||||
return wallmounted_to_dir[wallmounted % 8]
|
||||
@ -130,7 +130,7 @@ function core.dir_to_yaw(dir)
|
||||
end
|
||||
|
||||
function core.yaw_to_dir(yaw)
|
||||
return {x = -math.sin(yaw), y = 0, z = math.cos(yaw)}
|
||||
return vector.new(-math.sin(yaw), 0, math.cos(yaw))
|
||||
end
|
||||
|
||||
function core.is_colored_paramtype(ptype)
|
||||
@ -153,6 +153,18 @@ function core.strip_param2_color(param2, paramtype2)
|
||||
return param2
|
||||
end
|
||||
|
||||
local function has_all_groups(tbl, required_groups)
|
||||
if type(required_groups) == "string" then
|
||||
return (tbl[required_groups] or 0) ~= 0
|
||||
end
|
||||
for _, group in ipairs(required_groups) do
|
||||
if (tbl[group] or 0) == 0 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function core.get_node_drops(node, toolname)
|
||||
-- Compatibility, if node is string
|
||||
local nodename = node
|
||||
@ -192,7 +204,7 @@ function core.get_node_drops(node, toolname)
|
||||
if item.rarity ~= nil then
|
||||
good_rarity = item.rarity < 1 or math.random(item.rarity) == 1
|
||||
end
|
||||
if item.tools ~= nil then
|
||||
if item.tools ~= nil or item.tool_groups ~= nil then
|
||||
good_tool = false
|
||||
end
|
||||
if item.tools ~= nil and toolname then
|
||||
@ -207,6 +219,27 @@ function core.get_node_drops(node, toolname)
|
||||
end
|
||||
end
|
||||
end
|
||||
if item.tool_groups ~= nil and toolname then
|
||||
local tooldef = core.registered_items[toolname]
|
||||
if tooldef ~= nil and type(tooldef.groups) == "table" then
|
||||
if type(item.tool_groups) == "string" then
|
||||
-- tool_groups can be a string which specifies the required group
|
||||
good_tool = core.get_item_group(toolname, item.tool_groups) ~= 0
|
||||
else
|
||||
-- tool_groups can be a list of sufficient requirements.
|
||||
-- i.e. if any item in the list can be satisfied then the tool is good
|
||||
assert(type(item.tool_groups) == "table")
|
||||
for _, required_groups in ipairs(item.tool_groups) do
|
||||
-- required_groups can be either a string (a single group),
|
||||
-- or an array of strings where all must be in tooldef.groups
|
||||
good_tool = has_all_groups(tooldef.groups, required_groups)
|
||||
if good_tool then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if good_rarity and good_tool then
|
||||
got_count = got_count + 1
|
||||
for _, add_item in ipairs(item.items) do
|
||||
@ -268,12 +301,12 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
||||
end
|
||||
|
||||
-- Place above pointed node
|
||||
local place_to = {x = above.x, y = above.y, z = above.z}
|
||||
local place_to = vector.new(above)
|
||||
|
||||
-- If node under is buildable_to, place into it instead (eg. snow)
|
||||
if olddef_under.buildable_to then
|
||||
log("info", "node under is buildable to")
|
||||
place_to = {x = under.x, y = under.y, z = under.z}
|
||||
place_to = vector.new(under)
|
||||
end
|
||||
|
||||
if core.is_protected(place_to, playername) then
|
||||
@ -293,22 +326,14 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
||||
newnode.param2 = def.place_param2
|
||||
elseif (def.paramtype2 == "wallmounted" or
|
||||
def.paramtype2 == "colorwallmounted") and not param2 then
|
||||
local dir = {
|
||||
x = under.x - above.x,
|
||||
y = under.y - above.y,
|
||||
z = under.z - above.z
|
||||
}
|
||||
local dir = vector.subtract(under, above)
|
||||
newnode.param2 = core.dir_to_wallmounted(dir)
|
||||
-- Calculate the direction for furnaces and chests and stuff
|
||||
elseif (def.paramtype2 == "facedir" or
|
||||
def.paramtype2 == "colorfacedir") and not param2 then
|
||||
local placer_pos = placer and placer:get_pos()
|
||||
if placer_pos then
|
||||
local dir = {
|
||||
x = above.x - placer_pos.x,
|
||||
y = above.y - placer_pos.y,
|
||||
z = above.z - placer_pos.z
|
||||
}
|
||||
local dir = vector.subtract(above, placer_pos)
|
||||
newnode.param2 = core.dir_to_facedir(dir)
|
||||
log("info", "facedir: " .. newnode.param2)
|
||||
end
|
||||
@ -362,7 +387,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
||||
-- Run callback
|
||||
if def.after_place_node and not prevent_after_place then
|
||||
-- Deepcopy place_to and pointed_thing because callback can modify it
|
||||
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||
local place_to_copy = vector.new(place_to)
|
||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||
if def.after_place_node(place_to_copy, placer, itemstack,
|
||||
pointed_thing_copy) then
|
||||
@ -373,7 +398,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
||||
-- Run script hook
|
||||
for _, callback in ipairs(core.registered_on_placenodes) do
|
||||
-- Deepcopy pos, node and pointed_thing because callback can modify them
|
||||
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||
local place_to_copy = vector.new(place_to)
|
||||
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
|
||||
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
|
||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||
@ -519,11 +544,11 @@ function core.handle_node_drops(pos, drops, digger)
|
||||
for _, dropped_item in pairs(drops) do
|
||||
local left = give_item(dropped_item)
|
||||
if not left:is_empty() then
|
||||
local p = {
|
||||
x = pos.x + math.random()/2-0.25,
|
||||
y = pos.y + math.random()/2-0.25,
|
||||
z = pos.z + math.random()/2-0.25,
|
||||
}
|
||||
local p = vector.offset(pos,
|
||||
math.random()/2-0.25,
|
||||
math.random()/2-0.25,
|
||||
math.random()/2-0.25
|
||||
)
|
||||
core.add_item(p, left)
|
||||
end
|
||||
end
|
||||
@ -582,7 +607,7 @@ function core.node_dig(pos, node, digger)
|
||||
if def and def.preserve_metadata then
|
||||
local oldmeta = core.get_meta(pos):to_table().fields
|
||||
-- Copy pos and node because the callback can modify them.
|
||||
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
|
||||
local pos_copy = vector.new(pos)
|
||||
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
||||
local drop_stacks = {}
|
||||
for k, v in pairs(drops) do
|
||||
@ -614,7 +639,7 @@ function core.node_dig(pos, node, digger)
|
||||
-- Run callback
|
||||
if def and def.after_dig_node then
|
||||
-- Copy pos and node because callback can modify them
|
||||
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
|
||||
local pos_copy = vector.new(pos)
|
||||
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
||||
def.after_dig_node(pos_copy, node_copy, oldmetadata, digger)
|
||||
end
|
||||
@ -627,7 +652,7 @@ function core.node_dig(pos, node, digger)
|
||||
end
|
||||
|
||||
-- Copy pos and node because callback can modify them
|
||||
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
|
||||
local pos_copy = vector.new(pos)
|
||||
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
||||
callback(pos_copy, node_copy, digger)
|
||||
end
|
||||
@ -670,7 +695,7 @@ core.nodedef_default = {
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
wield_scale = vector.new(1, 1, 1),
|
||||
stack_max = default_stack_max,
|
||||
usable = false,
|
||||
liquids_pointable = false,
|
||||
@ -729,7 +754,7 @@ core.craftitemdef_default = {
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
wield_scale = vector.new(1, 1, 1),
|
||||
stack_max = default_stack_max,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = nil,
|
||||
@ -748,7 +773,7 @@ core.tooldef_default = {
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
wield_scale = vector.new(1, 1, 1),
|
||||
stack_max = 1,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = nil,
|
||||
@ -767,7 +792,7 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items
|
||||
groups = {},
|
||||
inventory_image = "",
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
wield_scale = vector.new(1, 1, 1),
|
||||
stack_max = default_stack_max,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = nil,
|
||||
|
@ -119,13 +119,12 @@ end
|
||||
|
||||
|
||||
function core.get_position_from_hash(hash)
|
||||
local pos = {}
|
||||
pos.x = (hash % 65536) - 32768
|
||||
local x = (hash % 65536) - 32768
|
||||
hash = math.floor(hash / 65536)
|
||||
pos.y = (hash % 65536) - 32768
|
||||
local y = (hash % 65536) - 32768
|
||||
hash = math.floor(hash / 65536)
|
||||
pos.z = (hash % 65536) - 32768
|
||||
return pos
|
||||
local z = (hash % 65536) - 32768
|
||||
return vector.new(x, y, z)
|
||||
end
|
||||
|
||||
|
||||
@ -215,7 +214,7 @@ function core.is_area_protected(minp, maxp, player_name, interval)
|
||||
local y = math.floor(yf + 0.5)
|
||||
for xf = minp.x, maxp.x, d.x do
|
||||
local x = math.floor(xf + 0.5)
|
||||
local pos = {x = x, y = y, z = z}
|
||||
local pos = vector.new(x, y, z)
|
||||
if core.is_protected(pos, player_name) then
|
||||
return pos
|
||||
end
|
||||
@ -270,24 +269,44 @@ function core.cancel_shutdown_requests()
|
||||
end
|
||||
|
||||
|
||||
-- Callback handling for dynamic_add_media
|
||||
-- Used for callback handling with dynamic_add_media
|
||||
core.dynamic_media_callbacks = {}
|
||||
|
||||
local dynamic_add_media_raw = core.dynamic_add_media_raw
|
||||
core.dynamic_add_media_raw = nil
|
||||
function core.dynamic_add_media(filepath, callback)
|
||||
local ret = dynamic_add_media_raw(filepath)
|
||||
if ret == false then
|
||||
return ret
|
||||
|
||||
-- PNG encoder safety wrapper
|
||||
|
||||
local o_encode_png = core.encode_png
|
||||
function core.encode_png(width, height, data, compression)
|
||||
if type(width) ~= "number" then
|
||||
error("Incorrect type for 'width', expected number, got " .. type(width))
|
||||
end
|
||||
if callback == nil then
|
||||
core.log("deprecated", "Calling minetest.dynamic_add_media without "..
|
||||
"a callback is deprecated and will stop working in future versions.")
|
||||
else
|
||||
-- At the moment async loading is not actually implemented, so we
|
||||
-- immediately call the callback ourselves
|
||||
for _, name in ipairs(ret) do
|
||||
callback(name)
|
||||
if type(height) ~= "number" then
|
||||
error("Incorrect type for 'height', expected number, got " .. type(height))
|
||||
end
|
||||
|
||||
local expected_byte_count = width * height * 4
|
||||
|
||||
if type(data) ~= "table" and type(data) ~= "string" then
|
||||
error("Incorrect type for 'height', expected table or string, got " .. type(height))
|
||||
end
|
||||
|
||||
local data_length = type(data) == "table" and #data * 4 or string.len(data)
|
||||
|
||||
if data_length ~= expected_byte_count then
|
||||
error(string.format(
|
||||
"Incorrect length of 'data', width and height imply %d bytes but %d were provided",
|
||||
expected_byte_count,
|
||||
data_length
|
||||
))
|
||||
end
|
||||
|
||||
if type(data) == "table" then
|
||||
local dataBuf = {}
|
||||
for i = 1, #data do
|
||||
dataBuf[i] = core.colorspec_to_bytes(data[i])
|
||||
end
|
||||
data = table.concat(dataBuf)
|
||||
end
|
||||
return true
|
||||
|
||||
return o_encode_png(width, height, data, compression or 6)
|
||||
end
|
||||
|
@ -97,10 +97,13 @@ core.register_privilege("rollback", {
|
||||
description = S("Can use the rollback functionality"),
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
core.register_privilege("debug", {
|
||||
description = S("Allows enabling various debug options that may affect gameplay"),
|
||||
core.register_privilege("basic_debug", {
|
||||
description = S("Can view more debug info that might give a gameplay advantage"),
|
||||
give_to_singleplayer = false,
|
||||
})
|
||||
core.register_privilege("debug", {
|
||||
description = S("Can enable wireframe"),
|
||||
give_to_singleplayer = false,
|
||||
give_to_admin = true,
|
||||
})
|
||||
|
||||
core.register_can_bypass_userlimit(function(name, ip)
|
||||
|
@ -610,6 +610,7 @@ core.registered_on_modchannel_message, core.register_on_modchannel_message = mak
|
||||
core.registered_on_player_inventory_actions, core.register_on_player_inventory_action = make_registration()
|
||||
core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration()
|
||||
core.registered_on_rightclickplayers, core.register_on_rightclickplayer = make_registration()
|
||||
core.registered_on_liquid_transformed, core.register_on_liquid_transformed = make_registration()
|
||||
|
||||
--
|
||||
-- Compatibility for on_mapgen_init()
|
||||
|
@ -1,6 +1,6 @@
|
||||
VoxelArea = {
|
||||
MinEdge = {x=1, y=1, z=1},
|
||||
MaxEdge = {x=0, y=0, z=0},
|
||||
MinEdge = vector.new(1, 1, 1),
|
||||
MaxEdge = vector.new(0, 0, 0),
|
||||
ystride = 0,
|
||||
zstride = 0,
|
||||
}
|
||||
@ -19,11 +19,11 @@ end
|
||||
|
||||
function VoxelArea:getExtent()
|
||||
local MaxEdge, MinEdge = self.MaxEdge, self.MinEdge
|
||||
return {
|
||||
x = MaxEdge.x - MinEdge.x + 1,
|
||||
y = MaxEdge.y - MinEdge.y + 1,
|
||||
z = MaxEdge.z - MinEdge.z + 1,
|
||||
}
|
||||
return vector.new(
|
||||
MaxEdge.x - MinEdge.x + 1,
|
||||
MaxEdge.y - MinEdge.y + 1,
|
||||
MaxEdge.z - MinEdge.z + 1
|
||||
)
|
||||
end
|
||||
|
||||
function VoxelArea:getVolume()
|
||||
|
@ -30,6 +30,7 @@ local clientpath = scriptdir .. "client" .. DIR_DELIM
|
||||
local commonpath = scriptdir .. "common" .. DIR_DELIM
|
||||
local asyncpath = scriptdir .. "async" .. DIR_DELIM
|
||||
|
||||
dofile(commonpath .. "vector.lua")
|
||||
dofile(commonpath .. "strict.lua")
|
||||
dofile(commonpath .. "serialize.lua")
|
||||
dofile(commonpath .. "misc_helpers.lua")
|
||||
|
@ -21,6 +21,7 @@ Player @1 does not exist.=Spieler @1 existiert nicht.
|
||||
Return list of all online players with privilege=Liste aller Spieler mit einem Privileg ausgeben
|
||||
Invalid parameters (see /help haspriv).=Ungültige Parameter (siehe „/help haspriv“).
|
||||
Unknown privilege!=Unbekanntes Privileg!
|
||||
No online player has the "@1" privilege.=Kein online spielender Spieler hat das „@1“-Privileg.
|
||||
Players online with the "@1" privilege: @2=Derzeit online spielende Spieler mit dem „@1“-Privileg: @2
|
||||
Your privileges are insufficient.=Ihre Privilegien sind unzureichend.
|
||||
Your privileges are insufficient. '@1' only allows you to grant: @2=Ihre Privilegien sind unzureichend. Mit „@1“ können Sie nur folgendes gewähren: @2
|
||||
@ -87,6 +88,7 @@ Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in
|
||||
Successfully reset light in the area ranging from @1 to @2.=Das Licht im Gebiet zwischen @1 und @2 wurde erfolgreich zurückgesetzt.
|
||||
Failed to load one or more blocks in area.=Fehlgeschlagen: Ein oder mehrere Kartenblöcke im Gebiet konnten nicht geladen werden.
|
||||
List mods installed on the server=Installierte Mods auf dem Server auflisten
|
||||
No mods installed.=Es sind keine Mods installiert.
|
||||
Cannot give an empty item.=Ein leerer Gegenstand kann nicht gegeben werden.
|
||||
Cannot give an unknown item.=Ein unbekannter Gegenstand kann nicht gegeben werden.
|
||||
Giving 'ignore' is not allowed.=„ignore“ darf nicht gegeben werden.
|
||||
@ -143,8 +145,8 @@ Invalid hour (must be between 0 and 23 inclusive).=Ungültige Stunde (muss zwisc
|
||||
Invalid minute (must be between 0 and 59 inclusive).=Ungültige Minute (muss zwischen 0 und 59 inklusive liegen).
|
||||
Show day count since world creation=Anzahl Tage seit der Erschaffung der Welt anzeigen
|
||||
Current day is @1.=Aktueller Tag ist @1.
|
||||
[<delay_in_seconds> | -1] [reconnect] [<message>]=[<Verzögerung_in_Sekunden> | -1] [reconnect] [<Nachricht>]
|
||||
Shutdown server (-1 cancels a delayed shutdown)=Server herunterfahren (-1 bricht einen verzögerten Abschaltvorgang ab)
|
||||
[<delay_in_seconds> | -1] [-r] [<message>]=[<Verzögerung_in_Sekunden> | -1] [-r] [<Nachricht>]
|
||||
Shutdown server (-1 cancels a delayed shutdown, -r allows players to reconnect)=Server herunterfahren (-1 bricht einen verzögerten Abschaltvorgang ab, -r erlaubt Spielern, sich wiederzuverbinden)
|
||||
Server shutting down (operator request).=Server wird heruntergefahren (Betreiberanfrage).
|
||||
Ban the IP of a player or show the ban list=Die IP eines Spielers verbannen oder die Bannliste anzeigen
|
||||
The ban list is empty.=Die Bannliste ist leer.
|
||||
@ -191,6 +193,7 @@ Available commands:=Verfügbare Befehle:
|
||||
Command not available: @1=Befehl nicht verfügbar: @1
|
||||
[all | privs | <cmd>]=[all | privs | <Befehl>]
|
||||
Get help for commands or list privileges=Hilfe für Befehle erhalten oder Privilegien auflisten
|
||||
Available privileges:=Verfügbare Privilegien:
|
||||
Command=Befehl
|
||||
Parameters=Parameter
|
||||
For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste.
|
||||
@ -200,7 +203,6 @@ Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /h
|
||||
Close=Schließen
|
||||
Privilege=Privileg
|
||||
Description=Beschreibung
|
||||
Available privileges:=Verfügbare Privilegien:
|
||||
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]]
|
||||
Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten
|
||||
Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben.
|
||||
|
@ -21,6 +21,7 @@ Player @1 does not exist.=Il giocatore @1 non esiste.
|
||||
Return list of all online players with privilege=Ritorna una lista di tutti i giocatori connessi col tale privilegio
|
||||
Invalid parameters (see /help haspriv).=Parametri non validi (vedi /help haspriv).
|
||||
Unknown privilege!=Privilegio sconosciuto!
|
||||
No online player has the "@1" privilege.=
|
||||
Players online with the "@1" privilege: @2=Giocatori connessi con il privilegio "@1": @2
|
||||
Your privileges are insufficient.=I tuoi privilegi sono insufficienti.
|
||||
Your privileges are insufficient. '@1' only allows you to grant: @2=
|
||||
@ -87,6 +88,7 @@ Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in
|
||||
Successfully reset light in the area ranging from @1 to @2.=Luce nell'area tra @1 e @2 reimpostata con successo.
|
||||
Failed to load one or more blocks in area.=Errore nel caricare uno o più blocchi mappa nell'area.
|
||||
List mods installed on the server=Elenca le mod installate nel server
|
||||
No mods installed.=
|
||||
Cannot give an empty item.=Impossibile dare un oggetto vuoto.
|
||||
Cannot give an unknown item.=Impossibile dare un oggetto sconosciuto.
|
||||
Giving 'ignore' is not allowed.=Non è permesso dare 'ignore'.
|
||||
@ -143,8 +145,8 @@ Invalid hour (must be between 0 and 23 inclusive).=Ora non valida (deve essere t
|
||||
Invalid minute (must be between 0 and 59 inclusive).=Minuto non valido (deve essere tra 0 e 59 inclusi)
|
||||
Show day count since world creation=Mostra il conteggio dei giorni da quando il mondo è stato creato
|
||||
Current day is @1.=Giorno attuale: @1.
|
||||
[<delay_in_seconds> | -1] [reconnect] [<message>]=[<ritardo_in_secondi> | -1] [reconnect] [<messaggio>]
|
||||
Shutdown server (-1 cancels a delayed shutdown)=Arresta il server (-1 annulla un arresto programmato)
|
||||
[<delay_in_seconds> | -1] [-r] [<message>]=
|
||||
Shutdown server (-1 cancels a delayed shutdown, -r allows players to reconnect)=
|
||||
Server shutting down (operator request).=Arresto del server in corso (per richiesta dell'operatore)
|
||||
Ban the IP of a player or show the ban list=Bandisce l'IP del giocatore o mostra la lista di quelli banditi
|
||||
The ban list is empty.=La lista banditi è vuota.
|
||||
@ -191,6 +193,7 @@ Available commands:=Comandi disponibili:
|
||||
Command not available: @1=Comando non disponibile: @1
|
||||
[all | privs | <cmd>]=[all | privs | <comando>]
|
||||
Get help for commands or list privileges=Richiama la finestra d'aiuto dei comandi o dei privilegi
|
||||
Available privileges:=Privilegi disponibili:
|
||||
Command=Comando
|
||||
Parameters=Parametri
|
||||
For more information, click on any entry in the list.=Per più informazioni, clicca su una qualsiasi voce dell'elenco.
|
||||
@ -200,7 +203,6 @@ Available commands: (see also: /help <cmd>)=Comandi disponibili: (vedi anche /he
|
||||
Close=Chiudi
|
||||
Privilege=Privilegio
|
||||
Description=Descrizione
|
||||
Available privileges:=Privilegi disponibili:
|
||||
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filtro>] | dump [<filtro>] | save [<formato> [<filtro>]] | reset
|
||||
Handle the profiler and profiling data=Gestisce il profiler e i dati da esso elaborati
|
||||
Statistics written to action log.=Statistiche scritte nel log delle azioni.
|
||||
@ -242,6 +244,8 @@ Profile saved to @1=
|
||||
|
||||
##### not used anymore #####
|
||||
|
||||
[<delay_in_seconds> | -1] [reconnect] [<message>]=[<ritardo_in_secondi> | -1] [reconnect] [<messaggio>]
|
||||
Shutdown server (-1 cancels a delayed shutdown)=Arresta il server (-1 annulla un arresto programmato)
|
||||
<name> (<privilege> | all)=<nome> (<privilegio> | all)
|
||||
<privilege> | all=<privilegio> | all
|
||||
Can modify 'shout' and 'interact' privileges=Si possono modificare i privilegi 'shout' e 'interact'
|
||||
|
@ -21,6 +21,7 @@ Player @1 does not exist.=
|
||||
Return list of all online players with privilege=
|
||||
Invalid parameters (see /help haspriv).=
|
||||
Unknown privilege!=
|
||||
No online player has the "@1" privilege.=
|
||||
Players online with the "@1" privilege: @2=
|
||||
Your privileges are insufficient.=
|
||||
Your privileges are insufficient. '@1' only allows you to grant: @2=
|
||||
@ -87,6 +88,7 @@ Resets lighting in the area between pos1 and pos2 (<pos1> and <pos2> must be in
|
||||
Successfully reset light in the area ranging from @1 to @2.=
|
||||
Failed to load one or more blocks in area.=
|
||||
List mods installed on the server=
|
||||
No mods installed.=
|
||||
Cannot give an empty item.=
|
||||
Cannot give an unknown item.=
|
||||
Giving 'ignore' is not allowed.=
|
||||
@ -143,8 +145,8 @@ Invalid hour (must be between 0 and 23 inclusive).=
|
||||
Invalid minute (must be between 0 and 59 inclusive).=
|
||||
Show day count since world creation=
|
||||
Current day is @1.=
|
||||
[<delay_in_seconds> | -1] [reconnect] [<message>]=
|
||||
Shutdown server (-1 cancels a delayed shutdown)=
|
||||
[<delay_in_seconds> | -1] [-r] [<message>]=
|
||||
Shutdown server (-1 cancels a delayed shutdown, -r allows players to reconnect)=
|
||||
Server shutting down (operator request).=
|
||||
Ban the IP of a player or show the ban list=
|
||||
The ban list is empty.=
|
||||
@ -191,6 +193,7 @@ Available commands:=
|
||||
Command not available: @1=
|
||||
[all | privs | <cmd>]=
|
||||
Get help for commands or list privileges=
|
||||
Available privileges:=
|
||||
Command=
|
||||
Parameters=
|
||||
For more information, click on any entry in the list.=
|
||||
@ -200,7 +203,6 @@ Available commands: (see also: /help <cmd>)=
|
||||
Close=
|
||||
Privilege=
|
||||
Description=
|
||||
Available privileges:=
|
||||
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
|
||||
Handle the profiler and profiling data=
|
||||
Statistics written to action log.=
|
||||
|
@ -57,24 +57,39 @@ local filter_types_type = {
|
||||
"txp",
|
||||
}
|
||||
|
||||
local REASON_NEW = "new"
|
||||
local REASON_UPDATE = "update"
|
||||
local REASON_DEPENDENCY = "dependency"
|
||||
|
||||
|
||||
local function get_download_url(package, reason)
|
||||
local base_url = core.settings:get("contentdb_url")
|
||||
local ret = base_url .. ("/packages/%s/%s/releases/%d/download/"):format(package.author, package.name, package.release)
|
||||
if reason then
|
||||
ret = ret .. "?reason=" .. reason
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
local function download_package(param)
|
||||
if core.download_file(param.package.url, param.filename) then
|
||||
if core.download_file(param.url, param.filename) then
|
||||
return {
|
||||
filename = param.filename,
|
||||
successful = true,
|
||||
}
|
||||
else
|
||||
core.log("error", "downloading " .. dump(param.package.url) .. " failed")
|
||||
core.log("error", "downloading " .. dump(param.url) .. " failed")
|
||||
return {
|
||||
successful = false,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local function start_install(package)
|
||||
local function start_install(package, reason)
|
||||
local params = {
|
||||
package = package,
|
||||
url = get_download_url(package, reason),
|
||||
filename = os.tempfolder() .. "_MODNAME_" .. package.name .. ".zip",
|
||||
}
|
||||
|
||||
@ -135,7 +150,7 @@ local function start_install(package)
|
||||
if next then
|
||||
table.remove(download_queue, 1)
|
||||
|
||||
start_install(next)
|
||||
start_install(next.package, next.reason)
|
||||
end
|
||||
|
||||
ui.update()
|
||||
@ -151,12 +166,12 @@ local function start_install(package)
|
||||
end
|
||||
end
|
||||
|
||||
local function queue_download(package)
|
||||
local function queue_download(package, reason)
|
||||
local max_concurrent_downloads = tonumber(core.settings:get("contentdb_max_concurrent_downloads"))
|
||||
if number_downloading < max_concurrent_downloads then
|
||||
start_install(package)
|
||||
start_install(package, reason)
|
||||
else
|
||||
table.insert(download_queue, package)
|
||||
table.insert(download_queue, { package = package, reason = reason })
|
||||
package.queued = true
|
||||
end
|
||||
end
|
||||
@ -407,12 +422,12 @@ function install_dialog.handle_submit(this, fields)
|
||||
end
|
||||
|
||||
if fields.install_all then
|
||||
queue_download(install_dialog.package)
|
||||
queue_download(install_dialog.package, REASON_NEW)
|
||||
|
||||
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)
|
||||
queue_download(dep.package, REASON_DEPENDENCY)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -560,18 +575,25 @@ function store.load()
|
||||
end
|
||||
|
||||
store.packages_full = core.parse_json(response.data) or {}
|
||||
store.aliases = {}
|
||||
|
||||
for _, package in pairs(store.packages_full) do
|
||||
package.url = base_url .. "/packages/" ..
|
||||
package.author .. "/" .. package.name ..
|
||||
"/releases/" .. package.release .. "/download/"
|
||||
|
||||
local name_len = #package.name
|
||||
if package.type == "game" and name_len > 5 and package.name:sub(name_len - 4) == "_game" then
|
||||
package.id = package.author:lower() .. "/" .. package.name:sub(1, name_len - 5)
|
||||
else
|
||||
package.id = package.author:lower() .. "/" .. package.name
|
||||
end
|
||||
|
||||
if package.aliases then
|
||||
for _, alias in ipairs(package.aliases) do
|
||||
-- We currently don't support name changing
|
||||
local suffix = "/" .. package.name
|
||||
if alias:sub(-#suffix) == suffix then
|
||||
store.aliases[alias:lower()] = package.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
store.packages_full_unordered = store.packages_full
|
||||
@ -584,7 +606,8 @@ function store.update_paths()
|
||||
pkgmgr.refresh_globals()
|
||||
for _, mod in pairs(pkgmgr.clientmods:get_list()) do
|
||||
if mod.author and mod.release > 0 then
|
||||
mod_hash[mod.author:lower() .. "/" .. mod.name] = mod
|
||||
local id = mod.author:lower() .. "/" .. mod.name
|
||||
mod_hash[store.aliases[id] or id] = mod
|
||||
end
|
||||
end
|
||||
|
||||
@ -592,14 +615,16 @@ function store.update_paths()
|
||||
pkgmgr.update_gamelist()
|
||||
for _, game in pairs(pkgmgr.games) do
|
||||
if game.author ~= "" and game.release > 0 then
|
||||
game_hash[game.author:lower() .. "/" .. game.id] = game
|
||||
local id = game.author:lower() .. "/" .. game.id
|
||||
game_hash[store.aliases[id] or id] = game
|
||||
end
|
||||
end
|
||||
|
||||
local txp_hash = {}
|
||||
for _, txp in pairs(pkgmgr.get_texture_packs()) do
|
||||
if txp.author and txp.release > 0 then
|
||||
txp_hash[txp.author:lower() .. "/" .. txp.name] = txp
|
||||
local id = txp.author:lower() .. "/" .. txp.name
|
||||
txp_hash[store.aliases[id] or id] = txp
|
||||
end
|
||||
end
|
||||
|
||||
@ -915,7 +940,7 @@ function store.handle_submit(this, fields)
|
||||
local package = store.packages_full[i]
|
||||
if package.path and package.installed_release < package.release and
|
||||
not (package.downloading or package.queued) then
|
||||
queue_download(package)
|
||||
queue_download(package, REASON_UPDATE)
|
||||
end
|
||||
end
|
||||
return true
|
||||
@ -948,7 +973,7 @@ function store.handle_submit(this, fields)
|
||||
this:hide()
|
||||
dlg:show()
|
||||
else
|
||||
queue_download(package)
|
||||
queue_download(package, package.path and REASON_UPDATE or REASON_NEW)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -31,6 +31,10 @@ end
|
||||
|
||||
-- returns error message, or nil
|
||||
local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
|
||||
|
||||
-- strip carriage returns (CR, /r)
|
||||
line = line:gsub("\r", "")
|
||||
|
||||
-- comment
|
||||
local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$")
|
||||
if comment then
|
||||
@ -650,7 +654,7 @@ local function create_change_setting_formspec(dialogdata)
|
||||
|
||||
-- Third row
|
||||
add_field(0.3, "te_octaves", fgettext("Octaves"), t[7])
|
||||
add_field(3.6, "te_persist", fgettext("Persistance"), t[8])
|
||||
add_field(3.6, "te_persist", fgettext("Persistence"), t[8])
|
||||
add_field(6.9, "te_lacun", fgettext("Lacunarity"), t[9])
|
||||
height = height + 1.1
|
||||
|
||||
|
@ -18,8 +18,14 @@
|
||||
|
||||
local enable_gamebar = PLATFORM ~= "Android"
|
||||
local current_game, singleplayer_refresh_gamebar
|
||||
local valid_disabled_settings = {
|
||||
["enable_damage"]=true,
|
||||
["creative_mode"]=true,
|
||||
["enable_server"]=true,
|
||||
}
|
||||
|
||||
if enable_gamebar then
|
||||
-- Currently chosen game in gamebar for theming and filtering
|
||||
function current_game()
|
||||
local last_game_id = core.settings:get("menu_last_game")
|
||||
local game = pkgmgr.find_by_gameid(last_game_id)
|
||||
@ -102,37 +108,87 @@ if enable_gamebar then
|
||||
btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
|
||||
end
|
||||
else
|
||||
-- Currently chosen game in gamebar: no gamebar -> no "current" game
|
||||
function current_game()
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function get_disabled_settings(game)
|
||||
if not game then
|
||||
return {}
|
||||
end
|
||||
|
||||
local gameconfig = Settings(game.path .. "/game.conf")
|
||||
local disabled_settings = {}
|
||||
if gameconfig then
|
||||
local disabled_settings_str = (gameconfig:get("disabled_settings") or ""):split()
|
||||
for _, value in pairs(disabled_settings_str) do
|
||||
local state = false
|
||||
value = value:trim()
|
||||
if string.sub(value, 1, 1) == "!" then
|
||||
state = true
|
||||
value = string.sub(value, 2)
|
||||
end
|
||||
if valid_disabled_settings[value] then
|
||||
disabled_settings[value] = state
|
||||
else
|
||||
core.log("error", "Invalid disabled setting in game.conf: "..tostring(value))
|
||||
end
|
||||
end
|
||||
end
|
||||
return disabled_settings
|
||||
end
|
||||
|
||||
local function get_formspec(tabview, name, tabdata)
|
||||
local retval = ""
|
||||
|
||||
local index = filterlist.get_current_index(menudata.worldlist,
|
||||
tonumber(core.settings:get("mainmenu_last_selected_world"))
|
||||
)
|
||||
tonumber(core.settings:get("mainmenu_last_selected_world")))
|
||||
local list = menudata.worldlist:get_list()
|
||||
local world = list and index and list[index]
|
||||
local gameid = world and world.gameid
|
||||
local game = gameid and pkgmgr.find_by_gameid(gameid)
|
||||
local disabled_settings = get_disabled_settings(game)
|
||||
|
||||
local creative, damage, host = "", "", ""
|
||||
|
||||
-- Y offsets for game settings checkboxes
|
||||
local y = -0.2
|
||||
local yo = 0.45
|
||||
|
||||
if disabled_settings["creative_mode"] == nil then
|
||||
creative = "checkbox[0,"..y..";cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
|
||||
dump(core.settings:get_bool("creative_mode")) .. "]"
|
||||
y = y + yo
|
||||
end
|
||||
if disabled_settings["enable_damage"] == nil then
|
||||
damage = "checkbox[0,"..y..";cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
|
||||
dump(core.settings:get_bool("enable_damage")) .. "]"
|
||||
y = y + yo
|
||||
end
|
||||
if disabled_settings["enable_server"] == nil then
|
||||
host = "checkbox[0,"..y..";cb_server;".. fgettext("Host Server") ..";" ..
|
||||
dump(core.settings:get_bool("enable_server")) .. "]"
|
||||
y = y + yo
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"button[3.9,3.8;2.8,1;world_delete;".. fgettext("Delete") .. "]" ..
|
||||
"button[6.55,3.8;2.8,1;world_configure;".. fgettext("Select Mods") .. "]" ..
|
||||
"button[9.2,3.8;2.8,1;world_create;".. fgettext("New") .. "]" ..
|
||||
"label[3.9,-0.05;".. fgettext("Select World:") .. "]"..
|
||||
"checkbox[0,-0.20;cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
|
||||
dump(core.settings:get_bool("creative_mode")) .. "]"..
|
||||
"checkbox[0,0.25;cb_enable_damage;".. fgettext("Enable Damage") .. ";" ..
|
||||
dump(core.settings:get_bool("enable_damage")) .. "]"..
|
||||
"checkbox[0,0.7;cb_server;".. fgettext("Host Server") ..";" ..
|
||||
dump(core.settings:get_bool("enable_server")) .. "]" ..
|
||||
creative ..
|
||||
damage ..
|
||||
host ..
|
||||
"textlist[3.9,0.4;7.9,3.45;sp_worlds;" ..
|
||||
menu_render_worldlist() ..
|
||||
";" .. index .. "]"
|
||||
|
||||
if core.settings:get_bool("enable_server") then
|
||||
if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then
|
||||
retval = retval ..
|
||||
"button[7.9,4.75;4.1,1;play;".. fgettext("Host Game") .. "]" ..
|
||||
"checkbox[0,1.15;cb_server_announce;" .. fgettext("Announce Server") .. ";" ..
|
||||
"checkbox[0,"..y..";cb_server_announce;" .. fgettext("Announce Server") .. ";" ..
|
||||
dump(core.settings:get_bool("server_announce")) .. "]" ..
|
||||
"field[0.3,2.85;3.8,0.5;te_playername;" .. fgettext("Name") .. ";" ..
|
||||
core.formspec_escape(core.settings:get("name")) .. "]" ..
|
||||
@ -227,9 +283,21 @@ local function main_button_handler(this, fields, name, tabdata)
|
||||
|
||||
-- Update last game
|
||||
local world = menudata.worldlist:get_raw_element(gamedata.selected_world)
|
||||
local game_obj
|
||||
if world then
|
||||
local game = pkgmgr.find_by_gameid(world.gameid)
|
||||
core.settings:set("menu_last_game", game.id)
|
||||
game_obj = pkgmgr.find_by_gameid(world.gameid)
|
||||
core.settings:set("menu_last_game", game_obj.id)
|
||||
end
|
||||
|
||||
local disabled_settings = get_disabled_settings(game_obj)
|
||||
for k, _ in pairs(valid_disabled_settings) do
|
||||
local v = disabled_settings[k]
|
||||
if v ~= nil then
|
||||
if k == "enable_server" and v == true then
|
||||
error("Setting 'enable_server' cannot be force-enabled! The game.conf needs to be fixed.")
|
||||
end
|
||||
core.settings:set_bool(k, disabled_settings[k])
|
||||
end
|
||||
end
|
||||
|
||||
if core.settings:get_bool("enable_server") then
|
||||
|
@ -43,6 +43,14 @@ local labels = {
|
||||
fgettext("2x"),
|
||||
fgettext("4x"),
|
||||
fgettext("8x")
|
||||
},
|
||||
shadow_levels = {
|
||||
fgettext("Disabled"),
|
||||
fgettext("Very Low"),
|
||||
fgettext("Low"),
|
||||
fgettext("Medium"),
|
||||
fgettext("High"),
|
||||
fgettext("Ultra High")
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,6 +74,10 @@ local dd_options = {
|
||||
antialiasing = {
|
||||
table.concat(labels.antialiasing, ","),
|
||||
{"0", "2", "4", "8"}
|
||||
},
|
||||
shadow_levels = {
|
||||
table.concat(labels.shadow_levels, ","),
|
||||
{ "0", "1", "2", "3", "4", "5" }
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,6 +122,15 @@ local getSettingIndex = {
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
ShadowMapping = function()
|
||||
local shadow_setting = core.settings:get("shadow_levels")
|
||||
for i = 1, #dd_options.shadow_levels[2] do
|
||||
if shadow_setting == dd_options.shadow_levels[2][i] then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
}
|
||||
|
||||
@ -197,7 +218,10 @@ local function formspec(tabview, name, tabdata)
|
||||
"checkbox[8.25,1.5;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_leaves")) .. "]" ..
|
||||
"checkbox[8.25,2;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_plants")) .. "]"
|
||||
.. dump(core.settings:get_bool("enable_waving_plants")) .. "]"..
|
||||
"label[8.25,3.0;" .. fgettext("Dynamic shadows: ") .. "]" ..
|
||||
"dropdown[8.25,3.5;3.5;dd_shadows;" .. dd_options.shadow_levels[1] .. ";"
|
||||
.. getSettingIndex.ShadowMapping() .. "]"
|
||||
else
|
||||
tab_string = tab_string ..
|
||||
"label[8.38,0.7;" .. core.colorize("#888888",
|
||||
@ -207,7 +231,9 @@ local function formspec(tabview, name, tabdata)
|
||||
"label[8.38,1.7;" .. core.colorize("#888888",
|
||||
fgettext("Waving Leaves")) .. "]" ..
|
||||
"label[8.38,2.2;" .. core.colorize("#888888",
|
||||
fgettext("Waving Plants")) .. "]"
|
||||
fgettext("Waving Plants")) .. "]"..
|
||||
"label[8.38,2.7;" .. core.colorize("#888888",
|
||||
fgettext("Dynamic shadows")) .. "]"
|
||||
end
|
||||
|
||||
return tab_string
|
||||
@ -333,6 +359,34 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
|
||||
ddhandled = true
|
||||
end
|
||||
|
||||
for i = 1, #labels.shadow_levels do
|
||||
if fields["dd_shadows"] == labels.shadow_levels[i] then
|
||||
core.settings:set("shadow_levels", dd_options.shadow_levels[2][i])
|
||||
ddhandled = true
|
||||
end
|
||||
end
|
||||
|
||||
if fields["dd_shadows"] == labels.shadow_levels[1] then
|
||||
core.settings:set("enable_dynamic_shadows", "false")
|
||||
else
|
||||
local shadow_presets = {
|
||||
[2] = { 80, 512, "true", 0, "false" },
|
||||
[3] = { 120, 1024, "true", 1, "false" },
|
||||
[4] = { 350, 2048, "true", 1, "false" },
|
||||
[5] = { 350, 2048, "true", 2, "true" },
|
||||
[6] = { 450, 4096, "true", 2, "true" },
|
||||
}
|
||||
local s = shadow_presets[table.indexof(labels.shadow_levels, fields["dd_shadows"])]
|
||||
if s then
|
||||
core.settings:set("enable_dynamic_shadows", "true")
|
||||
core.settings:set("shadow_map_max_distance", s[1])
|
||||
core.settings:set("shadow_map_texture_size", s[2])
|
||||
core.settings:set("shadow_map_texture_32bit", s[3])
|
||||
core.settings:set("shadow_filters", s[4])
|
||||
core.settings:set("shadow_map_color", s[5])
|
||||
end
|
||||
end
|
||||
|
||||
return ddhandled
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,7 @@ _G.core = {}
|
||||
_G.unpack = table.unpack
|
||||
_G.serverlistmgr = {}
|
||||
|
||||
dofile("builtin/common/vector.lua")
|
||||
dofile("builtin/common/misc_helpers.lua")
|
||||
dofile("builtin/mainmenu/serverlistmgr.lua")
|
||||
|
||||
|
@ -525,7 +525,7 @@ texture_clean_transparent (Clean transparent textures) bool false
|
||||
# can be blurred, so automatically upscale them with nearest-neighbor
|
||||
# interpolation to preserve crisp pixels. This sets the minimum texture size
|
||||
# for the upscaled textures; higher values look sharper, but require more
|
||||
# memory. Powers of 2 are recommended. This setting is ONLY applies if
|
||||
# memory. Powers of 2 are recommended. This setting is ONLY applied if
|
||||
# bilinear/trilinear/anisotropic filtering is enabled.
|
||||
# This is also used as the base node texture size for world-aligned
|
||||
# texture autoscaling.
|
||||
@ -594,6 +594,58 @@ enable_waving_leaves (Waving leaves) bool false
|
||||
# Requires shaders to be enabled.
|
||||
enable_waving_plants (Waving plants) bool false
|
||||
|
||||
[***Dynamic shadows]
|
||||
|
||||
# Set to true to enable Shadow Mapping.
|
||||
# Requires shaders to be enabled.
|
||||
enable_dynamic_shadows (Dynamic shadows) bool false
|
||||
|
||||
# Set the shadow strength.
|
||||
# Lower value means lighter shadows, higher value means darker shadows.
|
||||
shadow_strength (Shadow strength) float 0.2 0.05 1.0
|
||||
|
||||
# Maximum distance to render shadows.
|
||||
shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 120.0 10.0 1000.0
|
||||
|
||||
# Texture size to render the shadow map on.
|
||||
# This must be a power of two.
|
||||
# Bigger numbers create better shadows but it is also more expensive.
|
||||
shadow_map_texture_size (Shadow map texture size) int 1024 128 8192
|
||||
|
||||
# Sets shadow texture quality to 32 bits.
|
||||
# On false, 16 bits texture will be used.
|
||||
# This can cause much more artifacts in the shadow.
|
||||
shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true
|
||||
|
||||
# Enable Poisson disk filtering.
|
||||
# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering.
|
||||
shadow_poisson_filter (Poisson filtering) bool true
|
||||
|
||||
# Define shadow filtering quality
|
||||
# This simulates the soft shadows effect by applying a PCF or Poisson disk
|
||||
# but also uses more resources.
|
||||
shadow_filters (Shadow filter quality) enum 1 0,1,2
|
||||
|
||||
# Enable colored shadows.
|
||||
# On true translucent nodes cast colored shadows. This is expensive.
|
||||
shadow_map_color (Colored shadows) bool false
|
||||
|
||||
# Spread a complete update of shadow map over given amount of frames.
|
||||
# Higher values might make shadows laggy, lower values
|
||||
# will consume more resources.
|
||||
# Minimum value: 1; maximum value: 16
|
||||
shadow_update_frames (Map shadows update frames) int 8 1 16
|
||||
|
||||
# Set the soft shadow radius size.
|
||||
# Lower values mean sharper shadows, bigger values mean softer shadows.
|
||||
# Minimum value: 1.0; maxiumum value: 10.0
|
||||
shadow_soft_radius (Soft shadow radius) float 1.0 1.0 10.0
|
||||
|
||||
# Set the tilt of Sun/Moon orbit in degrees
|
||||
# Value of 0 means no tilt / vertical orbit.
|
||||
# Minimum value: 0.0; maximum value: 60.0
|
||||
shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 0.0 60.0
|
||||
|
||||
[**Advanced]
|
||||
|
||||
# Arm inertia, gives a more realistic movement of
|
||||
@ -620,10 +672,10 @@ viewing_range (Viewing range) int 190 20 4000
|
||||
# 0.1 = Default, 0.25 = Good value for weaker tablets.
|
||||
near_plane (Near plane) float 0.1 0 0.25
|
||||
|
||||
# Width component of the initial window size.
|
||||
# Width component of the initial window size. Ignored in fullscreen mode.
|
||||
screen_w (Screen width) int 1024 1
|
||||
|
||||
# Height component of the initial window size.
|
||||
# Height component of the initial window size. Ignored in fullscreen mode.
|
||||
screen_h (Screen height) int 600 1
|
||||
|
||||
# Save window size automatically when modified.
|
||||
@ -632,9 +684,6 @@ autosave_screensize (Autosave screen size) bool true
|
||||
# Fullscreen mode.
|
||||
fullscreen (Full screen) bool false
|
||||
|
||||
# Bits per pixel (aka color depth) in fullscreen mode.
|
||||
fullscreen_bpp (Full screen BPP) int 24
|
||||
|
||||
# Vertical screen synchronization.
|
||||
vsync (VSync) bool false
|
||||
|
||||
@ -678,7 +727,7 @@ texture_path (Texture path) path
|
||||
# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
|
||||
# On other platforms, OpenGL is recommended.
|
||||
# Shaders are supported by OpenGL (desktop only) and OGLES2 (experimental)
|
||||
video_driver (Video driver) enum opengl null,software,burningsvideo,direct3d8,direct3d9,opengl,ogles1,ogles2
|
||||
video_driver (Video driver) enum opengl opengl,ogles1,ogles2
|
||||
|
||||
# Radius of cloud area stated in number of 64 node cloud squares.
|
||||
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
|
||||
@ -739,7 +788,7 @@ selectionbox_width (Selection box width) int 2 1 5
|
||||
crosshair_color (Crosshair color) string (255,255,255)
|
||||
|
||||
# Crosshair alpha (opaqueness, between 0 and 255).
|
||||
# Also controls the object crosshair color
|
||||
# This also applies to the object crosshair.
|
||||
crosshair_alpha (Crosshair alpha) int 255 0 255
|
||||
|
||||
# Maximum number of recent chat messages to show
|
||||
@ -936,6 +985,12 @@ mute_sound (Mute sound) bool false
|
||||
|
||||
[Client]
|
||||
|
||||
# Clickable weblinks (middle-click or ctrl-left-click) enabled in chat console output.
|
||||
clickable_chat_weblinks (Chat weblinks) bool false
|
||||
|
||||
# Optional override for chat weblink color.
|
||||
chat_weblink_color (Weblink color) string
|
||||
|
||||
[*Network]
|
||||
|
||||
# Address to connect to.
|
||||
@ -948,9 +1003,9 @@ address (Server address) string
|
||||
remote_port (Remote port) int 30000 1 65535
|
||||
|
||||
# Prometheus listener address.
|
||||
# If minetest is compiled with ENABLE_PROMETHEUS option enabled,
|
||||
# If Minetest is compiled with ENABLE_PROMETHEUS option enabled,
|
||||
# enable metrics listener for Prometheus on that address.
|
||||
# Metrics can be fetch on http://127.0.0.1:30000/metrics
|
||||
# Metrics can be fetched on http://127.0.0.1:30000/metrics
|
||||
prometheus_listener_address (Prometheus listener address) string 127.0.0.1:30000
|
||||
|
||||
# Save the map received by the client on disk.
|
||||
@ -1057,11 +1112,10 @@ full_block_send_enable_min_time_from_building (Delay in sending blocks after bui
|
||||
# client number.
|
||||
max_packets_per_iteration (Max. packets per iteration) int 1024
|
||||
|
||||
# ZLib compression level to use when sending mapblocks to the client.
|
||||
# -1 - Zlib's default compression level
|
||||
# 0 - no compresson, fastest
|
||||
# Compression level to use when sending mapblocks to the client.
|
||||
# -1 - use default compression level
|
||||
# 0 - least 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]
|
||||
@ -1260,12 +1314,11 @@ max_objects_per_block (Maximum objects per block) int 64
|
||||
# See https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||
sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
|
||||
|
||||
# ZLib compression level to use when saving mapblocks to disk.
|
||||
# -1 - Zlib's default compression level
|
||||
# 0 - no compresson, fastest
|
||||
# Compression level to use when saving mapblocks to disk.
|
||||
# -1 - use default compression level
|
||||
# 0 - least 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
|
||||
map_compression_level_disk (Map Compression Level for Disk Storage) int -1 -1 9
|
||||
|
||||
# Length of a server tick and the interval at which objects are generally updated over
|
||||
# network.
|
||||
@ -1437,9 +1490,6 @@ curl_parallel_limit (cURL parallel limit) int 8
|
||||
# Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.
|
||||
curl_file_download_timeout (cURL file download timeout) int 300000
|
||||
|
||||
# Makes DirectX work with LuaJIT. Disable if it causes troubles.
|
||||
high_precision_fpu (High-precision FPU) bool true
|
||||
|
||||
# Replaces the default main menu with a custom one.
|
||||
main_menu_script (Main menu script) string
|
||||
|
||||
@ -2178,15 +2228,15 @@ chunksize (Chunk size) int 5
|
||||
enable_mapgen_debug_info (Mapgen debug) bool false
|
||||
|
||||
# Maximum number of blocks that can be queued for loading.
|
||||
emergequeue_limit_total (Absolute limit of queued blocks to emerge) int 1024
|
||||
emergequeue_limit_total (Absolute limit of queued blocks to emerge) int 1024 1 1000000
|
||||
|
||||
# Maximum number of blocks to be queued that are to be loaded from file.
|
||||
# This limit is enforced per player.
|
||||
emergequeue_limit_diskonly (Per-player limit of queued blocks load from disk) int 128
|
||||
emergequeue_limit_diskonly (Per-player limit of queued blocks load from disk) int 128 1 1000000
|
||||
|
||||
# Maximum number of blocks to be queued that are to be generated.
|
||||
# This limit is enforced per player.
|
||||
emergequeue_limit_generate (Per-player limit of queued blocks to generate) int 128
|
||||
emergequeue_limit_generate (Per-player limit of queued blocks to generate) int 128 1 1000000
|
||||
|
||||
# Number of emerge threads to use.
|
||||
# Value 0:
|
||||
|
@ -7,7 +7,22 @@ uniform vec3 eyePosition;
|
||||
// The cameraOffset is the current center of the visible world.
|
||||
uniform vec3 cameraOffset;
|
||||
uniform float animationTimer;
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
// shadow texture
|
||||
uniform sampler2D ShadowMapSampler;
|
||||
// shadow uniforms
|
||||
uniform vec3 v_LightDirection;
|
||||
uniform float f_textureresolution;
|
||||
uniform mat4 m_ShadowViewProj;
|
||||
uniform float f_shadowfar;
|
||||
varying float normalOffsetScale;
|
||||
varying float adj_shadow_strength;
|
||||
varying float cosLight;
|
||||
varying float f_normal_length;
|
||||
#endif
|
||||
|
||||
|
||||
varying vec3 vNormal;
|
||||
varying vec3 vPosition;
|
||||
// World position in the visible world (i.e. relative to the cameraOffset.)
|
||||
// This can be used for many shader effects without loss of precision.
|
||||
@ -22,10 +37,392 @@ varying mediump vec2 varTexCoord;
|
||||
centroid varying vec2 varTexCoord;
|
||||
#endif
|
||||
varying vec3 eyeVec;
|
||||
varying float nightRatio;
|
||||
|
||||
const float fogStart = FOG_START;
|
||||
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
|
||||
|
||||
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
const float bias0 = 0.9;
|
||||
const float zPersFactor = 0.5;
|
||||
const float bias1 = 1.0 - bias0 + 1e-6;
|
||||
|
||||
vec4 getPerspectiveFactor(in vec4 shadowPosition)
|
||||
{
|
||||
|
||||
float pDistance = length(shadowPosition.xy);
|
||||
float pFactor = pDistance * bias0 + bias1;
|
||||
|
||||
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPersFactor);
|
||||
|
||||
return shadowPosition;
|
||||
}
|
||||
|
||||
// assuming near is always 1.0
|
||||
float getLinearDepth()
|
||||
{
|
||||
return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
|
||||
}
|
||||
|
||||
vec3 getLightSpacePosition()
|
||||
{
|
||||
vec4 pLightSpace;
|
||||
// some drawtypes have zero normals, so we need to handle it :(
|
||||
#if DRAW_TYPE == NDT_PLANTLIKE
|
||||
pLightSpace = m_ShadowViewProj * vec4(worldPosition, 1.0);
|
||||
#else
|
||||
float offsetScale = (0.0057 * getLinearDepth() + normalOffsetScale);
|
||||
pLightSpace = m_ShadowViewProj * vec4(worldPosition + offsetScale * normalize(vNormal), 1.0);
|
||||
#endif
|
||||
pLightSpace = getPerspectiveFactor(pLightSpace);
|
||||
return pLightSpace.xyz * 0.5 + 0.5;
|
||||
}
|
||||
// custom smoothstep implementation because it's not defined in glsl1.2
|
||||
// https://docs.gl/sl4/smoothstep
|
||||
float mtsmoothstep(in float edge0, in float edge1, in float x)
|
||||
{
|
||||
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
||||
return t * t * (3.0 - 2.0 * t);
|
||||
}
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
|
||||
// c_precision of 128 fits within 7 base-10 digits
|
||||
const float c_precision = 128.0;
|
||||
const float c_precisionp1 = c_precision + 1.0;
|
||||
|
||||
float packColor(vec3 color)
|
||||
{
|
||||
return floor(color.b * c_precision + 0.5)
|
||||
+ floor(color.g * c_precision + 0.5) * c_precisionp1
|
||||
+ floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
|
||||
}
|
||||
|
||||
vec3 unpackColor(float value)
|
||||
{
|
||||
vec3 color;
|
||||
color.b = mod(value, c_precisionp1) / c_precision;
|
||||
color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
|
||||
color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
|
||||
return color;
|
||||
}
|
||||
|
||||
vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
|
||||
|
||||
float visibility = step(0.0, realDistance - texDepth.r);
|
||||
vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
|
||||
if (visibility < 0.1) {
|
||||
visibility = step(0.0, realDistance - texDepth.b);
|
||||
result = vec4(visibility, unpackColor(texDepth.a));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
|
||||
float visibility = step(0.0, realDistance - texDepth);
|
||||
return visibility;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if SHADOW_FILTER == 2
|
||||
#define PCFBOUND 3.5
|
||||
#define PCFSAMPLES 64.0
|
||||
#elif SHADOW_FILTER == 1
|
||||
#define PCFBOUND 1.5
|
||||
#if defined(POISSON_FILTER)
|
||||
#define PCFSAMPLES 32.0
|
||||
#else
|
||||
#define PCFSAMPLES 16.0
|
||||
#endif
|
||||
#else
|
||||
#define PCFBOUND 0.0
|
||||
#if defined(POISSON_FILTER)
|
||||
#define PCFSAMPLES 4.0
|
||||
#else
|
||||
#define PCFSAMPLES 1.0
|
||||
#endif
|
||||
#endif
|
||||
#ifdef COLORED_SHADOWS
|
||||
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
|
||||
float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
|
||||
return depth;
|
||||
}
|
||||
#else
|
||||
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
|
||||
float depth = realDistance - texDepth;
|
||||
return depth;
|
||||
}
|
||||
#endif
|
||||
|
||||
float getBaseLength(vec2 smTexCoord)
|
||||
{
|
||||
float l = length(2.0 * smTexCoord.xy - 1.0); // length in texture coords
|
||||
return bias1 / (1.0 / l - bias0); // return to undistorted coords
|
||||
}
|
||||
|
||||
float getDeltaPerspectiveFactor(float l)
|
||||
{
|
||||
return 0.1 / (bias0 * l + bias1); // original distortion factor, divided by 10
|
||||
}
|
||||
|
||||
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
|
||||
{
|
||||
float baseLength = getBaseLength(smTexCoord);
|
||||
float perspectiveFactor;
|
||||
|
||||
// Return fast if sharp shadows are requested
|
||||
if (SOFTSHADOWRADIUS <= 1.0) {
|
||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
||||
return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
|
||||
}
|
||||
|
||||
vec2 clampedpos;
|
||||
float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
|
||||
float y, x;
|
||||
float depth = 0.0;
|
||||
float pointDepth;
|
||||
float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
|
||||
|
||||
float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND);
|
||||
int n = 0;
|
||||
|
||||
for (y = -bound; y <= bound; y += 1.0)
|
||||
for (x = -bound; x <= bound; x += 1.0) {
|
||||
clampedpos = vec2(x,y);
|
||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius);
|
||||
clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy;
|
||||
|
||||
pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance);
|
||||
if (pointDepth > -0.01) {
|
||||
depth += pointDepth;
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
depth = depth / n;
|
||||
depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
|
||||
|
||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
||||
return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius);
|
||||
}
|
||||
|
||||
#ifdef POISSON_FILTER
|
||||
const vec2[64] poissonDisk = vec2[64](
|
||||
vec2(0.170019, -0.040254),
|
||||
vec2(-0.299417, 0.791925),
|
||||
vec2(0.645680, 0.493210),
|
||||
vec2(-0.651784, 0.717887),
|
||||
vec2(0.421003, 0.027070),
|
||||
vec2(-0.817194, -0.271096),
|
||||
vec2(-0.705374, -0.668203),
|
||||
vec2(0.977050, -0.108615),
|
||||
vec2(0.063326, 0.142369),
|
||||
vec2(0.203528, 0.214331),
|
||||
vec2(-0.667531, 0.326090),
|
||||
vec2(-0.098422, -0.295755),
|
||||
vec2(-0.885922, 0.215369),
|
||||
vec2(0.566637, 0.605213),
|
||||
vec2(0.039766, -0.396100),
|
||||
vec2(0.751946, 0.453352),
|
||||
vec2(0.078707, -0.715323),
|
||||
vec2(-0.075838, -0.529344),
|
||||
vec2(0.724479, -0.580798),
|
||||
vec2(0.222999, -0.215125),
|
||||
vec2(-0.467574, -0.405438),
|
||||
vec2(-0.248268, -0.814753),
|
||||
vec2(0.354411, -0.887570),
|
||||
vec2(0.175817, 0.382366),
|
||||
vec2(0.487472, -0.063082),
|
||||
vec2(0.355476, 0.025357),
|
||||
vec2(-0.084078, 0.898312),
|
||||
vec2(0.488876, -0.783441),
|
||||
vec2(0.470016, 0.217933),
|
||||
vec2(-0.696890, -0.549791),
|
||||
vec2(-0.149693, 0.605762),
|
||||
vec2(0.034211, 0.979980),
|
||||
vec2(0.503098, -0.308878),
|
||||
vec2(-0.016205, -0.872921),
|
||||
vec2(0.385784, -0.393902),
|
||||
vec2(-0.146886, -0.859249),
|
||||
vec2(0.643361, 0.164098),
|
||||
vec2(0.634388, -0.049471),
|
||||
vec2(-0.688894, 0.007843),
|
||||
vec2(0.464034, -0.188818),
|
||||
vec2(-0.440840, 0.137486),
|
||||
vec2(0.364483, 0.511704),
|
||||
vec2(0.034028, 0.325968),
|
||||
vec2(0.099094, -0.308023),
|
||||
vec2(0.693960, -0.366253),
|
||||
vec2(0.678884, -0.204688),
|
||||
vec2(0.001801, 0.780328),
|
||||
vec2(0.145177, -0.898984),
|
||||
vec2(0.062655, -0.611866),
|
||||
vec2(0.315226, -0.604297),
|
||||
vec2(-0.780145, 0.486251),
|
||||
vec2(-0.371868, 0.882138),
|
||||
vec2(0.200476, 0.494430),
|
||||
vec2(-0.494552, -0.711051),
|
||||
vec2(0.612476, 0.705252),
|
||||
vec2(-0.578845, -0.768792),
|
||||
vec2(-0.772454, -0.090976),
|
||||
vec2(0.504440, 0.372295),
|
||||
vec2(0.155736, 0.065157),
|
||||
vec2(0.391522, 0.849605),
|
||||
vec2(-0.620106, -0.328104),
|
||||
vec2(0.789239, -0.419965),
|
||||
vec2(-0.545396, 0.538133),
|
||||
vec2(-0.178564, -0.596057)
|
||||
);
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
|
||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
vec4 visibility = vec4(0.0);
|
||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
||||
if (radius < 0.1) {
|
||||
// we are in the middle of even brightness, no need for filtering
|
||||
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
||||
}
|
||||
|
||||
float baseLength = getBaseLength(smTexCoord);
|
||||
float perspectiveFactor;
|
||||
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
||||
int end_offset = int(samples) + init_offset;
|
||||
|
||||
for (int x = init_offset; x < end_offset; x++) {
|
||||
clampedpos = poissonDisk[x];
|
||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||
}
|
||||
|
||||
return visibility / samples;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
float visibility = 0.0;
|
||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
||||
if (radius < 0.1) {
|
||||
// we are in the middle of even brightness, no need for filtering
|
||||
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
||||
}
|
||||
|
||||
float baseLength = getBaseLength(smTexCoord);
|
||||
float perspectiveFactor;
|
||||
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
||||
int end_offset = int(samples) + init_offset;
|
||||
|
||||
for (int x = init_offset; x < end_offset; x++) {
|
||||
clampedpos = poissonDisk[x];
|
||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||
}
|
||||
|
||||
return visibility / samples;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* poisson filter disabled */
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
|
||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
vec4 visibility = vec4(0.0);
|
||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
||||
if (radius < 0.1) {
|
||||
// we are in the middle of even brightness, no need for filtering
|
||||
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
||||
}
|
||||
|
||||
float baseLength = getBaseLength(smTexCoord);
|
||||
float perspectiveFactor;
|
||||
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
float y, x;
|
||||
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
||||
int n = 0;
|
||||
|
||||
// basic PCF filter
|
||||
for (y = -bound; y <= bound; y += 1.0)
|
||||
for (x = -bound; x <= bound; x += 1.0) {
|
||||
clampedpos = vec2(x,y); // screen offset
|
||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||
n += 1;
|
||||
}
|
||||
|
||||
return visibility / n;
|
||||
}
|
||||
|
||||
#else
|
||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
float visibility = 0.0;
|
||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
||||
if (radius < 0.1) {
|
||||
// we are in the middle of even brightness, no need for filtering
|
||||
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
||||
}
|
||||
|
||||
float baseLength = getBaseLength(smTexCoord);
|
||||
float perspectiveFactor;
|
||||
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
float y, x;
|
||||
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
||||
int n = 0;
|
||||
|
||||
// basic PCF filter
|
||||
for (y = -bound; y <= bound; y += 1.0)
|
||||
for (x = -bound; x <= bound; x += 1.0) {
|
||||
clampedpos = vec2(x,y); // screen offset
|
||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||
n += 1;
|
||||
}
|
||||
|
||||
return visibility / n;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLE_TONE_MAPPING
|
||||
|
||||
/* Hable's UC2 Tone mapping parameters
|
||||
@ -58,25 +455,62 @@ vec4 applyToneMapping(vec4 color)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec3 color;
|
||||
vec2 uv = varTexCoord.st;
|
||||
|
||||
vec4 base = texture2D(baseTexture, uv).rgba;
|
||||
#ifdef USE_DISCARD
|
||||
// If alpha is zero, we can just discard the pixel. This fixes transparency
|
||||
// on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
|
||||
// and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
|
||||
if (base.a == 0.0) {
|
||||
#ifdef USE_DISCARD
|
||||
if (base.a == 0.0)
|
||||
discard;
|
||||
#endif
|
||||
#ifdef USE_DISCARD_REF
|
||||
if (base.a < 0.5)
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
color = base.rgb;
|
||||
|
||||
vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
float shadow_int = 0.0;
|
||||
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
|
||||
vec3 posLightSpace = getLightSpacePosition();
|
||||
|
||||
float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 20.0));
|
||||
float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z ),0.0);
|
||||
|
||||
if (distance_rate > 1e-7) {
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
vec4 visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
||||
shadow_int = visibility.r;
|
||||
shadow_color = visibility.gba;
|
||||
#else
|
||||
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
||||
#endif
|
||||
shadow_int *= distance_rate;
|
||||
shadow_int *= 1.0 - nightRatio;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (f_normal_length != 0 && cosLight < 0.035) {
|
||||
shadow_int = max(shadow_int, min(clamp(1.0-nightRatio, 0.0, 1.0), 1 - clamp(cosLight, 0.0, 0.035)/0.035));
|
||||
}
|
||||
|
||||
shadow_int = 1.0 - (shadow_int * f_adj_shadow_strength);
|
||||
|
||||
col.rgb = mix(shadow_color,col.rgb,shadow_int)*shadow_int;
|
||||
// col.r = 0.5 * clamp(getPenumbraRadius(ShadowMapSampler, posLightSpace.xy, posLightSpace.z, 1.0) / SOFTSHADOWRADIUS, 0.0, 1.0) + 0.5 * col.r;
|
||||
#endif
|
||||
|
||||
#if ENABLE_TONE_MAPPING
|
||||
col = applyToneMapping(col);
|
||||
#endif
|
||||
@ -94,6 +528,6 @@ void main(void)
|
||||
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
||||
col = mix(skyBgColor, col, clarity);
|
||||
col = vec4(col.rgb, base.a);
|
||||
|
||||
|
||||
gl_FragColor = col;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
uniform mat4 mWorld;
|
||||
|
||||
// Color of the light emitted by the sun.
|
||||
uniform vec3 dayLight;
|
||||
uniform vec3 eyePosition;
|
||||
@ -8,6 +7,7 @@ uniform vec3 eyePosition;
|
||||
uniform vec3 cameraOffset;
|
||||
uniform float animationTimer;
|
||||
|
||||
varying vec3 vNormal;
|
||||
varying vec3 vPosition;
|
||||
// World position in the visible world (i.e. relative to the cameraOffset.)
|
||||
// This can be used for many shader effects without loss of precision.
|
||||
@ -24,13 +24,38 @@ varying mediump vec2 varTexCoord;
|
||||
#else
|
||||
centroid varying vec2 varTexCoord;
|
||||
#endif
|
||||
varying vec3 eyeVec;
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
// shadow uniforms
|
||||
uniform vec3 v_LightDirection;
|
||||
uniform float f_textureresolution;
|
||||
uniform mat4 m_ShadowViewProj;
|
||||
uniform float f_shadowfar;
|
||||
uniform float f_shadow_strength;
|
||||
uniform float f_timeofday;
|
||||
varying float cosLight;
|
||||
varying float normalOffsetScale;
|
||||
varying float adj_shadow_strength;
|
||||
varying float f_normal_length;
|
||||
#endif
|
||||
|
||||
|
||||
varying vec3 eyeVec;
|
||||
varying float nightRatio;
|
||||
// Color of the light emitted by the light sources.
|
||||
const vec3 artificialLight = vec3(1.04, 1.04, 1.04);
|
||||
const float e = 2.718281828459;
|
||||
const float BS = 10.0;
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
// custom smoothstep implementation because it's not defined in glsl1.2
|
||||
// https://docs.gl/sl4/smoothstep
|
||||
float mtsmoothstep(in float edge0, in float edge1, in float x)
|
||||
{
|
||||
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
||||
return t * t * (3.0 - 2.0 * t);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
float smoothCurve(float x)
|
||||
{
|
||||
@ -86,6 +111,9 @@ float snoise(vec3 p)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
void main(void)
|
||||
{
|
||||
varTexCoord = inTexCoord0.st;
|
||||
@ -136,10 +164,9 @@ void main(void)
|
||||
gl_Position = mWorldViewProj * inVertexPosition;
|
||||
#endif
|
||||
|
||||
|
||||
vPosition = gl_Position.xyz;
|
||||
|
||||
eyeVec = -(mWorldView * inVertexPosition).xyz;
|
||||
vNormal = inVertexNormal;
|
||||
|
||||
// Calculate color.
|
||||
// Red, green and blue components are pre-multiplied with
|
||||
@ -152,7 +179,7 @@ void main(void)
|
||||
vec4 color = inVertexColor;
|
||||
#endif
|
||||
// The alpha gives the ratio of sunlight in the incoming light.
|
||||
float nightRatio = 1.0 - color.a;
|
||||
nightRatio = 1.0 - color.a;
|
||||
color.rgb = color.rgb * (color.a * dayLight.rgb +
|
||||
nightRatio * artificialLight.rgb) * 2.0;
|
||||
color.a = 1.0;
|
||||
@ -164,4 +191,26 @@ void main(void)
|
||||
0.07 * brightness);
|
||||
|
||||
varColor = clamp(color, 0.0, 1.0);
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
vec3 nNormal = normalize(vNormal);
|
||||
cosLight = dot(nNormal, -v_LightDirection);
|
||||
float texelSize = 767.0 / f_textureresolution;
|
||||
float slopeScale = clamp(1.0 - abs(cosLight), 0.0, 1.0);
|
||||
normalOffsetScale = texelSize * slopeScale;
|
||||
|
||||
if (f_timeofday < 0.2) {
|
||||
adj_shadow_strength = f_shadow_strength * 0.5 *
|
||||
(1.0 - mtsmoothstep(0.18, 0.2, f_timeofday));
|
||||
} else if (f_timeofday >= 0.8) {
|
||||
adj_shadow_strength = f_shadow_strength * 0.5 *
|
||||
mtsmoothstep(0.8, 0.83, f_timeofday);
|
||||
} else {
|
||||
adj_shadow_strength = f_shadow_strength *
|
||||
mtsmoothstep(0.20, 0.25, f_timeofday) *
|
||||
(1.0 - mtsmoothstep(0.7, 0.8, f_timeofday));
|
||||
}
|
||||
f_normal_length = length(vNormal);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -23,8 +23,22 @@ const float BS = 10.0;
|
||||
const float fogStart = FOG_START;
|
||||
const float fogShadingParameter = 1.0 / (1.0 - fogStart);
|
||||
|
||||
#if ENABLE_TONE_MAPPING
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
// shadow texture
|
||||
uniform sampler2D ShadowMapSampler;
|
||||
// shadow uniforms
|
||||
uniform vec3 v_LightDirection;
|
||||
uniform float f_textureresolution;
|
||||
uniform mat4 m_ShadowViewProj;
|
||||
uniform float f_shadowfar;
|
||||
uniform float f_timeofday;
|
||||
varying float normalOffsetScale;
|
||||
varying float adj_shadow_strength;
|
||||
varying float cosLight;
|
||||
varying float f_normal_length;
|
||||
#endif
|
||||
|
||||
#if ENABLE_TONE_MAPPING
|
||||
/* Hable's UC2 Tone mapping parameters
|
||||
A = 0.22;
|
||||
B = 0.30;
|
||||
@ -55,30 +69,306 @@ vec4 applyToneMapping(vec4 color)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
const float bias0 = 0.9;
|
||||
const float zPersFactor = 0.5;
|
||||
const float bias1 = 1.0 - bias0;
|
||||
|
||||
vec4 getPerspectiveFactor(in vec4 shadowPosition)
|
||||
{
|
||||
float pDistance = length(shadowPosition.xy);
|
||||
float pFactor = pDistance * bias0 + bias1;
|
||||
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPersFactor);
|
||||
|
||||
return shadowPosition;
|
||||
}
|
||||
|
||||
// assuming near is always 1.0
|
||||
float getLinearDepth()
|
||||
{
|
||||
return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
|
||||
}
|
||||
|
||||
vec3 getLightSpacePosition()
|
||||
{
|
||||
vec4 pLightSpace;
|
||||
float normalBias = 0.0005 * getLinearDepth() * cosLight + normalOffsetScale;
|
||||
pLightSpace = m_ShadowViewProj * vec4(worldPosition + normalBias * normalize(vNormal), 1.0);
|
||||
pLightSpace = getPerspectiveFactor(pLightSpace);
|
||||
return pLightSpace.xyz * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
|
||||
// c_precision of 128 fits within 7 base-10 digits
|
||||
const float c_precision = 128.0;
|
||||
const float c_precisionp1 = c_precision + 1.0;
|
||||
|
||||
float packColor(vec3 color)
|
||||
{
|
||||
return floor(color.b * c_precision + 0.5)
|
||||
+ floor(color.g * c_precision + 0.5) * c_precisionp1
|
||||
+ floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
|
||||
}
|
||||
|
||||
vec3 unpackColor(float value)
|
||||
{
|
||||
vec3 color;
|
||||
color.b = mod(value, c_precisionp1) / c_precision;
|
||||
color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
|
||||
color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
|
||||
return color;
|
||||
}
|
||||
|
||||
vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
|
||||
|
||||
float visibility = step(0.0, (realDistance-2e-5) - texDepth.r);
|
||||
vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
|
||||
if (visibility < 0.1) {
|
||||
visibility = step(0.0, (realDistance-2e-5) - texDepth.r);
|
||||
result = vec4(visibility, unpackColor(texDepth.a));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
|
||||
float visibility = step(0.0, (realDistance-2e-5) - texDepth);
|
||||
|
||||
return visibility;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if SHADOW_FILTER == 2
|
||||
#define PCFBOUND 3.5
|
||||
#define PCFSAMPLES 64.0
|
||||
#elif SHADOW_FILTER == 1
|
||||
#define PCFBOUND 1.5
|
||||
#if defined(POISSON_FILTER)
|
||||
#define PCFSAMPLES 32.0
|
||||
#else
|
||||
#define PCFSAMPLES 16.0
|
||||
#endif
|
||||
#else
|
||||
#define PCFBOUND 0.0
|
||||
#if defined(POISSON_FILTER)
|
||||
#define PCFSAMPLES 4.0
|
||||
#else
|
||||
#define PCFSAMPLES 1.0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef POISSON_FILTER
|
||||
const vec2[64] poissonDisk = vec2[64](
|
||||
vec2(0.170019, -0.040254),
|
||||
vec2(-0.299417, 0.791925),
|
||||
vec2(0.645680, 0.493210),
|
||||
vec2(-0.651784, 0.717887),
|
||||
vec2(0.421003, 0.027070),
|
||||
vec2(-0.817194, -0.271096),
|
||||
vec2(-0.705374, -0.668203),
|
||||
vec2(0.977050, -0.108615),
|
||||
vec2(0.063326, 0.142369),
|
||||
vec2(0.203528, 0.214331),
|
||||
vec2(-0.667531, 0.326090),
|
||||
vec2(-0.098422, -0.295755),
|
||||
vec2(-0.885922, 0.215369),
|
||||
vec2(0.566637, 0.605213),
|
||||
vec2(0.039766, -0.396100),
|
||||
vec2(0.751946, 0.453352),
|
||||
vec2(0.078707, -0.715323),
|
||||
vec2(-0.075838, -0.529344),
|
||||
vec2(0.724479, -0.580798),
|
||||
vec2(0.222999, -0.215125),
|
||||
vec2(-0.467574, -0.405438),
|
||||
vec2(-0.248268, -0.814753),
|
||||
vec2(0.354411, -0.887570),
|
||||
vec2(0.175817, 0.382366),
|
||||
vec2(0.487472, -0.063082),
|
||||
vec2(0.355476, 0.025357),
|
||||
vec2(-0.084078, 0.898312),
|
||||
vec2(0.488876, -0.783441),
|
||||
vec2(0.470016, 0.217933),
|
||||
vec2(-0.696890, -0.549791),
|
||||
vec2(-0.149693, 0.605762),
|
||||
vec2(0.034211, 0.979980),
|
||||
vec2(0.503098, -0.308878),
|
||||
vec2(-0.016205, -0.872921),
|
||||
vec2(0.385784, -0.393902),
|
||||
vec2(-0.146886, -0.859249),
|
||||
vec2(0.643361, 0.164098),
|
||||
vec2(0.634388, -0.049471),
|
||||
vec2(-0.688894, 0.007843),
|
||||
vec2(0.464034, -0.188818),
|
||||
vec2(-0.440840, 0.137486),
|
||||
vec2(0.364483, 0.511704),
|
||||
vec2(0.034028, 0.325968),
|
||||
vec2(0.099094, -0.308023),
|
||||
vec2(0.693960, -0.366253),
|
||||
vec2(0.678884, -0.204688),
|
||||
vec2(0.001801, 0.780328),
|
||||
vec2(0.145177, -0.898984),
|
||||
vec2(0.062655, -0.611866),
|
||||
vec2(0.315226, -0.604297),
|
||||
vec2(-0.780145, 0.486251),
|
||||
vec2(-0.371868, 0.882138),
|
||||
vec2(0.200476, 0.494430),
|
||||
vec2(-0.494552, -0.711051),
|
||||
vec2(0.612476, 0.705252),
|
||||
vec2(-0.578845, -0.768792),
|
||||
vec2(-0.772454, -0.090976),
|
||||
vec2(0.504440, 0.372295),
|
||||
vec2(0.155736, 0.065157),
|
||||
vec2(0.391522, 0.849605),
|
||||
vec2(-0.620106, -0.328104),
|
||||
vec2(0.789239, -0.419965),
|
||||
vec2(-0.545396, 0.538133),
|
||||
vec2(-0.178564, -0.596057)
|
||||
);
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
|
||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
vec4 visibility = vec4(0.0);
|
||||
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-PCFSAMPLES)));
|
||||
int end_offset = int(PCFSAMPLES) + init_offset;
|
||||
|
||||
for (int x = init_offset; x < end_offset; x++) {
|
||||
clampedpos = poissonDisk[x] * texture_size * SOFTSHADOWRADIUS + smTexCoord.xy;
|
||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||
}
|
||||
|
||||
return visibility / PCFSAMPLES;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
float visibility = 0.0;
|
||||
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-PCFSAMPLES)));
|
||||
int end_offset = int(PCFSAMPLES) + init_offset;
|
||||
|
||||
for (int x = init_offset; x < end_offset; x++) {
|
||||
clampedpos = poissonDisk[x] * texture_size * SOFTSHADOWRADIUS + smTexCoord.xy;
|
||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||
}
|
||||
|
||||
return visibility / PCFSAMPLES;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* poisson filter disabled */
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
|
||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
vec4 visibility = vec4(0.0);
|
||||
float sradius=0.0;
|
||||
if( PCFBOUND>0)
|
||||
sradius = SOFTSHADOWRADIUS / PCFBOUND;
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
float y, x;
|
||||
// basic PCF filter
|
||||
for (y = -PCFBOUND; y <= PCFBOUND; y += 1.0)
|
||||
for (x = -PCFBOUND; x <= PCFBOUND; x += 1.0) {
|
||||
clampedpos = vec2(x,y) * texture_size* sradius + smTexCoord.xy;
|
||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||
}
|
||||
|
||||
return visibility / PCFSAMPLES;
|
||||
}
|
||||
|
||||
#else
|
||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||
{
|
||||
vec2 clampedpos;
|
||||
float visibility = 0.0;
|
||||
float sradius=0.0;
|
||||
if( PCFBOUND>0)
|
||||
sradius = SOFTSHADOWRADIUS / PCFBOUND;
|
||||
|
||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
||||
float y, x;
|
||||
// basic PCF filter
|
||||
for (y = -PCFBOUND; y <= PCFBOUND; y += 1.0)
|
||||
for (x = -PCFBOUND; x <= PCFBOUND; x += 1.0) {
|
||||
clampedpos = vec2(x,y) * texture_size * sradius + smTexCoord.xy;
|
||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||
}
|
||||
|
||||
return visibility / PCFSAMPLES;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec3 color;
|
||||
vec2 uv = varTexCoord.st;
|
||||
|
||||
vec4 base = texture2D(baseTexture, uv).rgba;
|
||||
|
||||
#ifdef USE_DISCARD
|
||||
// If alpha is zero, we can just discard the pixel. This fixes transparency
|
||||
// on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
|
||||
// and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
|
||||
if (base.a == 0.0) {
|
||||
#ifdef USE_DISCARD
|
||||
if (base.a == 0.0)
|
||||
discard;
|
||||
#endif
|
||||
#ifdef USE_DISCARD_REF
|
||||
if (base.a < 0.5)
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
color = base.rgb;
|
||||
|
||||
vec4 col = vec4(color.rgb, base.a);
|
||||
|
||||
col.rgb *= varColor.rgb;
|
||||
|
||||
col.rgb *= emissiveColor.rgb * vIDiff;
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
float shadow_int = 0.0;
|
||||
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
|
||||
vec3 posLightSpace = getLightSpacePosition();
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
vec4 visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
||||
shadow_int = visibility.r;
|
||||
shadow_color = visibility.gba;
|
||||
#else
|
||||
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
||||
#endif
|
||||
|
||||
if (f_normal_length != 0 && cosLight <= 0.001) {
|
||||
shadow_int = clamp(shadow_int + 0.5 * abs(cosLight), 0.0, 1.0);
|
||||
}
|
||||
|
||||
shadow_int = 1.0 - (shadow_int * adj_shadow_strength);
|
||||
|
||||
col.rgb = mix(shadow_color, col.rgb, shadow_int) * shadow_int;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if ENABLE_TONE_MAPPING
|
||||
col = applyToneMapping(col);
|
||||
#endif
|
||||
|
@ -13,12 +13,37 @@ varying mediump vec2 varTexCoord;
|
||||
centroid varying vec2 varTexCoord;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
// shadow uniforms
|
||||
uniform vec3 v_LightDirection;
|
||||
uniform float f_textureresolution;
|
||||
uniform mat4 m_ShadowViewProj;
|
||||
uniform float f_shadowfar;
|
||||
uniform float f_shadow_strength;
|
||||
uniform float f_timeofday;
|
||||
varying float cosLight;
|
||||
varying float normalOffsetScale;
|
||||
varying float adj_shadow_strength;
|
||||
varying float f_normal_length;
|
||||
#endif
|
||||
|
||||
varying vec3 eyeVec;
|
||||
varying float vIDiff;
|
||||
|
||||
const float e = 2.718281828459;
|
||||
const float BS = 10.0;
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
// custom smoothstep implementation because it's not defined in glsl1.2
|
||||
// https://docs.gl/sl4/smoothstep
|
||||
float mtsmoothstep(in float edge0, in float edge1, in float x)
|
||||
{
|
||||
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
||||
return t * t * (3.0 - 2.0 * t);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
float directional_ambient(vec3 normal)
|
||||
{
|
||||
vec3 v = normal * normal;
|
||||
@ -54,4 +79,25 @@ void main(void)
|
||||
#else
|
||||
varColor = inVertexColor;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
|
||||
cosLight = max(0.0, dot(vNormal, -v_LightDirection));
|
||||
float texelSize = 0.51;
|
||||
float slopeScale = clamp(1.0 - cosLight, 0.0, 1.0);
|
||||
normalOffsetScale = texelSize * slopeScale;
|
||||
if (f_timeofday < 0.2) {
|
||||
adj_shadow_strength = f_shadow_strength * 0.5 *
|
||||
(1.0 - mtsmoothstep(0.18, 0.2, f_timeofday));
|
||||
} else if (f_timeofday >= 0.8) {
|
||||
adj_shadow_strength = f_shadow_strength * 0.5 *
|
||||
mtsmoothstep(0.8, 0.83, f_timeofday);
|
||||
} else {
|
||||
adj_shadow_strength = f_shadow_strength *
|
||||
mtsmoothstep(0.20, 0.25, f_timeofday) *
|
||||
(1.0 - mtsmoothstep(0.7, 0.8, f_timeofday));
|
||||
}
|
||||
f_normal_length = length(vNormal);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
13
client/shaders/shadow_shaders/pass1_fragment.glsl
Normal file
@ -0,0 +1,13 @@
|
||||
uniform sampler2D ColorMapSampler;
|
||||
varying vec4 tPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 col = texture2D(ColorMapSampler, gl_TexCoord[0].st);
|
||||
|
||||
if (col.a < 0.70)
|
||||
discard;
|
||||
|
||||
float depth = 0.5 + tPos.z * 0.5;
|
||||
gl_FragColor = vec4(depth, 0.0, 0.0, 1.0);
|
||||
}
|
38
client/shaders/shadow_shaders/pass1_trans_fragment.glsl
Normal file
@ -0,0 +1,38 @@
|
||||
uniform sampler2D ColorMapSampler;
|
||||
varying vec4 tPos;
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
// c_precision of 128 fits within 7 base-10 digits
|
||||
const float c_precision = 128.0;
|
||||
const float c_precisionp1 = c_precision + 1.0;
|
||||
|
||||
float packColor(vec3 color)
|
||||
{
|
||||
return floor(color.b * c_precision + 0.5)
|
||||
+ floor(color.g * c_precision + 0.5) * c_precisionp1
|
||||
+ floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
|
||||
}
|
||||
|
||||
const vec3 black = vec3(0.0);
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 col = texture2D(ColorMapSampler, gl_TexCoord[0].st);
|
||||
#ifndef COLORED_SHADOWS
|
||||
if (col.a < 0.5)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
float depth = 0.5 + tPos.z * 0.5;
|
||||
// ToDo: Liso: Apply movement on waving plants
|
||||
// depth in [0, 1] for texture
|
||||
|
||||
//col.rgb = col.a == 1.0 ? vec3(1.0) : col.rgb;
|
||||
#ifdef COLORED_SHADOWS
|
||||
float packedColor = packColor(mix(col.rgb, black, col.a));
|
||||
gl_FragColor = vec4(depth, packedColor, 0.0,1.0);
|
||||
#else
|
||||
gl_FragColor = vec4(depth, 0.0, 0.0, 1.0);
|
||||
#endif
|
||||
}
|
26
client/shaders/shadow_shaders/pass1_trans_vertex.glsl
Normal file
@ -0,0 +1,26 @@
|
||||
uniform mat4 LightMVP; // world matrix
|
||||
varying vec4 tPos;
|
||||
|
||||
const float bias0 = 0.9;
|
||||
const float zPersFactor = 0.5;
|
||||
const float bias1 = 1.0 - bias0 + 1e-6;
|
||||
|
||||
vec4 getPerspectiveFactor(in vec4 shadowPosition)
|
||||
{
|
||||
float pDistance = length(shadowPosition.xy);
|
||||
float pFactor = pDistance * bias0 + bias1;
|
||||
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPersFactor);
|
||||
|
||||
return shadowPosition;
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 pos = LightMVP * gl_Vertex;
|
||||
|
||||
tPos = getPerspectiveFactor(LightMVP * gl_Vertex);
|
||||
|
||||
gl_Position = vec4(tPos.xyz, 1.0);
|
||||
gl_TexCoord[0].st = gl_MultiTexCoord0.st;
|
||||
}
|
26
client/shaders/shadow_shaders/pass1_vertex.glsl
Normal file
@ -0,0 +1,26 @@
|
||||
uniform mat4 LightMVP; // world matrix
|
||||
varying vec4 tPos;
|
||||
|
||||
const float bias0 = 0.9;
|
||||
const float zPersFactor = 0.5;
|
||||
const float bias1 = 1.0 - bias0 + 1e-6;
|
||||
|
||||
vec4 getPerspectiveFactor(in vec4 shadowPosition)
|
||||
{
|
||||
float pDistance = length(shadowPosition.xy);
|
||||
float pFactor = pDistance * bias0 + bias1;
|
||||
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPersFactor);
|
||||
|
||||
return shadowPosition;
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 pos = LightMVP * gl_Vertex;
|
||||
|
||||
tPos = getPerspectiveFactor(pos);
|
||||
|
||||
gl_Position = vec4(tPos.xyz, 1.0);
|
||||
gl_TexCoord[0].st = gl_MultiTexCoord0.st;
|
||||
}
|
23
client/shaders/shadow_shaders/pass2_fragment.glsl
Normal file
@ -0,0 +1,23 @@
|
||||
uniform sampler2D ShadowMapClientMap;
|
||||
#ifdef COLORED_SHADOWS
|
||||
uniform sampler2D ShadowMapClientMapTraslucent;
|
||||
#endif
|
||||
uniform sampler2D ShadowMapSamplerdynamic;
|
||||
|
||||
void main() {
|
||||
|
||||
#ifdef COLORED_SHADOWS
|
||||
vec2 first_depth = texture2D(ShadowMapClientMap, gl_TexCoord[0].st).rg;
|
||||
vec2 depth_splitdynamics = vec2(texture2D(ShadowMapSamplerdynamic, gl_TexCoord[2].st).r, 0.0);
|
||||
if (first_depth.r > depth_splitdynamics.r)
|
||||
first_depth = depth_splitdynamics;
|
||||
vec2 depth_color = texture2D(ShadowMapClientMapTraslucent, gl_TexCoord[1].st).rg;
|
||||
gl_FragColor = vec4(first_depth.r, first_depth.g, depth_color.r, depth_color.g);
|
||||
#else
|
||||
float first_depth = texture2D(ShadowMapClientMap, gl_TexCoord[0].st).r;
|
||||
float depth_splitdynamics = texture2D(ShadowMapSamplerdynamic, gl_TexCoord[2].st).r;
|
||||
first_depth = min(first_depth, depth_splitdynamics);
|
||||
gl_FragColor = vec4(first_depth, 0.0, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
}
|
9
client/shaders/shadow_shaders/pass2_vertex.glsl
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 uv = vec4(gl_Vertex.xyz, 1.0) * 0.5 + 0.5;
|
||||
gl_TexCoord[0] = uv;
|
||||
gl_TexCoord[1] = uv;
|
||||
gl_TexCoord[2] = uv;
|
||||
gl_Position = vec4(gl_Vertex.xyz, 1.0);
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
|
||||
mark_as_advanced(IRRLICHT_DLL)
|
||||
|
||||
# Find include directory and libraries
|
||||
|
||||
# find our fork first, then upstream (TODO: remove this?)
|
||||
foreach(libname IN ITEMS IrrlichtMt Irrlicht)
|
||||
string(TOLOWER "${libname}" libname2)
|
||||
|
||||
find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
|
||||
DOC "Path to the directory with IrrlichtMt includes"
|
||||
PATHS
|
||||
/usr/local/include/${libname2}
|
||||
/usr/include/${libname2}
|
||||
/system/develop/headers/${libname2} #Haiku
|
||||
PATH_SUFFIXES "include/${libname2}"
|
||||
)
|
||||
|
||||
find_library(IRRLICHT_LIBRARY NAMES lib${libname} ${libname}
|
||||
DOC "Path to the IrrlichtMt library file"
|
||||
PATHS
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
/system/develop/lib # Haiku
|
||||
)
|
||||
|
||||
if(IRRLICHT_INCLUDE_DIR OR IRRLICHT_LIBRARY)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Handholding for users
|
||||
if(IRRLICHT_INCLUDE_DIR AND (NOT IS_DIRECTORY "${IRRLICHT_INCLUDE_DIR}" OR
|
||||
NOT EXISTS "${IRRLICHT_INCLUDE_DIR}/irrlicht.h"))
|
||||
message(WARNING "IRRLICHT_INCLUDE_DIR was set to ${IRRLICHT_INCLUDE_DIR} "
|
||||
"but irrlicht.h does not exist inside. The path will not be used.")
|
||||
unset(IRRLICHT_INCLUDE_DIR CACHE)
|
||||
endif()
|
||||
if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR APPLE)
|
||||
# (only on systems where we're sure how a valid library looks like)
|
||||
if(IRRLICHT_LIBRARY AND (IS_DIRECTORY "${IRRLICHT_LIBRARY}" OR
|
||||
NOT IRRLICHT_LIBRARY MATCHES "\\.(a|so|dylib|lib)([.0-9]+)?$"))
|
||||
message(WARNING "IRRLICHT_LIBRARY was set to ${IRRLICHT_LIBRARY} "
|
||||
"but is not a valid library file. The path will not be used.")
|
||||
unset(IRRLICHT_LIBRARY CACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# On Windows, find the DLL for installation
|
||||
if(WIN32)
|
||||
# If VCPKG_APPLOCAL_DEPS is ON, dll's are automatically handled by VCPKG
|
||||
if(NOT VCPKG_APPLOCAL_DEPS)
|
||||
find_file(IRRLICHT_DLL NAMES IrrlichtMt.dll
|
||||
DOC "Path of the IrrlichtMt dll (for installation)"
|
||||
)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Irrlicht DEFAULT_MSG IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR)
|
||||
|