mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2
This commit is contained in:
commit
fa212d19f7
572 changed files with 71629 additions and 67352 deletions
|
@ -1,4 +1,4 @@
|
||||||
Checks: '-*,modernize-use-emplace,modernize-avoid-bind,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,performance-*'
|
Checks: '-*,modernize-use-emplace,modernize-avoid-bind,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,performance-*,-performance-avoid-endl,performance-inefficient-string-concatenation'
|
||||||
WarningsAsErrors: '-*,modernize-use-emplace,performance-type-promotion-in-math-fn,performance-faster-string-find,performance-implicit-cast-in-loop'
|
WarningsAsErrors: '-*,modernize-use-emplace,performance-type-promotion-in-math-fn,performance-faster-string-find,performance-implicit-cast-in-loop'
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: performance-unnecessary-value-param.AllowedTypes
|
- key: performance-unnecessary-value-param.AllowedTypes
|
||||||
|
|
40
.github/CONTRIBUTING.md
vendored
40
.github/CONTRIBUTING.md
vendored
|
@ -14,7 +14,7 @@ Contributions are welcome! Here's how you can help:
|
||||||
[clone](https://help.github.com/articles/cloning-a-repository/) your fork.
|
[clone](https://help.github.com/articles/cloning-a-repository/) your fork.
|
||||||
|
|
||||||
2. Before you start coding, consider opening an
|
2. Before you start coding, consider opening an
|
||||||
[issue at Github](https://github.com/minetest/minetest/issues) to discuss the
|
[issue on Github](https://github.com/luanti-org/luanti/issues) to discuss the
|
||||||
suitability and implementation of your intended contribution with the core
|
suitability and implementation of your intended contribution with the core
|
||||||
developers.
|
developers.
|
||||||
|
|
||||||
|
@ -25,16 +25,16 @@ Contributions are welcome! Here's how you can help:
|
||||||
the work, to avoid disappointment.
|
the work, to avoid disappointment.
|
||||||
|
|
||||||
You may also benefit from discussing on our IRC development channel
|
You may also benefit from discussing on our IRC development channel
|
||||||
[#minetest-dev](http://www.minetest.net/irc/). Note that a proper IRC client
|
[#luanti-dev](http://www.luanti.org/irc/). Note that a proper IRC client
|
||||||
is required to speak on this channel.
|
is required to speak on this channel.
|
||||||
|
|
||||||
3. Start coding!
|
3. Start coding!
|
||||||
- Refer to the
|
- Refer to the
|
||||||
[Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.md),
|
[Lua API](https://github.com/luanti-org/luanti/blob/master/doc/lua_api.md),
|
||||||
[Developer Wiki](http://dev.minetest.net/Main_Page) and other
|
[Developer Wiki](https://dev.luanti.org/) and other
|
||||||
[documentation](https://github.com/minetest/minetest/tree/master/doc).
|
[documentation](https://github.com/luanti-org/luanti/tree/master/doc).
|
||||||
- Follow the [C/C++](http://dev.minetest.net/Code_style_guidelines) and
|
- Follow the [C/C++](https://dev.luanti.org/Code_style_guidelines) and
|
||||||
[Lua](http://dev.minetest.net/Lua_code_style_guidelines) code style guidelines.
|
[Lua](https://dev.luanti.org/Lua_code_style_guidelines) code style guidelines.
|
||||||
- Check your code works as expected and document any changes to the Lua API.
|
- Check your code works as expected and document any changes to the Lua API.
|
||||||
- To avoid conflicting changes between contributions, do not do the following manually. They will be done before each release.
|
- To avoid conflicting changes between contributions, do not do the following manually. They will be done before each release.
|
||||||
- Run `updatepo.sh` or update `luanti.po{,t}` even if your code adds new translatable strings.
|
- Run `updatepo.sh` or update `luanti.po{,t}` even if your code adds new translatable strings.
|
||||||
|
@ -53,7 +53,7 @@ Contributions are welcome! Here's how you can help:
|
||||||
- The following lines should describe the commit, starting a new line for each point.
|
- The following lines should describe the commit, starting a new line for each point.
|
||||||
|
|
||||||
5. Once you are happy with your changes, submit a pull request.
|
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).
|
- Open the [pull-request form](https://github.com/luanti-org/luanti/pull/new/master).
|
||||||
- Add a description explaining what you've done (or if it's a
|
- Add a description explaining what you've done (or if it's a
|
||||||
work-in-progress - what you need to do).
|
work-in-progress - what you need to do).
|
||||||
- Make sure to fill out the pull request template.
|
- Make sure to fill out the pull request template.
|
||||||
|
@ -64,8 +64,8 @@ Contributions are welcome! Here's how you can help:
|
||||||
picture of the project.
|
picture of the project.
|
||||||
2. It works.
|
2. It works.
|
||||||
3. It follows the code style for
|
3. It follows the code style for
|
||||||
[C/C++](http://dev.minetest.net/Code_style_guidelines) or
|
[C/C++](https://dev.luanti.org/Code_style_guidelines) or
|
||||||
[Lua](http://dev.minetest.net/Lua_code_style_guidelines).
|
[Lua](https://dev.luanti.org/Lua_code_style_guidelines).
|
||||||
4. The code's interfaces are well designed, regardless of other aspects that
|
4. The code's interfaces are well designed, regardless of other aspects that
|
||||||
might need more work in the future.
|
might need more work in the future.
|
||||||
5. It uses protocols and formats which include the required compatibility.
|
5. It uses protocols and formats which include the required compatibility.
|
||||||
|
@ -76,9 +76,9 @@ If you experience an issue, we would like to know the details - especially when
|
||||||
a stable release is on the way.
|
a stable release is on the way.
|
||||||
|
|
||||||
1. Do a quick search on GitHub to check if the issue has already been reported.
|
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
|
2. Is it an issue with the Luanti *engine*? If not, report it
|
||||||
[elsewhere](http://www.minetest.net/development/#reporting-issues).
|
[elsewhere](http://www.luanti.org/development/#reporting-issues).
|
||||||
3. [Open an issue](https://github.com/minetest/minetest/issues/new) and describe
|
3. [Open an issue](https://github.com/luanti-org/luanti/issues/new) and describe
|
||||||
the issue you are having - you could include:
|
the issue you are having - you could include:
|
||||||
- Error logs (check the bottom of the `debug.txt` file).
|
- Error logs (check the bottom of the `debug.txt` file).
|
||||||
- Screenshots.
|
- Screenshots.
|
||||||
|
@ -106,21 +106,21 @@ the project page with a list of current languages
|
||||||
Builtin (the component which contains things like server messages, chat command
|
Builtin (the component which contains things like server messages, chat command
|
||||||
descriptions, privilege descriptions) is translated separately; it needs to be
|
descriptions, privilege descriptions) is translated separately; it needs to be
|
||||||
translated by editing a `.tr` text file. See
|
translated by editing a `.tr` text file. See
|
||||||
[Translation](https://dev.minetest.net/Translation) for more information.
|
[Translation](https://dev.luanti.org/Translation) for more information.
|
||||||
|
|
||||||
## Donations
|
## Donations
|
||||||
|
|
||||||
If you'd like to monetarily support Luanti development, you can find donation
|
If you'd like to monetarily support Luanti development, you can find donation
|
||||||
methods on [our website](http://www.minetest.net/development/#donate).
|
methods on [our website](http://www.luanti.org/development/#donate).
|
||||||
|
|
||||||
# Maintaining
|
# Maintaining
|
||||||
|
|
||||||
* This is a concise version of the
|
* This is a concise version of the
|
||||||
[Rules & Guidelines](http://dev.minetest.net/Category:Rules_and_Guidelines) on the developer wiki.*
|
[Rules & Guidelines](https://dev.luanti.org/engine-dev-process/) on the developer wiki.*
|
||||||
|
|
||||||
These notes are for those who have push access Luanti (core developers / maintainers).
|
These notes are for those who have push access Luanti (core developers / maintainers).
|
||||||
|
|
||||||
- See the [project organisation](http://dev.minetest.net/Organisation) for the people involved.
|
- See the [project organisation](https://dev.luanti.org/Organisation) for the people involved.
|
||||||
|
|
||||||
## Concept approvals and roadmaps
|
## Concept approvals and roadmaps
|
||||||
|
|
||||||
|
@ -159,14 +159,14 @@ Submit a :+1: (+1) or "Looks good" comment to show you believe the pull-request
|
||||||
- The title should follow the commit guidelines (title starts with a capital letter, present tense, descriptive).
|
- The title should follow the commit guidelines (title starts with a capital letter, present tense, descriptive).
|
||||||
- Don't modify history older than 10 minutes.
|
- Don't modify history older than 10 minutes.
|
||||||
- Use rebase, not merge to get linear history:
|
- Use rebase, not merge to get linear history:
|
||||||
- `curl https://github.com/minetest/minetest/pull/1.patch | git am`
|
- `curl -Ls https://github.com/luanti-org/luanti/pull/1.patch | git am`
|
||||||
|
|
||||||
## Reviewing issues and feature requests
|
## Reviewing issues and feature requests
|
||||||
|
|
||||||
- If an issue does not get a response from its author within 1 month (when requiring more details), it can be closed.
|
- If an issue does not get a response from its author within 1 month (when requiring more details), it can be closed.
|
||||||
- When an issue is a duplicate, refer to the first ones and close the later ones.
|
- When an issue is a duplicate, refer to the first ones and close the later ones.
|
||||||
- Tag issues with the appropriate [labels](https://github.com/minetest/minetest/labels) for devices, platforms etc.
|
- Tag issues with the appropriate [labels](https://github.com/luanti-org/luanti/labels) for devices, platforms etc.
|
||||||
|
|
||||||
## Releasing a new version
|
## Releasing a new version
|
||||||
|
|
||||||
*Refer to [dev.minetest.net/Releasing_Luanti](https://dev.minetest.net/Releasing_Luanti)*
|
*Refer to [dev.luanti.org/Releasing_Luanti](https://dev.luanti.org/Releasing_Luanti)*
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
|
@ -9,7 +9,7 @@ body:
|
||||||
|
|
||||||
1. **Please update Luanti to the latest stable or dev version** before submitting bug reports. Make sure the bug is still reproducible on the latest version.
|
1. **Please update Luanti to the latest stable or dev version** before submitting bug reports. Make sure the bug is still reproducible on the latest version.
|
||||||
2. This page is for reporting the bugs of **the engine itself**. For bugs in a particular game, please [search for the game in the ContentDB](https://content.luanti.org/packages/?type=game) and submit a bug report in their issue trackers.
|
2. This page is for reporting the bugs of **the engine itself**. For bugs in a particular game, please [search for the game in the ContentDB](https://content.luanti.org/packages/?type=game) and submit a bug report in their issue trackers.
|
||||||
* For example, you can submit issues about the Minetest Game [in its own repository](https://github.com/minetest/minetest_game/issues).
|
* For example, you can submit issues about the Minetest Game [in its own repository](https://github.com/luanti-org/minetest_game/issues).
|
||||||
3. Please provide as many details as possible for us to spot the problem quicker.
|
3. Please provide as many details as possible for us to spot the problem quicker.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,7 +1,7 @@
|
||||||
blank_issues_enabled: true
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Submit issues about Minetest Game
|
- name: Submit issues about Minetest Game
|
||||||
url: https://github.com/minetest/minetest_game/issues/new/choose
|
url: https://github.com/luanti-org/minetest_game/issues/new
|
||||||
about: Only submit issues of the engine in this repository's issue tracker. Submit those of Minetest Game in its own issue tracker.
|
about: Only submit issues of the engine in this repository's issue tracker. Submit those of Minetest Game in its own issue tracker.
|
||||||
- name: Search for issue trackers of third-party games
|
- name: Search for issue trackers of third-party games
|
||||||
url: https://content.luanti.org/packages/?type=game
|
url: https://content.luanti.org/packages/?type=game
|
||||||
|
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -3,7 +3,7 @@ Add compact, short information about your PR for easier understanding:
|
||||||
- Goal of the PR
|
- Goal of the PR
|
||||||
- How does the PR work?
|
- How does the PR work?
|
||||||
- Does it resolve any reported issue?
|
- Does it resolve any reported issue?
|
||||||
- Does this relate to a goal in [the roadmap](https://github.com/minetest/minetest/blob/master/doc/direction.md)?
|
- Does this relate to a goal in [the roadmap](https://github.com/luanti-org/luanti/blob/master/doc/direction.md)?
|
||||||
- If not a bug fix, why is this PR needed? What usecases does it solve?
|
- If not a bug fix, why is this PR needed? What usecases does it solve?
|
||||||
|
|
||||||
## To do
|
## To do
|
||||||
|
|
4
.github/SECURITY.md
vendored
4
.github/SECURITY.md
vendored
|
@ -3,7 +3,7 @@
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
We only support the latest stable version for security issues.
|
We only support the latest stable version for security issues.
|
||||||
See the [releases page](https://github.com/minetest/minetest/releases).
|
See the [releases page](https://github.com/luanti-org/luanti/releases).
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ We ask that you report vulnerabilities privately, by contacting a core developer
|
||||||
to give us time to fix them. You can do that by emailing one of the following addresses:
|
to give us time to fix them. You can do that by emailing one of the following addresses:
|
||||||
|
|
||||||
* celeron55@gmail.com
|
* celeron55@gmail.com
|
||||||
* rubenwardy@minetest.net
|
* rw@rubenwardy.com
|
||||||
|
|
||||||
Depending on severity, we will either create a private issue for the vulnerability
|
Depending on severity, we will either create a private issue for the vulnerability
|
||||||
and release a patch version of Luanti, or give you permission to file the issue publicly.
|
and release a patch version of Luanti, or give you permission to file the issue publicly.
|
||||||
|
|
2
.github/workflows/lua_api_deploy.yml
vendored
2
.github/workflows/lua_api_deploy.yml
vendored
|
@ -16,7 +16,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.repository == 'minetest/minetest'
|
if: github.repository == 'luanti-org/luanti'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
79
.github/workflows/whitespace_checks.yml
vendored
79
.github/workflows/whitespace_checks.yml
vendored
|
@ -14,6 +14,7 @@ on:
|
||||||
- '**.sh'
|
- '**.sh'
|
||||||
- '**.cmake'
|
- '**.cmake'
|
||||||
- '**.glsl'
|
- '**.glsl'
|
||||||
|
- '**.lua'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '**.txt'
|
- '**.txt'
|
||||||
|
@ -24,6 +25,7 @@ on:
|
||||||
- '**.sh'
|
- '**.sh'
|
||||||
- '**.cmake'
|
- '**.cmake'
|
||||||
- '**.glsl'
|
- '**.glsl'
|
||||||
|
- '**.lua'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
trailing_whitespaces:
|
trailing_whitespaces:
|
||||||
|
@ -32,7 +34,72 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
# Line endings are already ensured by .gitattributes
|
# Line endings are already ensured by .gitattributes
|
||||||
- name: Check trailing whitespaces
|
- name: Check trailing whitespaces
|
||||||
run: if git ls-files | grep -E '\.txt$|\.md$|\.[ch]$|\.cpp$|\.hpp$|\.sh$|\.cmake$|\.glsl$' | xargs grep -n '\s$'; then echo -e "\033[0;31mFound trailing whitespace"; (exit 1); else (exit 0); fi
|
run: |
|
||||||
|
if git ls-files |\
|
||||||
|
grep -E '\.txt$|\.md$|\.[ch]$|\.cpp$|\.hpp$|\.sh$|\.cmake$|\.glsl$' |\
|
||||||
|
xargs grep -n '\s$';\
|
||||||
|
then\
|
||||||
|
echo -e "\033[0;31mFound trailing whitespace";\
|
||||||
|
(exit 1);\
|
||||||
|
else\
|
||||||
|
(exit 0);\
|
||||||
|
fi
|
||||||
|
|
||||||
|
indent_spaces:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
# Line endings are already ensured by .gitattributes
|
||||||
|
# Multiple multline comments in one line is not supported by this check
|
||||||
|
# and there is no reason to use them
|
||||||
|
# So lines like: "/* */ /*" or "*/ a = 5; /*" will result in error
|
||||||
|
- name: Check for unsupported multiline comments
|
||||||
|
run: |
|
||||||
|
if git ls-files |\
|
||||||
|
grep -E '^src/.*\.cpp$|^src/.*\.[ch]$' |\
|
||||||
|
xargs grep -n '\*/.*/\*';\
|
||||||
|
then
|
||||||
|
echo -e "\033[0;31mUnsupported combination of multiline comments. New multiline comment should begin on new line.";\
|
||||||
|
(exit 1);\
|
||||||
|
else\
|
||||||
|
(exit 0);\
|
||||||
|
fi
|
||||||
|
if git ls-files |\
|
||||||
|
grep -E '\.lua$' |\
|
||||||
|
xargs grep -n -e '\]\].*--\[\[';\
|
||||||
|
then
|
||||||
|
echo -e "\033[0;31mUnsupported combination of multiline comments. New multiline comment should begin on new line.";\
|
||||||
|
(exit 1);\
|
||||||
|
else\
|
||||||
|
(exit 0);\
|
||||||
|
fi
|
||||||
|
# This prepare files for final check
|
||||||
|
# See python script ./util/ci/indent_tab_preprocess.py for details.
|
||||||
|
- name: Preprocess files
|
||||||
|
run: |
|
||||||
|
git ls-files |\
|
||||||
|
grep -E '^src/.*\.cpp$|^src/.*\.[ch]$' |\
|
||||||
|
xargs -L 1 -P $(($(nproc) + 1)) \
|
||||||
|
python3 ./util/ci/indent_tab_preprocess.py "/*" "*/"
|
||||||
|
git ls-files |\
|
||||||
|
grep -E '\.lua$' |\
|
||||||
|
xargs -L 1 -P $(($(nproc) + 1)) \
|
||||||
|
python3 ./util/ci/indent_tab_preprocess.py "--[[" "]]"
|
||||||
|
# Check for bad indent.
|
||||||
|
# This runs over preprocessed files.
|
||||||
|
# If there is any remaining space on line beginning or after tab,
|
||||||
|
# error is generated
|
||||||
|
- name: Check indent spaces
|
||||||
|
run: |
|
||||||
|
if git ls-files |\
|
||||||
|
grep -E '^src/.*\.cpp$|^src/.*\.[ch]$|\.lua' |\
|
||||||
|
xargs grep -n -P '^\t*[ ]';\
|
||||||
|
then\
|
||||||
|
echo -e "\033[0;31mFound incorrect indent whitespaces";\
|
||||||
|
(exit 1);\
|
||||||
|
else\
|
||||||
|
(exit 0);\
|
||||||
|
fi
|
||||||
|
|
||||||
tabs_lua_api_files:
|
tabs_lua_api_files:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -40,6 +107,12 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
# Some files should not contain tabs
|
# Some files should not contain tabs
|
||||||
- name: Check tabs in Lua API files
|
- name: Check tabs in Lua API files
|
||||||
run: if grep -n $'\t' doc/lua_api.md doc/client_lua_api.md; then echo -e "\033[0;31mFound tab in markdown file"; (exit 1); else (exit 0); fi
|
run: |
|
||||||
|
if grep -n $'\t' doc/lua_api.md doc/client_lua_api.md;\
|
||||||
|
then\
|
||||||
|
echo -e "\033[0;31mFound tab in markdown file";\
|
||||||
|
(exit 1);\
|
||||||
|
else\
|
||||||
|
(exit 0);\
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
6
.github/workflows/windows.yml
vendored
6
.github/workflows/windows.yml
vendored
|
@ -71,8 +71,8 @@ jobs:
|
||||||
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
|
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
env:
|
env:
|
||||||
VCPKG_VERSION: 01f602195983451bc83e72f4214af2cbc495aa94
|
VCPKG_VERSION: d5ec528843d29e3a52d745a64b469f810b2cedbf
|
||||||
# 2024.05.24
|
# 2025.02.14
|
||||||
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp sdl2
|
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp sdl2
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
@ -106,10 +106,12 @@ jobs:
|
||||||
vcpkgTriplet: ${{ matrix.config.vcpkg_triplet }}
|
vcpkgTriplet: ${{ matrix.config.vcpkg_triplet }}
|
||||||
|
|
||||||
- name: CMake
|
- name: CMake
|
||||||
|
# Note: See #15976 for why CMAKE_POLICY_VERSION_MINIMUM=3.5 is set.
|
||||||
run: |
|
run: |
|
||||||
cmake ${{matrix.config.generator}} `
|
cmake ${{matrix.config.generator}} `
|
||||||
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}\vcpkg\scripts\buildsystems\vcpkg.cmake" `
|
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}\vcpkg\scripts\buildsystems\vcpkg.cmake" `
|
||||||
-DCMAKE_BUILD_TYPE=Release `
|
-DCMAKE_BUILD_TYPE=Release `
|
||||||
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 `
|
||||||
-DENABLE_POSTGRESQL=OFF `
|
-DENABLE_POSTGRESQL=OFF `
|
||||||
-DENABLE_LUAJIT=TRUE `
|
-DENABLE_LUAJIT=TRUE `
|
||||||
-DREQUIRE_LUAJIT=TRUE `
|
-DREQUIRE_LUAJIT=TRUE `
|
||||||
|
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -49,13 +49,13 @@ AppDir
|
||||||
# Nix
|
# Nix
|
||||||
/result
|
/result
|
||||||
|
|
||||||
## Files related to Minetest development cycle
|
## Files related to Luanti development cycle
|
||||||
/*.patch
|
/*.patch
|
||||||
*.diff
|
*.diff
|
||||||
# GNU Patch reject file
|
# GNU Patch reject file
|
||||||
*.rej
|
*.rej
|
||||||
|
|
||||||
## Non-static Minetest directories or symlinks to these
|
## Non-static Luanti directories or symlinks to these
|
||||||
/bin/
|
/bin/
|
||||||
/games/*
|
/games/*
|
||||||
!/games/devtest/
|
!/games/devtest/
|
||||||
|
@ -80,7 +80,7 @@ minetest.conf
|
||||||
debug.txt
|
debug.txt
|
||||||
debug.txt.1
|
debug.txt.1
|
||||||
|
|
||||||
## Other files generated by Minetest
|
## Other files generated by Luanti
|
||||||
screenshot_*.png
|
screenshot_*.png
|
||||||
testbm.txt
|
testbm.txt
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ ignore = {
|
||||||
read_globals = {
|
read_globals = {
|
||||||
"ItemStack",
|
"ItemStack",
|
||||||
"INIT",
|
"INIT",
|
||||||
|
"PLATFORM",
|
||||||
"DIR_DELIM",
|
"DIR_DELIM",
|
||||||
"dump", "dump2",
|
"dump", "dump2",
|
||||||
"fgettext", "fgettext_ne",
|
"fgettext", "fgettext_ne",
|
||||||
|
@ -18,10 +19,10 @@ read_globals = {
|
||||||
"VoxelManip",
|
"VoxelManip",
|
||||||
"profiler",
|
"profiler",
|
||||||
"Settings",
|
"Settings",
|
||||||
"PerlinNoise", "PerlinNoiseMap",
|
"ValueNoise", "ValueNoiseMap",
|
||||||
|
|
||||||
string = {fields = {"split", "trim"}},
|
string = {fields = {"split", "trim"}},
|
||||||
table = {fields = {"copy", "getn", "indexof", "keyof", "insert_all"}},
|
table = {fields = {"copy", "copy_with_metatables", "getn", "indexof", "keyof", "insert_all"}},
|
||||||
math = {fields = {"hypot", "round"}},
|
math = {fields = {"hypot", "round"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,10 +76,6 @@ files["builtin/mainmenu"] = {
|
||||||
globals = {
|
globals = {
|
||||||
"gamedata",
|
"gamedata",
|
||||||
},
|
},
|
||||||
|
|
||||||
read_globals = {
|
|
||||||
"PLATFORM",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
files["builtin/common/tests"] = {
|
files["builtin/common/tests"] = {
|
||||||
|
|
|
@ -11,7 +11,7 @@ set(CLANG_MINIMUM_VERSION "7.0.1")
|
||||||
|
|
||||||
# You should not need to edit these manually, use util/bump_version.sh
|
# You should not need to edit these manually, use util/bump_version.sh
|
||||||
set(VERSION_MAJOR 5)
|
set(VERSION_MAJOR 5)
|
||||||
set(VERSION_MINOR 11)
|
set(VERSION_MINOR 12)
|
||||||
set(VERSION_PATCH 0)
|
set(VERSION_PATCH 0)
|
||||||
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ endif()
|
||||||
# - win32/gcc: fails to link
|
# - win32/gcc: fails to link
|
||||||
# - win32/clang: works
|
# - win32/clang: works
|
||||||
# - macOS on x86: seems to be fine
|
# - macOS on x86: seems to be fine
|
||||||
# - macOS on ARM: crashes, see <https://github.com/minetest/minetest/issues/14397>
|
# - macOS on ARM: crashes, see <https://github.com/luanti-org/luanti/issues/14397>
|
||||||
# Note: since CMake has no easy architecture detection disabling for Mac entirely
|
# Note: since CMake has no easy architecture detection disabling for Mac entirely
|
||||||
#### ####
|
#### ####
|
||||||
if((WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR APPLE)
|
if((WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR APPLE)
|
||||||
|
|
|
@ -102,6 +102,9 @@ grorp:
|
||||||
using the font "undefined medium" (https://undefined-medium.com/),
|
using the font "undefined medium" (https://undefined-medium.com/),
|
||||||
which is licensed under the SIL Open Font License, Version 1.1
|
which is licensed under the SIL Open Font License, Version 1.1
|
||||||
modified by DS
|
modified by DS
|
||||||
|
textures/base/pack/dig_btn.png
|
||||||
|
textures/base/pack/place_btn.png
|
||||||
|
derived by editing the text in aux1_btn.svg
|
||||||
|
|
||||||
License of Luanti source code
|
License of Luanti source code
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
18
README.md
18
README.md
|
@ -1,13 +1,15 @@
|
||||||
Luanti (formerly Minetest)
|
<div align="center">
|
||||||
==========================
|
<img src="textures/base/pack/logo.png" width="32%">
|
||||||
|
<h1>Luanti (formerly Minetest)</h1>
|
||||||

|
<img src="https://github.com/luanti-org/luanti/workflows/build/badge.svg" alt="Build Status">
|
||||||
[](https://hosted.weblate.org/engage/minetest/?utm_source=widget)
|
<a href="https://hosted.weblate.org/engage/minetest/?utm_source=widget"><img src="https://hosted.weblate.org/widgets/minetest/-/svg-badge.svg" alt="Translation status"></a>
|
||||||
[](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
|
<a href="https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html"><img src="https://img.shields.io/badge/license-LGPLv2.1%2B-blue.svg" alt="License"></a>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
Luanti is a free open-source voxel game engine with easy modding and game creation.
|
Luanti is a free open-source voxel game engine with easy modding and game creation.
|
||||||
|
|
||||||
Copyright (C) 2010-2024 Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-2025 Perttu Ahola <celeron55@gmail.com>
|
||||||
and contributors (see source file comments and the version control log)
|
and contributors (see source file comments and the version control log)
|
||||||
|
|
||||||
Table of Contents
|
Table of Contents
|
||||||
|
@ -28,7 +30,7 @@ Further documentation
|
||||||
- Website: https://www.luanti.org/
|
- Website: https://www.luanti.org/
|
||||||
- Wiki: https://wiki.luanti.org/
|
- Wiki: https://wiki.luanti.org/
|
||||||
- Forum: https://forum.luanti.org/
|
- Forum: https://forum.luanti.org/
|
||||||
- GitHub: https://github.com/minetest/minetest/
|
- GitHub: https://github.com/luanti-org/luanti/
|
||||||
- [Developer documentation](doc/developing/)
|
- [Developer documentation](doc/developing/)
|
||||||
- [doc/](doc/) directory of source distribution
|
- [doc/](doc/) directory of source distribution
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||||
index fd5a056e3..83e3cf657 100644
|
|
||||||
--- a/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
--- a/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||||
+++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
+++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||||
@@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
@@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||||
|
@ -9,7 +8,7 @@ index fd5a056e3..83e3cf657 100644
|
||||||
- if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
- if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
||||||
+ if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
+ if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
||||||
+ /*
|
+ /*
|
||||||
+ * CUSTOM ADDITION FOR MINETEST
|
+ * CUSTOM ADDITION FOR LUANTI
|
||||||
+ * should be upstreamed
|
+ * should be upstreamed
|
||||||
+ */
|
+ */
|
||||||
+ (source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
+ (source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
||||||
|
|
|
@ -60,8 +60,8 @@ import java.util.Locale;
|
||||||
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
|
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
|
||||||
private static final String TAG = "SDL";
|
private static final String TAG = "SDL";
|
||||||
private static final int SDL_MAJOR_VERSION = 2;
|
private static final int SDL_MAJOR_VERSION = 2;
|
||||||
private static final int SDL_MINOR_VERSION = 30;
|
private static final int SDL_MINOR_VERSION = 32;
|
||||||
private static final int SDL_MICRO_VERSION = 8;
|
private static final int SDL_MICRO_VERSION = 0;
|
||||||
/*
|
/*
|
||||||
// Display InputType.SOURCE/CLASS of events and devices
|
// Display InputType.SOURCE/CLASS of events and devices
|
||||||
//
|
//
|
||||||
|
@ -790,6 +790,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
SDLActivity.mFullscreenModeActive = false;
|
SDLActivity.mFullscreenModeActive = false;
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) {
|
||||||
|
window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "error handling message, getContext() returned no Activity");
|
Log.e(TAG, "error handling message, getContext() returned no Activity");
|
||||||
|
@ -1347,7 +1350,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||||
|
|
||||||
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
||||||
/*
|
/*
|
||||||
* CUSTOM ADDITION FOR MINETEST
|
* CUSTOM ADDITION FOR LUANTI
|
||||||
* should be upstreamed
|
* should be upstreamed
|
||||||
*/
|
*/
|
||||||
(source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
(source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
||||||
|
|
11
android/app/src/main/res/values-fa/strings.xml
Normal file
11
android/app/src/main/res/values-fa/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="unzip_notification_description">کمتر از 1 دقیقه…</string>
|
||||||
|
<string name="loading">در حال بارگذاری…</string>
|
||||||
|
<string name="ime_dialog_done">انجام شد</string>
|
||||||
|
<string name="label">لوآنتی</string>
|
||||||
|
<string name="unzip_notification_title">در حال بارگذاری لوآنتی</string>
|
||||||
|
<string name="notification_channel_name">نوتیفیکیشن عمومی</string>
|
||||||
|
<string name="notification_channel_description">نوتیفیکیشن از لوآنتی</string>
|
||||||
|
<string name="no_web_browser">هیچ مرورگری یافت نشد</string>
|
||||||
|
</resources>
|
11
android/app/src/main/res/values-fr/strings.xml
Normal file
11
android/app/src/main/res/values-fr/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="label">Luanti</string>
|
||||||
|
<string name="loading">Chargement…</string>
|
||||||
|
<string name="notification_channel_name">Notification générale</string>
|
||||||
|
<string name="notification_channel_description">Notifications de Luanti</string>
|
||||||
|
<string name="unzip_notification_title">Chargement de Luanti</string>
|
||||||
|
<string name="unzip_notification_description">Moins d\'une minute…</string>
|
||||||
|
<string name="ime_dialog_done">Terminé</string>
|
||||||
|
<string name="no_web_browser">Aucun navigateur web trouvé</string>
|
||||||
|
</resources>
|
11
android/app/src/main/res/values-gl/strings.xml
Normal file
11
android/app/src/main/res/values-gl/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="label">Luanti</string>
|
||||||
|
<string name="loading">Cargando…</string>
|
||||||
|
<string name="notification_channel_name">Notificación xeral</string>
|
||||||
|
<string name="notification_channel_description">Notificacións de Luanti</string>
|
||||||
|
<string name="unzip_notification_title">Cargando Luanti</string>
|
||||||
|
<string name="unzip_notification_description">Menos de 1 minuto…</string>
|
||||||
|
<string name="ime_dialog_done">Feito</string>
|
||||||
|
<string name="no_web_browser">Non se atopou ningún navegador web</string>
|
||||||
|
</resources>
|
11
android/app/src/main/res/values-sv/strings.xml
Normal file
11
android/app/src/main/res/values-sv/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="label">Luanti</string>
|
||||||
|
<string name="loading">Laddar…</string>
|
||||||
|
<string name="unzip_notification_description">Mindre än 1 minut…</string>
|
||||||
|
<string name="ime_dialog_done">Färdig</string>
|
||||||
|
<string name="no_web_browser">Ingen webbläsare kunde hittas</string>
|
||||||
|
<string name="notification_channel_name">Generell notis</string>
|
||||||
|
<string name="notification_channel_description">Notiser från Luanti</string>
|
||||||
|
<string name="unzip_notification_title">Laddar Luanti</string>
|
||||||
|
</resources>
|
2
android/app/src/main/res/values-ta/strings.xml
Normal file
2
android/app/src/main/res/values-ta/strings.xml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources></resources>
|
11
android/app/src/main/res/values-uk/strings.xml
Normal file
11
android/app/src/main/res/values-uk/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="label">Luanti</string>
|
||||||
|
<string name="no_web_browser">Браузерів не знайдено</string>
|
||||||
|
<string name="loading">Завантаження…</string>
|
||||||
|
<string name="notification_channel_name">Загальні сповіщення</string>
|
||||||
|
<string name="unzip_notification_title">Luanti завантажується</string>
|
||||||
|
<string name="unzip_notification_description">Менше за 1 хвилину…</string>
|
||||||
|
<string name="ime_dialog_done">Готово</string>
|
||||||
|
<string name="notification_channel_description">Сповіщення від Luanti</string>
|
||||||
|
</resources>
|
11
android/app/src/main/res/values-zh-rCN/strings.xml
Normal file
11
android/app/src/main/res/values-zh-rCN/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="label">Luanti</string>
|
||||||
|
<string name="loading">加载中…</string>
|
||||||
|
<string name="notification_channel_name">一般通知</string>
|
||||||
|
<string name="notification_channel_description">Luanti 的通知</string>
|
||||||
|
<string name="unzip_notification_title">加载 Luanti 中</string>
|
||||||
|
<string name="unzip_notification_description">不到1分钟…</string>
|
||||||
|
<string name="ime_dialog_done">完成</string>
|
||||||
|
<string name="no_web_browser">未找到网页浏览器</string>
|
||||||
|
</resources>
|
11
android/app/src/main/res/values-zh-rTW/strings.xml
Normal file
11
android/app/src/main/res/values-zh-rTW/strings.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="loading">載入中…</string>
|
||||||
|
<string name="notification_channel_name">一般通知</string>
|
||||||
|
<string name="notification_channel_description">Luanti 的通知</string>
|
||||||
|
<string name="unzip_notification_description">不到1分鐘…</string>
|
||||||
|
<string name="ime_dialog_done">完畢</string>
|
||||||
|
<string name="no_web_browser">未找到任何網頁瀏覽器</string>
|
||||||
|
<string name="label">Luanti</string>
|
||||||
|
<string name="unzip_notification_title">載入Luanti中</string>
|
||||||
|
</resources>
|
|
@ -1,7 +1,7 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
project.ext.set("versionMajor", 5) // Version Major
|
project.ext.set("versionMajor", 5) // Version Major
|
||||||
project.ext.set("versionMinor", 11) // Version Minor
|
project.ext.set("versionMinor", 12) // Version Minor
|
||||||
project.ext.set("versionPatch", 0) // Version Patch
|
project.ext.set("versionPatch", 0) // Version Patch
|
||||||
// ^ keep in sync with cmake
|
// ^ keep in sync with cmake
|
||||||
|
|
||||||
|
|
148
android/icons/dig_btn.svg
Normal file
148
android/icons/dig_btn.svg
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
inkscape:export-ydpi="24.000002"
|
||||||
|
inkscape:export-xdpi="24.000002"
|
||||||
|
inkscape:export-filename="../../textures/base/pack/dig_btn.png"
|
||||||
|
sodipodi:docname="dig_btn.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 135.46666 135.46667"
|
||||||
|
height="512"
|
||||||
|
width="512"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:snap-others="true"
|
||||||
|
inkscape:snap-object-midpoints="false"
|
||||||
|
inkscape:snap-to-guides="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:snap-page="true"
|
||||||
|
inkscape:snap-grids="false"
|
||||||
|
inkscape:pagecheckerboard="false"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:current-layer="layer2"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:cy="266.84627"
|
||||||
|
inkscape:cx="201.24514"
|
||||||
|
inkscape:zoom="1.4633894"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#404040"
|
||||||
|
id="base"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:deskcolor="#d1d1d1">
|
||||||
|
<inkscape:grid
|
||||||
|
empopacity="0.25098039"
|
||||||
|
empcolor="#40ff40"
|
||||||
|
opacity="0.1254902"
|
||||||
|
color="#40ff40"
|
||||||
|
empspacing="4"
|
||||||
|
spacingy="0.26458333"
|
||||||
|
spacingx="0.26458333"
|
||||||
|
id="grid16"
|
||||||
|
type="xygrid"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
units="px"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
inkscape:label="Layer 2"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7055"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7035"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7005"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5127"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<text
|
||||||
|
transform="scale(1.0078883,0.99217343)"
|
||||||
|
id="text4716"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.4785px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
xml:space="preserve"><tspan
|
||||||
|
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
id="tspan4714"
|
||||||
|
sodipodi:role="line">LMB</tspan></text>
|
||||||
|
<flowRoot
|
||||||
|
transform="scale(0.26458333)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRoot4718"
|
||||||
|
xml:space="preserve"><flowRegion
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRegion4720"><rect
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
y="124.10143"
|
||||||
|
x="264.65997"
|
||||||
|
height="136.37059"
|
||||||
|
width="157.5838"
|
||||||
|
id="rect4722" /></flowRegion><flowPara
|
||||||
|
id="flowPara4724" /></flowRoot>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
148
android/icons/place_btn.svg
Normal file
148
android/icons/place_btn.svg
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
inkscape:export-ydpi="24.000002"
|
||||||
|
inkscape:export-xdpi="24.000002"
|
||||||
|
inkscape:export-filename="../../textures/base/pack/place_btn.png"
|
||||||
|
sodipodi:docname="place_btn.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 135.46666 135.46667"
|
||||||
|
height="512"
|
||||||
|
width="512"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:snap-others="true"
|
||||||
|
inkscape:snap-object-midpoints="false"
|
||||||
|
inkscape:snap-to-guides="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:snap-page="true"
|
||||||
|
inkscape:snap-grids="false"
|
||||||
|
inkscape:pagecheckerboard="false"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:current-layer="layer2"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:cy="266.84627"
|
||||||
|
inkscape:cx="201.24514"
|
||||||
|
inkscape:zoom="1.4633894"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#404040"
|
||||||
|
id="base"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:deskcolor="#d1d1d1">
|
||||||
|
<inkscape:grid
|
||||||
|
empopacity="0.25098039"
|
||||||
|
empcolor="#40ff40"
|
||||||
|
opacity="0.1254902"
|
||||||
|
color="#40ff40"
|
||||||
|
empspacing="4"
|
||||||
|
spacingy="0.26458333"
|
||||||
|
spacingx="0.26458333"
|
||||||
|
id="grid16"
|
||||||
|
type="xygrid"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
units="px"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
inkscape:label="Layer 2"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7055"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7035"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7005"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5127"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<text
|
||||||
|
transform="scale(1.0078883,0.99217343)"
|
||||||
|
id="text4716"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.4785px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
xml:space="preserve"><tspan
|
||||||
|
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
id="tspan4714"
|
||||||
|
sodipodi:role="line">RMB</tspan></text>
|
||||||
|
<flowRoot
|
||||||
|
transform="scale(0.26458333)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRoot4718"
|
||||||
|
xml:space="preserve"><flowRegion
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRegion4720"><rect
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
y="124.10143"
|
||||||
|
x="264.65997"
|
||||||
|
height="136.37059"
|
||||||
|
width="157.5838"
|
||||||
|
id="rect4722" /></flowRegion><flowPara
|
||||||
|
id="flowPara4724" /></flowRoot>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
|
@ -52,7 +52,7 @@ if (new File(depsDir, 'armeabi-v7a').exists()) {
|
||||||
task downloadDeps(type: Download) {
|
task downloadDeps(type: Download) {
|
||||||
def depsZip = new File(buildDir, 'deps.zip')
|
def depsZip = new File(buildDir, 'deps.zip')
|
||||||
|
|
||||||
src 'https://github.com/minetest/minetest_android_deps/releases/download/latest/deps-lite.zip'
|
src 'https://github.com/luanti-org/luanti_android_deps/releases/download/latest/deps-lite.zip'
|
||||||
dest depsZip
|
dest depsZip
|
||||||
overwrite false
|
overwrite false
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ do
|
||||||
all.registered_craftitems = {}
|
all.registered_craftitems = {}
|
||||||
all.registered_tools = {}
|
all.registered_tools = {}
|
||||||
for k, v in pairs(all.registered_items) do
|
for k, v in pairs(all.registered_items) do
|
||||||
-- Disable further modification
|
-- Ignore new keys
|
||||||
setmetatable(v, {__newindex = {}})
|
setmetatable(v, {__newindex = function() end})
|
||||||
-- Reassemble the other tables
|
-- Reassemble the other tables
|
||||||
if v.type == "node" then
|
if v.type == "node" then
|
||||||
getmetatable(v).__index = all.nodedef_default
|
getmetatable(v).__index = all.nodedef_default
|
||||||
|
@ -59,6 +59,9 @@ end
|
||||||
local alias_metatable = {
|
local alias_metatable = {
|
||||||
__index = function(t, name)
|
__index = function(t, name)
|
||||||
return rawget(t, core.registered_aliases[name])
|
return rawget(t, core.registered_aliases[name])
|
||||||
|
end,
|
||||||
|
__newindex = function()
|
||||||
|
error("table is read-only")
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
setmetatable(core.registered_items, alias_metatable)
|
setmetatable(core.registered_items, alias_metatable)
|
||||||
|
|
|
@ -2,7 +2,10 @@ local scriptpath = core.get_builtin_path()
|
||||||
local clientpath = scriptpath.."client"..DIR_DELIM
|
local clientpath = scriptpath.."client"..DIR_DELIM
|
||||||
local commonpath = scriptpath.."common"..DIR_DELIM
|
local commonpath = scriptpath.."common"..DIR_DELIM
|
||||||
|
|
||||||
dofile(clientpath .. "register.lua")
|
local builtin_shared = {}
|
||||||
|
|
||||||
|
assert(loadfile(commonpath .. "register.lua"))(builtin_shared)
|
||||||
|
assert(loadfile(clientpath .. "register.lua"))(builtin_shared)
|
||||||
dofile(commonpath .. "after.lua")
|
dofile(commonpath .. "after.lua")
|
||||||
dofile(commonpath .. "mod_storage.lua")
|
dofile(commonpath .. "mod_storage.lua")
|
||||||
dofile(commonpath .. "chatcommands.lua")
|
dofile(commonpath .. "chatcommands.lua")
|
||||||
|
|
|
@ -1,68 +1,6 @@
|
||||||
core.callback_origins = {}
|
local builtin_shared = ...
|
||||||
|
|
||||||
local getinfo = debug.getinfo
|
local make_registration = builtin_shared.make_registration
|
||||||
debug.getinfo = nil
|
|
||||||
|
|
||||||
--- Runs given callbacks.
|
|
||||||
--
|
|
||||||
-- Note: this function is also called from C++
|
|
||||||
-- @tparam table callbacks a table with registered callbacks, like `core.registered_on_*`
|
|
||||||
-- @tparam number mode a RunCallbacksMode, as defined in src/script/common/c_internal.h
|
|
||||||
-- @param ... arguments for the callback
|
|
||||||
-- @return depends on mode
|
|
||||||
function core.run_callbacks(callbacks, mode, ...)
|
|
||||||
assert(type(callbacks) == "table")
|
|
||||||
local cb_len = #callbacks
|
|
||||||
if cb_len == 0 then
|
|
||||||
if mode == 2 or mode == 3 then
|
|
||||||
return true
|
|
||||||
elseif mode == 4 or mode == 5 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local ret
|
|
||||||
for i = 1, cb_len do
|
|
||||||
local cb_ret = callbacks[i](...)
|
|
||||||
|
|
||||||
if mode == 0 and i == 1 or mode == 1 and i == cb_len then
|
|
||||||
ret = cb_ret
|
|
||||||
elseif mode == 2 then
|
|
||||||
if not cb_ret or i == 1 then
|
|
||||||
ret = cb_ret
|
|
||||||
end
|
|
||||||
elseif mode == 3 then
|
|
||||||
if cb_ret then
|
|
||||||
return cb_ret
|
|
||||||
end
|
|
||||||
ret = cb_ret
|
|
||||||
elseif mode == 4 then
|
|
||||||
if (cb_ret and not ret) or i == 1 then
|
|
||||||
ret = cb_ret
|
|
||||||
end
|
|
||||||
elseif mode == 5 and cb_ret then
|
|
||||||
return cb_ret
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Callback registration
|
|
||||||
--
|
|
||||||
|
|
||||||
local function make_registration()
|
|
||||||
local t = {}
|
|
||||||
local registerfunc = function(func)
|
|
||||||
t[#t + 1] = func
|
|
||||||
core.callback_origins[func] = {
|
|
||||||
mod = core.get_current_modname() or "??",
|
|
||||||
name = getinfo(1, "n").name or "??"
|
|
||||||
}
|
|
||||||
--local origin = core.callback_origins[func]
|
|
||||||
--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
|
|
||||||
end
|
|
||||||
return t, registerfunc
|
|
||||||
end
|
|
||||||
|
|
||||||
core.registered_globalsteps, core.register_globalstep = make_registration()
|
core.registered_globalsteps, core.register_globalstep = make_registration()
|
||||||
core.registered_on_mods_loaded, core.register_on_mods_loaded = make_registration()
|
core.registered_on_mods_loaded, core.register_on_mods_loaded = make_registration()
|
||||||
|
|
|
@ -90,7 +90,7 @@ local facedir_to_dir_map = {
|
||||||
1, 4, 3, 2,
|
1, 4, 3, 2,
|
||||||
}
|
}
|
||||||
function core.facedir_to_dir(facedir)
|
function core.facedir_to_dir(facedir)
|
||||||
return facedir_to_dir[facedir_to_dir_map[facedir % 32]]
|
return vector.copy(facedir_to_dir[facedir_to_dir_map[facedir % 32]])
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.dir_to_fourdir(dir)
|
function core.dir_to_fourdir(dir)
|
||||||
|
@ -110,7 +110,7 @@ function core.dir_to_fourdir(dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.fourdir_to_dir(fourdir)
|
function core.fourdir_to_dir(fourdir)
|
||||||
return facedir_to_dir[facedir_to_dir_map[fourdir % 4]]
|
return vector.copy(facedir_to_dir[facedir_to_dir_map[fourdir % 4]])
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.dir_to_wallmounted(dir)
|
function core.dir_to_wallmounted(dir)
|
||||||
|
@ -147,7 +147,7 @@ local wallmounted_to_dir = {
|
||||||
vector.new( 0, -1, 0),
|
vector.new( 0, -1, 0),
|
||||||
}
|
}
|
||||||
function core.wallmounted_to_dir(wallmounted)
|
function core.wallmounted_to_dir(wallmounted)
|
||||||
return wallmounted_to_dir[wallmounted % 8]
|
return vector.copy(wallmounted_to_dir[wallmounted % 8])
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.dir_to_yaw(dir)
|
function core.dir_to_yaw(dir)
|
||||||
|
|
|
@ -457,18 +457,37 @@ do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
function table.copy(t, seen)
|
local function table_copy(value, preserve_metatables)
|
||||||
local n = {}
|
local seen = {}
|
||||||
seen = seen or {}
|
local function copy(val)
|
||||||
seen[t] = n
|
if type(val) ~= "table" then
|
||||||
for k, v in pairs(t) do
|
return val
|
||||||
n[(type(k) == "table" and (seen[k] or table.copy(k, seen))) or k] =
|
|
||||||
(type(v) == "table" and (seen[v] or table.copy(v, seen))) or v
|
|
||||||
end
|
end
|
||||||
return n
|
local t = val
|
||||||
|
if seen[t] then
|
||||||
|
return seen[t]
|
||||||
|
end
|
||||||
|
local res = {}
|
||||||
|
seen[t] = res
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
res[copy(k)] = copy(v)
|
||||||
|
end
|
||||||
|
if preserve_metatables then
|
||||||
|
setmetatable(res, getmetatable(t))
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
return copy(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.copy(value)
|
||||||
|
return table_copy(value, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function table.copy_with_metatables(value)
|
||||||
|
return table_copy(value, true)
|
||||||
|
end
|
||||||
|
|
||||||
function table.insert_all(t, other)
|
function table.insert_all(t, other)
|
||||||
if table.move then -- LuaJIT
|
if table.move then -- LuaJIT
|
||||||
|
|
|
@ -54,7 +54,8 @@ function builtin_shared.make_registration()
|
||||||
local registerfunc = function(func)
|
local registerfunc = function(func)
|
||||||
t[#t + 1] = func
|
t[#t + 1] = func
|
||||||
core.callback_origins[func] = {
|
core.callback_origins[func] = {
|
||||||
mod = core.get_current_modname() or "??",
|
-- may be nil or return nil
|
||||||
|
mod = core.get_current_modname and core.get_current_modname() or "??",
|
||||||
name = debug.getinfo(1, "n").name or "??"
|
name = debug.getinfo(1, "n").name or "??"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -66,7 +67,8 @@ function builtin_shared.make_registration_reverse()
|
||||||
local registerfunc = function(func)
|
local registerfunc = function(func)
|
||||||
table.insert(t, 1, func)
|
table.insert(t, 1, func)
|
||||||
core.callback_origins[func] = {
|
core.callback_origins[func] = {
|
||||||
mod = core.get_current_modname() or "??",
|
-- may be nil or return nil
|
||||||
|
mod = core.get_current_modname and core.get_current_modname() or "??",
|
||||||
name = debug.getinfo(1, "n").name or "??"
|
name = debug.getinfo(1, "n").name or "??"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -98,6 +98,7 @@ local function make_field(converter, validator, stringifier)
|
||||||
local fs = ("field[0,0.3;%f,0.8;%s;%s;%s]"):format(
|
local fs = ("field[0,0.3;%f,0.8;%s;%s;%s]"):format(
|
||||||
avail_w - 1.5, setting.name, get_label(setting), core.formspec_escape(value))
|
avail_w - 1.5, setting.name, get_label(setting), core.formspec_escape(value))
|
||||||
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name)
|
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name)
|
||||||
|
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name) -- for pause menu env
|
||||||
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 1.5, "set_" .. setting.name, fgettext("Set"))
|
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 1.5, "set_" .. setting.name, fgettext("Set"))
|
||||||
|
|
||||||
return fs, 1.1
|
return fs, 1.1
|
||||||
|
@ -217,6 +218,8 @@ local function make_path(setting)
|
||||||
|
|
||||||
local fs = ("field[0,0.3;%f,0.8;%s;%s;%s]"):format(
|
local fs = ("field[0,0.3;%f,0.8;%s;%s;%s]"):format(
|
||||||
avail_w - 3, setting.name, get_label(setting), core.formspec_escape(value))
|
avail_w - 3, setting.name, get_label(setting), core.formspec_escape(value))
|
||||||
|
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name)
|
||||||
|
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name) -- for pause menu env
|
||||||
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 3, "pick_" .. setting.name, fgettext("Browse"))
|
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 3, "pick_" .. setting.name, fgettext("Browse"))
|
||||||
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 1.5, "set_" .. setting.name, fgettext("Set"))
|
fs = fs .. ("button[%f,0.3;1.5,0.8;%s;%s]"):format(avail_w - 1.5, "set_" .. setting.name, fgettext("Set"))
|
||||||
|
|
||||||
|
@ -249,8 +252,11 @@ local function make_path(setting)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
if PLATFORM == "Android" then
|
if PLATFORM == "Android" or INIT == "pause_menu" then
|
||||||
-- The Irrlicht file picker doesn't work on Android.
|
-- The Irrlicht file picker doesn't work on Android.
|
||||||
|
-- Access to the Irrlicht file picker isn't implemented in the pause menu.
|
||||||
|
-- We want to delete the Irrlicht file picker anyway, so any time spent on
|
||||||
|
-- that would be wasted.
|
||||||
make.path = make.string
|
make.path = make.string
|
||||||
make.filepath = make.string
|
make.filepath = make.string
|
||||||
else
|
else
|
||||||
|
@ -282,6 +288,14 @@ function make.v3f(setting)
|
||||||
fs = fs .. ("field[%f,0.6;%f,0.8;%s;%s;%s]"):format(
|
fs = fs .. ("field[%f,0.6;%f,0.8;%s;%s;%s]"):format(
|
||||||
2 * (field_width + 0.25), field_width, setting.name .. "_z", "Z", value.z)
|
2 * (field_width + 0.25), field_width, setting.name .. "_z", "Z", value.z)
|
||||||
|
|
||||||
|
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name .. "_x")
|
||||||
|
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name .. "_y")
|
||||||
|
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name .. "_z")
|
||||||
|
-- for pause menu env
|
||||||
|
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name .. "_x")
|
||||||
|
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name .. "_y")
|
||||||
|
fs = fs .. ("field_close_on_enter[%s;false]"):format(setting.name .. "_z")
|
||||||
|
|
||||||
fs = fs .. ("button[%f,0.6;1,0.8;%s;%s]"):format(avail_w, "set_" .. setting.name, fgettext("Set"))
|
fs = fs .. ("button[%f,0.6;1,0.8;%s;%s]"):format(avail_w, "set_" .. setting.name, fgettext("Set"))
|
||||||
|
|
||||||
return fs, 1.4
|
return fs, 1.4
|
||||||
|
@ -428,8 +442,22 @@ local function make_noise_params(setting)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if INIT == "pause_menu" then
|
||||||
|
-- Making the noise parameter dialog work in the pause menu settings would
|
||||||
|
-- require porting "FSTK" (at least the dialog API) from the mainmenu formspec
|
||||||
|
-- API to the in-game formspec API.
|
||||||
|
-- There's no reason you'd want to adjust mapgen noise parameter settings
|
||||||
|
-- in-game (they only apply to new worlds, hidden as [world_creation]),
|
||||||
|
-- so there's no reason to implement this.
|
||||||
|
local empty = function()
|
||||||
|
return { get_formspec = function() return "", 0 end }
|
||||||
|
end
|
||||||
|
make.noise_params_2d = empty
|
||||||
|
make.noise_params_3d = empty
|
||||||
|
else
|
||||||
make.noise_params_2d = make_noise_params
|
make.noise_params_2d = make_noise_params
|
||||||
make.noise_params_3d = make_noise_params
|
make.noise_params_3d = make_noise_params
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
return make
|
return make
|
|
@ -16,11 +16,10 @@
|
||||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
|
||||||
local component_funcs = dofile(core.get_mainmenu_path() .. DIR_DELIM ..
|
local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM
|
||||||
"settings" .. DIR_DELIM .. "components.lua")
|
|
||||||
|
|
||||||
local shadows_component = dofile(core.get_mainmenu_path() .. DIR_DELIM ..
|
local component_funcs = dofile(path .. "components.lua")
|
||||||
"settings" .. DIR_DELIM .. "shadows_component.lua")
|
local shadows_component = dofile(path .. "shadows_component.lua")
|
||||||
|
|
||||||
local loaded = false
|
local loaded = false
|
||||||
local full_settings
|
local full_settings
|
||||||
|
@ -110,8 +109,9 @@ local function load()
|
||||||
local change_keys = {
|
local change_keys = {
|
||||||
query_text = "Controls",
|
query_text = "Controls",
|
||||||
requires = {
|
requires = {
|
||||||
touch_controls = false,
|
keyboard_mouse = true,
|
||||||
},
|
},
|
||||||
|
context = "client",
|
||||||
get_formspec = function(self, avail_w)
|
get_formspec = function(self, avail_w)
|
||||||
local btn_w = math.min(avail_w, 3)
|
local btn_w = math.min(avail_w, 3)
|
||||||
return ("button[0,0;%f,0.8;btn_change_keys;%s]"):format(btn_w, fgettext("Controls")), 0.8
|
return ("button[0,0;%f,0.8;btn_change_keys;%s]"):format(btn_w, fgettext("Controls")), 0.8
|
||||||
|
@ -128,6 +128,7 @@ local function load()
|
||||||
requires = {
|
requires = {
|
||||||
touchscreen = true,
|
touchscreen = true,
|
||||||
},
|
},
|
||||||
|
context = "client",
|
||||||
get_formspec = function(self, avail_w)
|
get_formspec = function(self, avail_w)
|
||||||
local btn_w = math.min(avail_w, 6)
|
local btn_w = math.min(avail_w, 6)
|
||||||
return ("button[0,0;%f,0.8;btn_touch_layout;%s]"):format(btn_w, fgettext("Touchscreen layout")), 0.8
|
return ("button[0,0;%f,0.8;btn_touch_layout;%s]"):format(btn_w, fgettext("Touchscreen layout")), 0.8
|
||||||
|
@ -160,7 +161,6 @@ local function load()
|
||||||
{ heading = fgettext_ne("Movement") },
|
{ heading = fgettext_ne("Movement") },
|
||||||
"arm_inertia",
|
"arm_inertia",
|
||||||
"view_bobbing_amount",
|
"view_bobbing_amount",
|
||||||
"fall_bobbing_amount",
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -175,18 +175,24 @@ local function load()
|
||||||
table.insert(content, idx, shadows_component)
|
table.insert(content, idx, shadows_component)
|
||||||
|
|
||||||
idx = table.indexof(content, "enable_auto_exposure") + 1
|
idx = table.indexof(content, "enable_auto_exposure") + 1
|
||||||
|
local setting_info = get_setting_info("enable_auto_exposure")
|
||||||
local note = component_funcs.note(fgettext_ne("(The game will need to enable automatic exposure as well)"))
|
local note = component_funcs.note(fgettext_ne("(The game will need to enable automatic exposure as well)"))
|
||||||
note.requires = get_setting_info("enable_auto_exposure").requires
|
note.requires = setting_info.requires
|
||||||
|
note.context = setting_info.context
|
||||||
table.insert(content, idx, note)
|
table.insert(content, idx, note)
|
||||||
|
|
||||||
idx = table.indexof(content, "enable_bloom") + 1
|
idx = table.indexof(content, "enable_bloom") + 1
|
||||||
|
setting_info = get_setting_info("enable_bloom")
|
||||||
note = component_funcs.note(fgettext_ne("(The game will need to enable bloom as well)"))
|
note = component_funcs.note(fgettext_ne("(The game will need to enable bloom as well)"))
|
||||||
note.requires = get_setting_info("enable_bloom").requires
|
note.requires = setting_info.requires
|
||||||
|
note.context = setting_info.context
|
||||||
table.insert(content, idx, note)
|
table.insert(content, idx, note)
|
||||||
|
|
||||||
idx = table.indexof(content, "enable_volumetric_lighting") + 1
|
idx = table.indexof(content, "enable_volumetric_lighting") + 1
|
||||||
|
setting_info = get_setting_info("enable_volumetric_lighting")
|
||||||
note = component_funcs.note(fgettext_ne("(The game will need to enable volumetric lighting as well)"))
|
note = component_funcs.note(fgettext_ne("(The game will need to enable volumetric lighting as well)"))
|
||||||
note.requires = get_setting_info("enable_volumetric_lighting").requires
|
note.requires = setting_info.requires
|
||||||
|
note.context = setting_info.context
|
||||||
table.insert(content, idx, note)
|
table.insert(content, idx, note)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -261,6 +267,17 @@ local function load()
|
||||||
["true"] = fgettext_ne("Enabled"),
|
["true"] = fgettext_ne("Enabled"),
|
||||||
["false"] = fgettext_ne("Disabled"),
|
["false"] = fgettext_ne("Disabled"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_setting_info("touch_interaction_style").option_labels = {
|
||||||
|
["tap"] = fgettext_ne("Tap"),
|
||||||
|
["tap_crosshair"] = fgettext_ne("Tap with crosshair"),
|
||||||
|
["buttons_crosshair"] = fgettext("Buttons with crosshair"),
|
||||||
|
}
|
||||||
|
|
||||||
|
get_setting_info("touch_punch_gesture").option_labels = {
|
||||||
|
["short_tap"] = fgettext_ne("Short tap"),
|
||||||
|
["long_tap"] = fgettext_ne("Long tap"),
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,7 +370,18 @@ local function update_filtered_pages(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function check_requirements(name, requires)
|
local shown_contexts = {
|
||||||
|
common = true,
|
||||||
|
client = true,
|
||||||
|
server = INIT ~= "pause_menu" or core.is_internal_server(),
|
||||||
|
world_creation = INIT ~= "pause_menu",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function check_requirements(name, requires, context)
|
||||||
|
if context and not shown_contexts[context] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
if requires == nil then
|
if requires == nil then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -361,6 +389,7 @@ local function check_requirements(name, requires)
|
||||||
local video_driver = core.get_active_driver()
|
local video_driver = core.get_active_driver()
|
||||||
local touch_support = core.irrlicht_device_supports_touch()
|
local touch_support = core.irrlicht_device_supports_touch()
|
||||||
local touch_controls = core.settings:get("touch_controls")
|
local touch_controls = core.settings:get("touch_controls")
|
||||||
|
local touch_interaction_style = core.settings:get("touch_interaction_style")
|
||||||
local special = {
|
local special = {
|
||||||
android = PLATFORM == "Android",
|
android = PLATFORM == "Android",
|
||||||
desktop = PLATFORM ~= "Android",
|
desktop = PLATFORM ~= "Android",
|
||||||
|
@ -371,6 +400,7 @@ local function check_requirements(name, requires)
|
||||||
keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)),
|
keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)),
|
||||||
opengl = (video_driver == "opengl" or video_driver == "opengl3"),
|
opengl = (video_driver == "opengl" or video_driver == "opengl3"),
|
||||||
gles = video_driver:sub(1, 5) == "ogles",
|
gles = video_driver:sub(1, 5) == "ogles",
|
||||||
|
touch_interaction_style_tap = touch_interaction_style ~= "buttons_crosshair",
|
||||||
}
|
}
|
||||||
|
|
||||||
for req_key, req_value in pairs(requires) do
|
for req_key, req_value in pairs(requires) do
|
||||||
|
@ -378,6 +408,9 @@ local function check_requirements(name, requires)
|
||||||
local required_setting = get_setting_info(req_key)
|
local required_setting = get_setting_info(req_key)
|
||||||
if required_setting == nil then
|
if required_setting == nil then
|
||||||
core.log("warning", "Unknown setting " .. req_key .. " required by " .. (name or "???"))
|
core.log("warning", "Unknown setting " .. req_key .. " required by " .. (name or "???"))
|
||||||
|
elseif required_setting.type ~= "bool" then
|
||||||
|
core.log("warning", "Setting " .. req_key .. " of type " .. required_setting.type ..
|
||||||
|
" used as requirement by " .. (name or "???") .. ", only bool is allowed")
|
||||||
end
|
end
|
||||||
local actual_value = core.settings:get_bool(req_key,
|
local actual_value = core.settings:get_bool(req_key,
|
||||||
required_setting and core.is_yes(required_setting.default))
|
required_setting and core.is_yes(required_setting.default))
|
||||||
|
@ -409,11 +442,11 @@ function page_has_contents(page, actual_content)
|
||||||
elseif type(item) == "string" then
|
elseif type(item) == "string" then
|
||||||
local setting = get_setting_info(item)
|
local setting = get_setting_info(item)
|
||||||
assert(setting, "Unknown setting: " .. item)
|
assert(setting, "Unknown setting: " .. item)
|
||||||
if check_requirements(setting.name, setting.requires) then
|
if check_requirements(setting.name, setting.requires, setting.context) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
elseif item.get_formspec then
|
elseif item.get_formspec then
|
||||||
if check_requirements(item.id, item.requires) then
|
if check_requirements(item.id, item.requires, item.context) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -435,20 +468,22 @@ local function build_page_components(page)
|
||||||
elseif item.heading then
|
elseif item.heading then
|
||||||
last_heading = item
|
last_heading = item
|
||||||
else
|
else
|
||||||
local name, requires
|
local name, requires, context
|
||||||
if type(item) == "string" then
|
if type(item) == "string" then
|
||||||
local setting = get_setting_info(item)
|
local setting = get_setting_info(item)
|
||||||
assert(setting, "Unknown setting: " .. item)
|
assert(setting, "Unknown setting: " .. item)
|
||||||
name = setting.name
|
name = setting.name
|
||||||
requires = setting.requires
|
requires = setting.requires
|
||||||
|
context = setting.context
|
||||||
elseif item.get_formspec then
|
elseif item.get_formspec then
|
||||||
name = item.id
|
name = item.id
|
||||||
requires = item.requires
|
requires = item.requires
|
||||||
|
context = item.context
|
||||||
else
|
else
|
||||||
error("Unknown content in page: " .. dump(item))
|
error("Unknown content in page: " .. dump(item))
|
||||||
end
|
end
|
||||||
|
|
||||||
if check_requirements(name, requires) then
|
if check_requirements(name, requires, context) then
|
||||||
if last_heading then
|
if last_heading then
|
||||||
content[#content + 1] = last_heading
|
content[#content + 1] = last_heading
|
||||||
last_heading = nil
|
last_heading = nil
|
||||||
|
@ -514,7 +549,8 @@ local function get_formspec(dialogdata)
|
||||||
"box[0,0;", tostring(tabsize.width), ",", tostring(tabsize.height), ";#0000008C]",
|
"box[0,0;", tostring(tabsize.width), ",", tostring(tabsize.height), ";#0000008C]",
|
||||||
|
|
||||||
("button[0,%f;%f,0.8;back;%s]"):format(
|
("button[0,%f;%f,0.8;back;%s]"):format(
|
||||||
tabsize.height + 0.2, back_w, fgettext("Back")),
|
tabsize.height + 0.2, back_w,
|
||||||
|
INIT == "pause_menu" and fgettext("Exit") or fgettext("Back")),
|
||||||
|
|
||||||
("box[%f,%f;%f,0.8;#0000008C]"):format(
|
("box[%f,%f;%f,0.8;#0000008C]"):format(
|
||||||
back_w + 0.2, tabsize.height + 0.2, checkbox_w),
|
back_w + 0.2, tabsize.height + 0.2, checkbox_w),
|
||||||
|
@ -531,6 +567,7 @@ local function get_formspec(dialogdata)
|
||||||
"field[0.25,0.25;", tostring(search_width), ",0.75;search_query;;",
|
"field[0.25,0.25;", tostring(search_width), ",0.75;search_query;;",
|
||||||
core.formspec_escape(dialogdata.query or ""), "]",
|
core.formspec_escape(dialogdata.query or ""), "]",
|
||||||
"field_enter_after_edit[search_query;true]",
|
"field_enter_after_edit[search_query;true]",
|
||||||
|
"field_close_on_enter[search_query;false]", -- for pause menu env
|
||||||
"container[", tostring(search_width + 0.25), ", 0.25]",
|
"container[", tostring(search_width + 0.25), ", 0.25]",
|
||||||
"image_button[0,0;0.75,0.75;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
|
"image_button[0,0;0.75,0.75;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
|
||||||
"image_button[0.75,0;0.75,0.75;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";search_clear;]",
|
"image_button[0.75,0;0.75,0.75;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";search_clear;]",
|
||||||
|
@ -671,7 +708,8 @@ local function buttonhandler(this, fields)
|
||||||
dialogdata.rightscroll = core.explode_scrollbar_event(fields.rightscroll).value or dialogdata.rightscroll
|
dialogdata.rightscroll = core.explode_scrollbar_event(fields.rightscroll).value or dialogdata.rightscroll
|
||||||
dialogdata.query = fields.search_query
|
dialogdata.query = fields.search_query
|
||||||
|
|
||||||
if fields.back then
|
-- "fields.quit" is for the pause menu env
|
||||||
|
if fields.back or fields.quit then
|
||||||
this:delete()
|
this:delete()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -765,6 +803,7 @@ local function eventhandler(event)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if INIT == "mainmenu" then
|
||||||
function create_settings_dlg()
|
function create_settings_dlg()
|
||||||
load()
|
load()
|
||||||
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
|
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
|
||||||
|
@ -773,3 +812,35 @@ function create_settings_dlg()
|
||||||
|
|
||||||
return dlg
|
return dlg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
assert(INIT == "pause_menu")
|
||||||
|
|
||||||
|
local dialog
|
||||||
|
|
||||||
|
core.register_on_formspec_input(function(formname, fields)
|
||||||
|
if dialog and formname == "__builtin:settings" then
|
||||||
|
-- buttonhandler returning true means we should update the formspec.
|
||||||
|
-- dialog is re-checked since the buttonhandler may have closed it.
|
||||||
|
if buttonhandler(dialog, fields) and dialog then
|
||||||
|
core.show_formspec("__builtin:settings", get_formspec(dialog.data))
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
core.open_settings = function()
|
||||||
|
load()
|
||||||
|
dialog = {}
|
||||||
|
dialog.data = {}
|
||||||
|
dialog.data.page_id = update_filtered_pages("")
|
||||||
|
dialog.delete = function()
|
||||||
|
dialog = nil
|
||||||
|
-- only needed for the "fields.back" case, in the "fields.quit"
|
||||||
|
-- case it's a no-op
|
||||||
|
core.show_formspec("__builtin:settings", "")
|
||||||
|
end
|
||||||
|
|
||||||
|
core.show_formspec("__builtin:settings", get_formspec(dialog.data))
|
||||||
|
end
|
||||||
|
end
|
|
@ -61,7 +61,7 @@ local function create_minetest_conf_example(settings)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if entry.type == "key" then
|
if entry.type == "key" then
|
||||||
local line = "See https://github.com/minetest/irrlicht/blob/master/include/Keycodes.h"
|
local line = "See https://github.com/luanti-org/luanti/blob/master/irr/include/Keycodes.h"
|
||||||
insert(result, "# " .. line .. "\n")
|
insert(result, "# " .. line .. "\n")
|
||||||
end
|
end
|
||||||
insert(result, "# type: " .. entry.type)
|
insert(result, "# type: " .. entry.type)
|
|
@ -15,11 +15,11 @@
|
||||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
local path = core.get_mainmenu_path() .. DIR_DELIM .. "settings"
|
local path = core.get_builtin_path() .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM
|
||||||
|
|
||||||
dofile(path .. DIR_DELIM .. "settingtypes.lua")
|
dofile(path .. "settingtypes.lua")
|
||||||
dofile(path .. DIR_DELIM .. "dlg_change_mapgen_flags.lua")
|
dofile(path .. "dlg_change_mapgen_flags.lua")
|
||||||
dofile(path .. DIR_DELIM .. "dlg_settings.lua")
|
dofile(path .. "dlg_settings.lua")
|
||||||
|
|
||||||
-- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
|
-- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
|
||||||
-- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
|
-- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
|
|
@ -40,12 +40,24 @@ local CHAR_CLASSES = {
|
||||||
FLAGS = "[%w_%-%.,]",
|
FLAGS = "[%w_%-%.,]",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local valid_contexts = {common = true, client = true, server = true, world_creation = true}
|
||||||
|
|
||||||
|
local function check_context_annotation(context, force_context)
|
||||||
|
if force_context then
|
||||||
|
return "Context annotations are not allowed, context is always " .. force_context
|
||||||
|
end
|
||||||
|
if not valid_contexts[context] then
|
||||||
|
return "Unknown context"
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
local function flags_to_table(flags)
|
local function flags_to_table(flags)
|
||||||
return flags:gsub("%s+", ""):split(",", true) -- Remove all spaces and split
|
return flags:gsub("%s+", ""):split(",", true) -- Remove all spaces and split
|
||||||
end
|
end
|
||||||
|
|
||||||
-- returns error message, or nil
|
-- returns error message, or nil
|
||||||
local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
|
local function parse_setting_line(settings, line, read_all, base_level, allow_secure, force_context)
|
||||||
|
|
||||||
-- strip carriage returns (CR, /r)
|
-- strip carriage returns (CR, /r)
|
||||||
line = line:gsub("\r", "")
|
line = line:gsub("\r", "")
|
||||||
|
@ -69,9 +81,32 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
|
|
||||||
-- category
|
-- category
|
||||||
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
|
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
|
||||||
|
local category_context
|
||||||
|
if not category then
|
||||||
|
stars, category, category_context = line:match("^%[([%*]*)([^%]]+)%] %[([^%]]+)%]$")
|
||||||
|
end
|
||||||
if category then
|
if category then
|
||||||
local category_level = stars:len() + base_level
|
local category_level = stars:len() + base_level
|
||||||
|
|
||||||
|
if settings.current_context_level and
|
||||||
|
category_level <= settings.current_context_level then
|
||||||
|
-- The start of this category marks the end of the context annotation's scope.
|
||||||
|
settings.current_context_level = nil
|
||||||
|
settings.current_context = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if category_context then
|
||||||
|
local err = check_context_annotation(category_context, force_context)
|
||||||
|
if err then
|
||||||
|
return err
|
||||||
|
end
|
||||||
|
if settings.current_context_level then
|
||||||
|
return "Category context annotations cannot be nested"
|
||||||
|
end
|
||||||
|
settings.current_context_level = category_level
|
||||||
|
settings.current_context = category_context
|
||||||
|
end
|
||||||
|
|
||||||
if settings.current_hide_level then
|
if settings.current_hide_level then
|
||||||
if settings.current_hide_level < category_level then
|
if settings.current_hide_level < category_level then
|
||||||
-- Skip this category, it's inside a hidden category.
|
-- Skip this category, it's inside a hidden category.
|
||||||
|
@ -102,7 +137,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
end
|
end
|
||||||
|
|
||||||
-- settings
|
-- settings
|
||||||
local first_part, name, readable_name, setting_type = line:match("^"
|
local function make_pattern(include_context)
|
||||||
|
return "^"
|
||||||
-- this first capture group matches the whole first part,
|
-- this first capture group matches the whole first part,
|
||||||
-- so we can later strip it from the rest of the line
|
-- so we can later strip it from the rest of the line
|
||||||
.. "("
|
.. "("
|
||||||
|
@ -110,9 +146,19 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
.. CHAR_CLASSES.SPACE .. "*"
|
.. CHAR_CLASSES.SPACE .. "*"
|
||||||
.. "%(([^%)]*)%)" -- readable name
|
.. "%(([^%)]*)%)" -- readable name
|
||||||
.. CHAR_CLASSES.SPACE .. "*"
|
.. CHAR_CLASSES.SPACE .. "*"
|
||||||
|
.. (include_context and (
|
||||||
|
"%[([^%]]+)%]" -- context annotation
|
||||||
|
.. CHAR_CLASSES.SPACE .. "*"
|
||||||
|
) or "")
|
||||||
.. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type
|
.. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type
|
||||||
.. CHAR_CLASSES.SPACE .. "*"
|
.. CHAR_CLASSES.SPACE .. "*"
|
||||||
.. ")")
|
.. ")"
|
||||||
|
end
|
||||||
|
local first_part, name, readable_name, setting_type = line:match(make_pattern(false))
|
||||||
|
local setting_context
|
||||||
|
if not first_part then
|
||||||
|
first_part, name, readable_name, setting_context, setting_type = line:match(make_pattern(true))
|
||||||
|
end
|
||||||
|
|
||||||
if not first_part then
|
if not first_part then
|
||||||
return "Invalid line"
|
return "Invalid line"
|
||||||
|
@ -122,6 +168,26 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
return "Tried to add \"secure.\" setting"
|
return "Tried to add \"secure.\" setting"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if setting_context then
|
||||||
|
local err = check_context_annotation(setting_context, force_context)
|
||||||
|
if err then
|
||||||
|
return err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local context
|
||||||
|
if force_context then
|
||||||
|
context = force_context
|
||||||
|
else
|
||||||
|
if setting_context then
|
||||||
|
context = setting_context
|
||||||
|
elseif settings.current_context_level then
|
||||||
|
context = settings.current_context
|
||||||
|
else
|
||||||
|
return "Missing context annotation"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local requires = {}
|
local requires = {}
|
||||||
local last_line = #current_comment > 0 and current_comment[#current_comment]:trim()
|
local last_line = #current_comment > 0 and current_comment[#current_comment]:trim()
|
||||||
if last_line and last_line:lower():sub(1, 9) == "requires:" then
|
if last_line and last_line:lower():sub(1, 9) == "requires:" then
|
||||||
|
@ -170,6 +236,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
min = min,
|
min = min,
|
||||||
max = max,
|
max = max,
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -193,6 +260,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
type = setting_type,
|
type = setting_type,
|
||||||
default = default,
|
default = default,
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -245,6 +313,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
},
|
},
|
||||||
values = values,
|
values = values,
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
noise_params = true,
|
noise_params = true,
|
||||||
flags = flags_to_table("defaults,eased,absvalue")
|
flags = flags_to_table("defaults,eased,absvalue")
|
||||||
|
@ -263,6 +332,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
type = "bool",
|
type = "bool",
|
||||||
default = remaining_line,
|
default = remaining_line,
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -290,6 +360,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
min = min,
|
min = min,
|
||||||
max = max,
|
max = max,
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -313,6 +384,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
default = default,
|
default = default,
|
||||||
values = values:split(",", true),
|
values = values:split(",", true),
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -331,6 +403,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
type = setting_type,
|
type = setting_type,
|
||||||
default = default,
|
default = default,
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -361,6 +434,7 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
default = default,
|
default = default,
|
||||||
possible = flags_to_table(possible),
|
possible = flags_to_table(possible),
|
||||||
requires = requires,
|
requires = requires,
|
||||||
|
context = context,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
@ -369,14 +443,14 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
|
||||||
return "Invalid setting type \"" .. setting_type .. "\""
|
return "Invalid setting type \"" .. setting_type .. "\""
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
|
local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure, force_context)
|
||||||
-- store this helper variable in the table so it's easier to pass to parse_setting_line()
|
-- store this helper variable in the table so it's easier to pass to parse_setting_line()
|
||||||
result.current_comment = {}
|
result.current_comment = {}
|
||||||
result.current_hide_level = nil
|
result.current_hide_level = nil
|
||||||
|
|
||||||
local line = file:read("*line")
|
local line = file:read("*line")
|
||||||
while line do
|
while line do
|
||||||
local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure)
|
local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure, force_context)
|
||||||
if error_msg then
|
if error_msg then
|
||||||
core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
|
core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
|
||||||
end
|
end
|
||||||
|
@ -408,7 +482,17 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
||||||
file:close()
|
file:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
if parse_mods then
|
-- TODO: Support game/mod settings in the pause menu too
|
||||||
|
-- Note that this will need to work different from how it's done in the
|
||||||
|
-- mainmenu:
|
||||||
|
-- * ~~Only if in singleplayer / on local server, not on remote servers~~
|
||||||
|
-- (done now: context annotations)
|
||||||
|
-- * Only show settings for the active game and mods
|
||||||
|
-- (add API function to get them, can return nil if on a remote server)
|
||||||
|
-- (names are probably not enough, will need paths for uniqueness)
|
||||||
|
-- This means just making "pkgmgr.lua" work won't get you very far.
|
||||||
|
|
||||||
|
if INIT == "mainmenu" and parse_mods then
|
||||||
-- Parse games
|
-- Parse games
|
||||||
local games_category_initialized = false
|
local games_category_initialized = false
|
||||||
for _, game in ipairs(pkgmgr.games) do
|
for _, game in ipairs(pkgmgr.games) do
|
||||||
|
@ -432,7 +516,7 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
||||||
type = "category",
|
type = "category",
|
||||||
})
|
})
|
||||||
|
|
||||||
parse_single_file(file, path, read_all, settings, 2, false)
|
parse_single_file(file, path, read_all, settings, 2, false, "server")
|
||||||
|
|
||||||
file:close()
|
file:close()
|
||||||
end
|
end
|
||||||
|
@ -465,7 +549,7 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
||||||
type = "category",
|
type = "category",
|
||||||
})
|
})
|
||||||
|
|
||||||
parse_single_file(file, path, read_all, settings, 2, false)
|
parse_single_file(file, path, read_all, settings, 2, false, "server")
|
||||||
|
|
||||||
file:close()
|
file:close()
|
||||||
end
|
end
|
||||||
|
@ -496,7 +580,7 @@ function settingtypes.parse_config_file(read_all, parse_mods)
|
||||||
type = "category",
|
type = "category",
|
||||||
})
|
})
|
||||||
|
|
||||||
parse_single_file(file, path, read_all, settings, 2, false)
|
parse_single_file(file, path, read_all, settings, 2, false, "client")
|
||||||
|
|
||||||
file:close()
|
file:close()
|
||||||
end
|
end
|
|
@ -84,6 +84,7 @@ return {
|
||||||
requires = {
|
requires = {
|
||||||
opengl = true,
|
opengl = true,
|
||||||
},
|
},
|
||||||
|
context = "client",
|
||||||
get_formspec = function(self, avail_w)
|
get_formspec = function(self, avail_w)
|
||||||
local labels = table.copy(shadow_levels_labels)
|
local labels = table.copy(shadow_levels_labels)
|
||||||
local idx = detect_mapping_idx()
|
local idx = detect_mapping_idx()
|
|
@ -178,6 +178,35 @@ describe("table", function()
|
||||||
assert.equal(2, table.keyof({[2] = "foo", [3] = "bar"}, "foo"))
|
assert.equal(2, table.keyof({[2] = "foo", [3] = "bar"}, "foo"))
|
||||||
assert.equal(3, table.keyof({[1] = "foo", [3] = "bar"}, "bar"))
|
assert.equal(3, table.keyof({[1] = "foo", [3] = "bar"}, "bar"))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe("copy()", function()
|
||||||
|
it("strips metatables", function()
|
||||||
|
local v = vector.new(1, 2, 3)
|
||||||
|
local w = table.copy(v)
|
||||||
|
assert.are_not.equal(v, w)
|
||||||
|
assert.same(v, w)
|
||||||
|
assert.equal(nil, getmetatable(w))
|
||||||
|
end)
|
||||||
|
it("preserves referential structure", function()
|
||||||
|
local t = {{}, {}}
|
||||||
|
t[1][1] = t[2]
|
||||||
|
t[2][1] = t[1]
|
||||||
|
local copy = table.copy(t)
|
||||||
|
assert.same(t, copy)
|
||||||
|
assert.equal(copy[1][1], copy[2])
|
||||||
|
assert.equal(copy[2][1], copy[1])
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("copy_with_metatables()", function()
|
||||||
|
it("preserves metatables", function()
|
||||||
|
local v = vector.new(1, 2, 3)
|
||||||
|
local w = table.copy_with_metatables(v)
|
||||||
|
assert.equal(getmetatable(v), getmetatable(w))
|
||||||
|
assert(vector.check(w))
|
||||||
|
assert.equal(v, w) -- vector overrides ==
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("formspec_escape", function()
|
describe("formspec_escape", function()
|
||||||
|
|
|
@ -33,7 +33,7 @@ function core.get_node(pos)
|
||||||
return core.vmanip:get_node_at(pos)
|
return core.vmanip:get_node_at(pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.get_perlin(seed, octaves, persist, spread)
|
function core.get_value_noise(seed, octaves, persist, spread)
|
||||||
local params
|
local params
|
||||||
if type(seed) == "table" then
|
if type(seed) == "table" then
|
||||||
params = table.copy(seed)
|
params = table.copy(seed)
|
||||||
|
@ -47,12 +47,18 @@ function core.get_perlin(seed, octaves, persist, spread)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
params.seed = core.get_seed(params.seed) -- add mapgen seed
|
params.seed = core.get_seed(params.seed) -- add mapgen seed
|
||||||
return PerlinNoise(params)
|
return ValueNoise(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function core.get_value_noise_map(params, size)
|
||||||
function core.get_perlin_map(params, size)
|
|
||||||
local params2 = table.copy(params)
|
local params2 = table.copy(params)
|
||||||
params2.seed = core.get_seed(params.seed) -- add mapgen seed
|
params2.seed = core.get_seed(params.seed) -- add mapgen seed
|
||||||
return PerlinNoiseMap(params2, size)
|
return ValueNoiseMap(params2, size)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- deprecated as of 5.12, as it was not Perlin noise
|
||||||
|
-- but with no warnings (yet) for compatibility
|
||||||
|
core.get_perlin = core.get_value_noise
|
||||||
|
core.get_perlin_map = core.get_value_noise_map
|
||||||
|
PerlinNoise = ValueNoise
|
||||||
|
PerlinNoiseMap = ValueNoiseMap
|
||||||
|
|
|
@ -9,8 +9,8 @@ do
|
||||||
all.registered_craftitems = {}
|
all.registered_craftitems = {}
|
||||||
all.registered_tools = {}
|
all.registered_tools = {}
|
||||||
for k, v in pairs(all.registered_items) do
|
for k, v in pairs(all.registered_items) do
|
||||||
-- Disable further modification
|
-- Ignore new keys
|
||||||
setmetatable(v, {__newindex = {}})
|
setmetatable(v, {__newindex = function() end})
|
||||||
-- Reassemble the other tables
|
-- Reassemble the other tables
|
||||||
if v.type == "node" then
|
if v.type == "node" then
|
||||||
getmetatable(v).__index = all.nodedef_default
|
getmetatable(v).__index = all.nodedef_default
|
||||||
|
@ -36,6 +36,9 @@ end
|
||||||
local alias_metatable = {
|
local alias_metatable = {
|
||||||
__index = function(t, name)
|
__index = function(t, name)
|
||||||
return rawget(t, core.registered_aliases[name])
|
return rawget(t, core.registered_aliases[name])
|
||||||
|
end,
|
||||||
|
__newindex = function()
|
||||||
|
error("table is read-only")
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
setmetatable(core.registered_items, alias_metatable)
|
setmetatable(core.registered_items, alias_metatable)
|
||||||
|
|
|
@ -60,6 +60,8 @@ core.register_on_chat_message(function(name, message)
|
||||||
|
|
||||||
param = param or ""
|
param = param or ""
|
||||||
|
|
||||||
|
core.log("verbose", string.format("Handling chat command %q with params %q", cmd, param))
|
||||||
|
|
||||||
-- Run core.registered_on_chatcommands callbacks.
|
-- Run core.registered_on_chatcommands callbacks.
|
||||||
if core.run_callbacks(core.registered_on_chatcommands, 5, name, cmd, param) then
|
if core.run_callbacks(core.registered_on_chatcommands, 5, name, cmd, param) then
|
||||||
return true
|
return true
|
||||||
|
@ -1275,7 +1277,7 @@ core.register_chatcommand("msg", {
|
||||||
core.log("action", "DM from " .. name .. " to " .. sendto
|
core.log("action", "DM from " .. name .. " to " .. sendto
|
||||||
.. ": " .. message)
|
.. ": " .. message)
|
||||||
core.chat_send_player(sendto, S("DM from @1: @2", name, message))
|
core.chat_send_player(sendto, S("DM from @1: @2", name, message))
|
||||||
return true, S("Message sent.")
|
return true, S("DM sent to @1: @2", sendto, message)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -61,3 +61,10 @@ function core.register_on_auth_fail(func)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- deprecated as of 5.12, as it was not Perlin noise
|
||||||
|
-- but with no warnings (yet) for compatibility
|
||||||
|
core.get_perlin = core.get_value_noise
|
||||||
|
core.get_perlin_map = core.get_value_noise_map
|
||||||
|
PerlinNoise = ValueNoise
|
||||||
|
PerlinNoiseMap = ValueNoiseMap
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
local builtin_shared = ...
|
local builtin_shared = ...
|
||||||
local SCALE = 0.667
|
|
||||||
|
|
||||||
local facedir_to_euler = {
|
local facedir_to_euler = {
|
||||||
{y = 0, x = 0, z = 0},
|
{y = 0, x = 0, z = 0},
|
||||||
|
@ -36,9 +35,7 @@ local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
|
||||||
|
|
||||||
core.register_entity(":__builtin:falling_node", {
|
core.register_entity(":__builtin:falling_node", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
visual = "item",
|
visual = "node",
|
||||||
visual_size = vector.new(SCALE, SCALE, SCALE),
|
|
||||||
textures = {},
|
|
||||||
physical = true,
|
physical = true,
|
||||||
is_visible = false,
|
is_visible = false,
|
||||||
collide_with_objects = true,
|
collide_with_objects = true,
|
||||||
|
@ -80,41 +77,15 @@ core.register_entity(":__builtin:falling_node", {
|
||||||
-- Save liquidtype for falling water
|
-- Save liquidtype for falling water
|
||||||
self.liquidtype = def.liquidtype
|
self.liquidtype = def.liquidtype
|
||||||
|
|
||||||
-- Set entity visuals
|
-- Set up entity visuals
|
||||||
if def.drawtype == "torchlike" or def.drawtype == "signlike" then
|
-- For compatibility with older clients we continue to use "item" visual
|
||||||
local textures
|
-- for simple situations.
|
||||||
if def.tiles and def.tiles[1] then
|
local drawtypes = {normal=true, glasslike=true, allfaces=true, nodebox=true}
|
||||||
local tile = def.tiles[1]
|
local p2types = {none=true, facedir=true, ["4dir"]=true}
|
||||||
if type(tile) == "table" then
|
if drawtypes[def.drawtype] and p2types[def.paramtype2] and def.use_texture_alpha ~= "blend" then
|
||||||
tile = tile.name
|
|
||||||
end
|
|
||||||
if def.drawtype == "torchlike" then
|
|
||||||
textures = { "("..tile..")^[transformFX", tile }
|
|
||||||
else
|
|
||||||
textures = { tile, "("..tile..")^[transformFX" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local vsize
|
|
||||||
if def.visual_scale then
|
|
||||||
local s = def.visual_scale
|
|
||||||
vsize = vector.new(s, s, s)
|
|
||||||
end
|
|
||||||
self.object:set_properties({
|
|
||||||
is_visible = true,
|
|
||||||
visual = "upright_sprite",
|
|
||||||
visual_size = vsize,
|
|
||||||
textures = textures,
|
|
||||||
glow = def.light_source,
|
|
||||||
})
|
|
||||||
elseif def.drawtype ~= "airlike" then
|
|
||||||
local itemstring = node.name
|
|
||||||
if core.is_colored_paramtype(def.paramtype2) then
|
|
||||||
itemstring = core.itemstring_with_palette(itemstring, node.param2)
|
|
||||||
end
|
|
||||||
-- FIXME: solution needed for paramtype2 == "leveled"
|
|
||||||
-- Calculate size of falling node
|
-- Calculate size of falling node
|
||||||
local s = {}
|
local s = vector.zero()
|
||||||
s.x = (def.visual_scale or 1) * SCALE
|
s.x = (def.visual_scale or 1) * 0.667
|
||||||
s.y = s.x
|
s.y = s.x
|
||||||
s.z = s.x
|
s.z = s.x
|
||||||
-- Compensate for wield_scale
|
-- Compensate for wield_scale
|
||||||
|
@ -125,10 +96,31 @@ core.register_entity(":__builtin:falling_node", {
|
||||||
end
|
end
|
||||||
self.object:set_properties({
|
self.object:set_properties({
|
||||||
is_visible = true,
|
is_visible = true,
|
||||||
wield_item = itemstring,
|
visual = "item",
|
||||||
|
wield_item = node.name,
|
||||||
visual_size = s,
|
visual_size = s,
|
||||||
glow = def.light_source,
|
glow = def.light_source,
|
||||||
})
|
})
|
||||||
|
-- Rotate as needed
|
||||||
|
if def.paramtype2 == "facedir" then
|
||||||
|
local fdir = node.param2 % 32 % 24
|
||||||
|
local euler = facedir_to_euler[fdir + 1]
|
||||||
|
if euler then
|
||||||
|
self.object:set_rotation(euler)
|
||||||
|
end
|
||||||
|
elseif def.paramtype2 == "4dir" then
|
||||||
|
local fdir = node.param2 % 4
|
||||||
|
local euler = facedir_to_euler[fdir + 1]
|
||||||
|
if euler then
|
||||||
|
self.object:set_rotation(euler)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif def.drawtype ~= "airlike" then
|
||||||
|
self.object:set_properties({
|
||||||
|
is_visible = true,
|
||||||
|
node = node,
|
||||||
|
glow = def.light_source,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set collision box (certain nodeboxes only for now)
|
-- Set collision box (certain nodeboxes only for now)
|
||||||
|
@ -148,111 +140,6 @@ core.register_entity(":__builtin:falling_node", {
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Rotate entity
|
|
||||||
if def.drawtype == "torchlike" then
|
|
||||||
if (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted")
|
|
||||||
and node.param2 % 8 == 7 then
|
|
||||||
self.object:set_yaw(-math.pi*0.25)
|
|
||||||
else
|
|
||||||
self.object:set_yaw(math.pi*0.25)
|
|
||||||
end
|
|
||||||
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
|
|
||||||
and (def.wield_image == "" or def.wield_image == nil))
|
|
||||||
or def.drawtype == "signlike"
|
|
||||||
or def.drawtype == "mesh"
|
|
||||||
or def.drawtype == "normal"
|
|
||||||
or def.drawtype == "nodebox" then
|
|
||||||
if (def.paramtype2 == "facedir" or def.paramtype2 == "colorfacedir") then
|
|
||||||
local fdir = node.param2 % 32 % 24
|
|
||||||
-- Get rotation from a precalculated lookup table
|
|
||||||
local euler = facedir_to_euler[fdir + 1]
|
|
||||||
if euler then
|
|
||||||
self.object:set_rotation(euler)
|
|
||||||
end
|
|
||||||
elseif (def.paramtype2 == "4dir" or def.paramtype2 == "color4dir") then
|
|
||||||
local fdir = node.param2 % 4
|
|
||||||
-- Get rotation from a precalculated lookup table
|
|
||||||
local euler = facedir_to_euler[fdir + 1]
|
|
||||||
if euler then
|
|
||||||
self.object:set_rotation(euler)
|
|
||||||
end
|
|
||||||
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
|
|
||||||
rot = 1
|
|
||||||
end
|
|
||||||
local pitch, yaw, roll = 0, 0, 0
|
|
||||||
if def.drawtype == "nodebox" or def.drawtype == "mesh" then
|
|
||||||
if rot == 0 then
|
|
||||||
pitch, yaw = math.pi/2, 0
|
|
||||||
elseif rot == 1 then
|
|
||||||
pitch, yaw = -math.pi/2, math.pi
|
|
||||||
elseif rot == 2 then
|
|
||||||
pitch, yaw = 0, math.pi/2
|
|
||||||
elseif rot == 3 then
|
|
||||||
pitch, yaw = 0, -math.pi/2
|
|
||||||
elseif rot == 4 then
|
|
||||||
pitch, yaw = 0, math.pi
|
|
||||||
elseif rot == 6 then
|
|
||||||
pitch, yaw = math.pi/2, 0
|
|
||||||
elseif rot == 7 then
|
|
||||||
pitch, yaw = -math.pi/2, math.pi
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if rot == 1 then
|
|
||||||
pitch, yaw = math.pi, math.pi
|
|
||||||
elseif rot == 2 then
|
|
||||||
pitch, yaw = math.pi/2, math.pi/2
|
|
||||||
elseif rot == 3 then
|
|
||||||
pitch, yaw = math.pi/2, -math.pi/2
|
|
||||||
elseif rot == 4 then
|
|
||||||
pitch, yaw = math.pi/2, math.pi
|
|
||||||
elseif rot == 5 then
|
|
||||||
pitch, yaw = math.pi/2, 0
|
|
||||||
elseif rot == 6 then
|
|
||||||
pitch, yaw = math.pi, -math.pi/2
|
|
||||||
elseif rot == 7 then
|
|
||||||
pitch, yaw = 0, -math.pi/2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if def.drawtype == "signlike" then
|
|
||||||
pitch = pitch - math.pi/2
|
|
||||||
if rot == 0 then
|
|
||||||
yaw = yaw + math.pi/2
|
|
||||||
elseif rot == 1 then
|
|
||||||
yaw = yaw - math.pi/2
|
|
||||||
elseif rot == 6 then
|
|
||||||
yaw = yaw - math.pi/2
|
|
||||||
pitch = pitch + math.pi
|
|
||||||
elseif rot == 7 then
|
|
||||||
yaw = yaw + math.pi/2
|
|
||||||
pitch = pitch + math.pi
|
|
||||||
end
|
|
||||||
elseif def.drawtype == "mesh" or def.drawtype == "normal" or def.drawtype == "nodebox" then
|
|
||||||
if rot == 0 or rot == 1 then
|
|
||||||
roll = roll + math.pi
|
|
||||||
elseif rot == 6 or rot == 7 then
|
|
||||||
if def.drawtype ~= "normal" then
|
|
||||||
roll = roll - math.pi/2
|
|
||||||
end
|
|
||||||
else
|
|
||||||
yaw = yaw + math.pi
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.object:set_rotation({x=pitch, y=yaw, z=roll})
|
|
||||||
elseif (def.drawtype == "mesh" and def.paramtype2 == "degrotate") then
|
|
||||||
local p2 = (node.param2 - (def.place_param2 or 0)) % 240
|
|
||||||
local yaw = (p2 / 240) * (math.pi * 2)
|
|
||||||
self.object:set_yaw(yaw)
|
|
||||||
elseif (def.drawtype == "mesh" and def.paramtype2 == "colordegrotate") then
|
|
||||||
local p2 = (node.param2 % 32 - (def.place_param2 or 0) % 32) % 24
|
|
||||||
local yaw = (p2 / 24) * (math.pi * 2)
|
|
||||||
self.object:set_yaw(yaw)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
get_staticdata = function(self)
|
get_staticdata = function(self)
|
||||||
|
|
|
@ -45,6 +45,7 @@ core.features = {
|
||||||
abm_without_neighbors = true,
|
abm_without_neighbors = true,
|
||||||
biome_weights = true,
|
biome_weights = true,
|
||||||
particle_blend_clip = true,
|
particle_blend_clip = true,
|
||||||
|
remove_item_match_meta = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
function core.has_feature(arg)
|
function core.has_feature(arg)
|
||||||
|
|
|
@ -360,13 +360,12 @@ end
|
||||||
function core.item_drop(itemstack, dropper, pos)
|
function core.item_drop(itemstack, dropper, pos)
|
||||||
local dropper_is_player = dropper and dropper:is_player()
|
local dropper_is_player = dropper and dropper:is_player()
|
||||||
local p = table.copy(pos)
|
local p = table.copy(pos)
|
||||||
local cnt = itemstack:get_count()
|
|
||||||
if dropper_is_player then
|
if dropper_is_player then
|
||||||
p.y = p.y + 1.2
|
p.y = p.y + 1.2
|
||||||
end
|
end
|
||||||
local item = itemstack:take_item(cnt)
|
local obj = core.add_item(p, ItemStack(itemstack))
|
||||||
local obj = core.add_item(p, item)
|
|
||||||
if obj then
|
if obj then
|
||||||
|
itemstack:clear()
|
||||||
if dropper_is_player then
|
if dropper_is_player then
|
||||||
local dir = dropper:get_look_dir()
|
local dir = dropper:get_look_dir()
|
||||||
dir.x = dir.x * 2.9
|
dir.x = dir.x * 2.9
|
||||||
|
@ -375,7 +374,7 @@ function core.item_drop(itemstack, dropper, pos)
|
||||||
obj:set_velocity(dir)
|
obj:set_velocity(dir)
|
||||||
obj:get_luaentity().dropped_by = dropper:get_player_name()
|
obj:get_luaentity().dropped_by = dropper:get_player_name()
|
||||||
end
|
end
|
||||||
return itemstack
|
return itemstack, obj
|
||||||
end
|
end
|
||||||
-- If we reach this, adding the object to the
|
-- If we reach this, adding the object to the
|
||||||
-- environment failed
|
-- environment failed
|
||||||
|
|
|
@ -112,3 +112,26 @@ if core.set_push_moveresult1 then
|
||||||
end)
|
end)
|
||||||
core.set_push_moveresult1 = nil
|
core.set_push_moveresult1 = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Protocol version table
|
||||||
|
-- see also src/network/networkprotocol.cpp
|
||||||
|
core.protocol_versions = {
|
||||||
|
["5.0.0"] = 37,
|
||||||
|
["5.1.0"] = 38,
|
||||||
|
["5.2.0"] = 39,
|
||||||
|
["5.3.0"] = 39,
|
||||||
|
["5.4.0"] = 39,
|
||||||
|
["5.5.0"] = 40,
|
||||||
|
["5.6.0"] = 41,
|
||||||
|
["5.7.0"] = 42,
|
||||||
|
["5.8.0"] = 43,
|
||||||
|
["5.9.0"] = 44,
|
||||||
|
["5.9.1"] = 45,
|
||||||
|
["5.10.0"] = 46,
|
||||||
|
["5.11.0"] = 47,
|
||||||
|
["5.12.0"] = 48,
|
||||||
|
}
|
||||||
|
|
||||||
|
setmetatable(core.protocol_versions, {__newindex = function()
|
||||||
|
error("core.protocol_versions is read-only")
|
||||||
|
end})
|
||||||
|
|
|
@ -61,7 +61,7 @@ local function check_modname_prefix(name)
|
||||||
return name:sub(2)
|
return name:sub(2)
|
||||||
else
|
else
|
||||||
-- Enforce that the name starts with the correct mod name.
|
-- Enforce that the name starts with the correct mod name.
|
||||||
local expected_prefix = core.get_current_modname() .. ":"
|
local expected_prefix = (core.get_current_modname() or "") .. ":"
|
||||||
if name:sub(1, #expected_prefix) ~= expected_prefix then
|
if name:sub(1, #expected_prefix) ~= expected_prefix then
|
||||||
error("Name " .. name .. " does not follow naming conventions: " ..
|
error("Name " .. name .. " does not follow naming conventions: " ..
|
||||||
"\"" .. expected_prefix .. "\" or \":\" prefix required")
|
"\"" .. expected_prefix .. "\" or \":\" prefix required")
|
||||||
|
@ -95,6 +95,7 @@ function core.register_abm(spec)
|
||||||
check_node_list(spec.nodenames, "nodenames")
|
check_node_list(spec.nodenames, "nodenames")
|
||||||
check_node_list(spec.neighbors, "neighbors")
|
check_node_list(spec.neighbors, "neighbors")
|
||||||
assert(type(spec.action) == "function", "Required field 'action' of type function")
|
assert(type(spec.action) == "function", "Required field 'action' of type function")
|
||||||
|
|
||||||
core.registered_abms[#core.registered_abms + 1] = spec
|
core.registered_abms[#core.registered_abms + 1] = spec
|
||||||
spec.mod_origin = core.get_current_modname() or "??"
|
spec.mod_origin = core.get_current_modname() or "??"
|
||||||
end
|
end
|
||||||
|
@ -128,127 +129,51 @@ function core.register_entity(name, prototype)
|
||||||
prototype.mod_origin = core.get_current_modname() or "??"
|
prototype.mod_origin = core.get_current_modname() or "??"
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.register_item(name, itemdef)
|
local function preprocess_node(nodedef)
|
||||||
-- Check name
|
|
||||||
if name == nil then
|
|
||||||
error("Unable to register item: Name is nil")
|
|
||||||
end
|
|
||||||
name = check_modname_prefix(tostring(name))
|
|
||||||
if forbidden_item_names[name] then
|
|
||||||
error("Unable to register item: Name is forbidden: " .. name)
|
|
||||||
end
|
|
||||||
itemdef.name = name
|
|
||||||
|
|
||||||
-- Apply defaults and add to registered_* table
|
|
||||||
if itemdef.type == "node" then
|
|
||||||
-- Use the nodebox as selection box if it's not set manually
|
-- Use the nodebox as selection box if it's not set manually
|
||||||
if itemdef.drawtype == "nodebox" and not itemdef.selection_box then
|
if nodedef.drawtype == "nodebox" and not nodedef.selection_box then
|
||||||
itemdef.selection_box = itemdef.node_box
|
nodedef.selection_box = nodedef.node_box
|
||||||
elseif itemdef.drawtype == "fencelike" and not itemdef.selection_box then
|
elseif nodedef.drawtype == "fencelike" and not nodedef.selection_box then
|
||||||
itemdef.selection_box = {
|
nodedef.selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
|
fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
if itemdef.light_source and itemdef.light_source > core.LIGHT_MAX then
|
|
||||||
itemdef.light_source = core.LIGHT_MAX
|
if nodedef.light_source and nodedef.light_source > core.LIGHT_MAX then
|
||||||
|
nodedef.light_source = core.LIGHT_MAX
|
||||||
core.log("warning", "Node 'light_source' value exceeds maximum," ..
|
core.log("warning", "Node 'light_source' value exceeds maximum," ..
|
||||||
" limiting to maximum: " ..name)
|
" limiting it: " .. nodedef.name)
|
||||||
end
|
|
||||||
setmetatable(itemdef, {__index = core.nodedef_default})
|
|
||||||
core.registered_nodes[itemdef.name] = itemdef
|
|
||||||
elseif itemdef.type == "craft" then
|
|
||||||
setmetatable(itemdef, {__index = core.craftitemdef_default})
|
|
||||||
core.registered_craftitems[itemdef.name] = itemdef
|
|
||||||
elseif itemdef.type == "tool" then
|
|
||||||
setmetatable(itemdef, {__index = core.tooldef_default})
|
|
||||||
core.registered_tools[itemdef.name] = itemdef
|
|
||||||
elseif itemdef.type == "none" then
|
|
||||||
setmetatable(itemdef, {__index = core.noneitemdef_default})
|
|
||||||
else
|
|
||||||
error("Unable to register item: Type is invalid: " .. dump(itemdef))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Flowing liquid uses param2
|
-- Flowing liquid uses param2
|
||||||
if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
|
if nodedef.liquidtype == "flowing" then
|
||||||
itemdef.paramtype2 = "flowingliquid"
|
nodedef.paramtype2 = "flowingliquid"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function preprocess_craft(itemdef)
|
||||||
-- BEGIN Legacy stuff
|
-- BEGIN Legacy stuff
|
||||||
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
|
if itemdef.inventory_image == nil and itemdef.image ~= nil then
|
||||||
core.register_craft({
|
core.log("deprecated", "The `image` field in craftitem definitions " ..
|
||||||
type="cooking",
|
"is deprecated. Use `inventory_image` instead. " ..
|
||||||
output=itemdef.cookresult_itemstring,
|
"Craftitem name: " .. itemdef.name, 3)
|
||||||
recipe=itemdef.name,
|
itemdef.inventory_image = itemdef.image
|
||||||
cooktime=itemdef.furnace_cooktime
|
|
||||||
})
|
|
||||||
end
|
|
||||||
if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
|
|
||||||
core.register_craft({
|
|
||||||
type="fuel",
|
|
||||||
recipe=itemdef.name,
|
|
||||||
burntime=itemdef.furnace_burntime
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
-- END Legacy stuff
|
-- END Legacy stuff
|
||||||
|
|
||||||
itemdef.mod_origin = core.get_current_modname() or "??"
|
|
||||||
|
|
||||||
-- Disable all further modifications
|
|
||||||
getmetatable(itemdef).__newindex = {}
|
|
||||||
|
|
||||||
--core.log("Registering item: " .. itemdef.name)
|
|
||||||
core.registered_items[itemdef.name] = itemdef
|
|
||||||
core.registered_aliases[itemdef.name] = nil
|
|
||||||
register_item_raw(itemdef)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.unregister_item(name)
|
local function preprocess_tool(tooldef)
|
||||||
if not core.registered_items[name] then
|
|
||||||
core.log("warning", "Not unregistering item " ..name..
|
|
||||||
" because it doesn't exist.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
-- Erase from registered_* table
|
|
||||||
local type = core.registered_items[name].type
|
|
||||||
if type == "node" then
|
|
||||||
core.registered_nodes[name] = nil
|
|
||||||
elseif type == "craft" then
|
|
||||||
core.registered_craftitems[name] = nil
|
|
||||||
elseif type == "tool" then
|
|
||||||
core.registered_tools[name] = nil
|
|
||||||
end
|
|
||||||
core.registered_items[name] = nil
|
|
||||||
|
|
||||||
|
|
||||||
unregister_item_raw(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
function core.register_node(name, nodedef)
|
|
||||||
nodedef.type = "node"
|
|
||||||
core.register_item(name, nodedef)
|
|
||||||
end
|
|
||||||
|
|
||||||
function core.register_craftitem(name, craftitemdef)
|
|
||||||
craftitemdef.type = "craft"
|
|
||||||
|
|
||||||
-- BEGIN Legacy stuff
|
|
||||||
if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
|
|
||||||
craftitemdef.inventory_image = craftitemdef.image
|
|
||||||
end
|
|
||||||
-- END Legacy stuff
|
|
||||||
|
|
||||||
core.register_item(name, craftitemdef)
|
|
||||||
end
|
|
||||||
|
|
||||||
function core.register_tool(name, tooldef)
|
|
||||||
tooldef.type = "tool"
|
|
||||||
tooldef.stack_max = 1
|
tooldef.stack_max = 1
|
||||||
|
|
||||||
-- BEGIN Legacy stuff
|
-- BEGIN Legacy stuff
|
||||||
if tooldef.inventory_image == nil and tooldef.image ~= nil then
|
if tooldef.inventory_image == nil and tooldef.image ~= nil then
|
||||||
|
core.log("deprecated", "The `image` field in tool definitions " ..
|
||||||
|
"is deprecated. Use `inventory_image` instead. " ..
|
||||||
|
"Tool name: " .. tooldef.name, 3)
|
||||||
tooldef.inventory_image = tooldef.image
|
tooldef.inventory_image = tooldef.image
|
||||||
end
|
end
|
||||||
|
|
||||||
if tooldef.tool_capabilities == nil and
|
if tooldef.tool_capabilities == nil and
|
||||||
(tooldef.full_punch_interval ~= nil or
|
(tooldef.full_punch_interval ~= nil or
|
||||||
tooldef.basetime ~= nil or
|
tooldef.basetime ~= nil or
|
||||||
|
@ -261,6 +186,9 @@ function core.register_tool(name, tooldef)
|
||||||
tooldef.dd_crackiness ~= nil or
|
tooldef.dd_crackiness ~= nil or
|
||||||
tooldef.dd_crumbliness ~= nil or
|
tooldef.dd_crumbliness ~= nil or
|
||||||
tooldef.dd_cuttability ~= nil) then
|
tooldef.dd_cuttability ~= nil) then
|
||||||
|
core.log("deprecated", "Specifying tool capabilities directly in the tool " ..
|
||||||
|
"definition is deprecated. Use the `tool_capabilities` field instead. " ..
|
||||||
|
"Tool name: " .. tooldef.name, 3)
|
||||||
tooldef.tool_capabilities = {
|
tooldef.tool_capabilities = {
|
||||||
full_punch_interval = tooldef.full_punch_interval,
|
full_punch_interval = tooldef.full_punch_interval,
|
||||||
basetime = tooldef.basetime,
|
basetime = tooldef.basetime,
|
||||||
|
@ -277,7 +205,7 @@ function core.register_tool(name, tooldef)
|
||||||
end
|
end
|
||||||
-- END Legacy stuff
|
-- END Legacy stuff
|
||||||
|
|
||||||
-- This isn't just legacy, but more of a convenience feature
|
-- Automatically set punch_attack_uses as a convenience feature
|
||||||
local toolcaps = tooldef.tool_capabilities
|
local toolcaps = tooldef.tool_capabilities
|
||||||
if toolcaps and toolcaps.punch_attack_uses == nil then
|
if toolcaps and toolcaps.punch_attack_uses == nil then
|
||||||
for _, cap in pairs(toolcaps.groupcaps or {}) do
|
for _, cap in pairs(toolcaps.groupcaps or {}) do
|
||||||
|
@ -288,8 +216,126 @@ function core.register_tool(name, tooldef)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
core.register_item(name, tooldef)
|
local default_tables = {
|
||||||
|
node = core.nodedef_default,
|
||||||
|
craft = core.craftitemdef_default,
|
||||||
|
tool = core.tooldef_default,
|
||||||
|
none = core.noneitemdef_default,
|
||||||
|
}
|
||||||
|
|
||||||
|
local preprocess_fns = {
|
||||||
|
node = preprocess_node,
|
||||||
|
craft = preprocess_craft,
|
||||||
|
tool = preprocess_tool,
|
||||||
|
}
|
||||||
|
|
||||||
|
function core.register_item(name, itemdef)
|
||||||
|
-- Check name
|
||||||
|
if name == nil then
|
||||||
|
error("Unable to register item: Name is nil")
|
||||||
|
end
|
||||||
|
name = check_modname_prefix(tostring(name))
|
||||||
|
if forbidden_item_names[name] then
|
||||||
|
error("Unable to register item: Name is forbidden: " .. name)
|
||||||
|
end
|
||||||
|
|
||||||
|
itemdef.name = name
|
||||||
|
|
||||||
|
-- Compatibility stuff depending on type
|
||||||
|
local fn = preprocess_fns[itemdef.type]
|
||||||
|
if fn then
|
||||||
|
fn(itemdef)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply defaults
|
||||||
|
local defaults = default_tables[itemdef.type]
|
||||||
|
if defaults == nil then
|
||||||
|
error("Unable to register item: Type is invalid: " .. dump(itemdef))
|
||||||
|
end
|
||||||
|
local old_mt = getmetatable(itemdef)
|
||||||
|
-- TODO most of these checks should become an error after a while (maybe in 2026?)
|
||||||
|
if old_mt ~= nil and next(old_mt) ~= nil then
|
||||||
|
-- Note that even registering multiple identical items with the same table
|
||||||
|
-- is not allowed, due to the 'name' property.
|
||||||
|
if old_mt.__index == defaults then
|
||||||
|
core.log("warning", "Item definition table was reused between registrations. "..
|
||||||
|
"This is unsupported and broken: " .. name)
|
||||||
|
else
|
||||||
|
core.log("warning", "Item definition has a metatable, this is "..
|
||||||
|
"unsupported and it will be overwritten: " .. name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
setmetatable(itemdef, {__index = defaults})
|
||||||
|
|
||||||
|
-- BEGIN Legacy stuff
|
||||||
|
if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
|
||||||
|
core.log("deprecated", "The `cookresult_itemstring` item definition " ..
|
||||||
|
"field is deprecated. Use `core.register_craft` instead. " ..
|
||||||
|
"Item name: " .. itemdef.name, 2)
|
||||||
|
core.register_craft({
|
||||||
|
type="cooking",
|
||||||
|
output=itemdef.cookresult_itemstring,
|
||||||
|
recipe=itemdef.name,
|
||||||
|
cooktime=itemdef.furnace_cooktime
|
||||||
|
})
|
||||||
|
end
|
||||||
|
if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
|
||||||
|
core.log("deprecated", "The `furnace_burntime` item definition " ..
|
||||||
|
"field is deprecated. Use `core.register_craft` instead. " ..
|
||||||
|
"Item name: " .. itemdef.name, 2)
|
||||||
|
core.register_craft({
|
||||||
|
type="fuel",
|
||||||
|
recipe=itemdef.name,
|
||||||
|
burntime=itemdef.furnace_burntime
|
||||||
|
})
|
||||||
|
end
|
||||||
|
-- END Legacy stuff
|
||||||
|
|
||||||
|
itemdef.mod_origin = core.get_current_modname() or "??"
|
||||||
|
|
||||||
|
-- Ignore new keys as a failsafe to prevent mistakes
|
||||||
|
getmetatable(itemdef).__newindex = function() end
|
||||||
|
|
||||||
|
-- Add to registered_* tables
|
||||||
|
if itemdef.type == "node" then
|
||||||
|
core.registered_nodes[itemdef.name] = itemdef
|
||||||
|
elseif itemdef.type == "craft" then
|
||||||
|
core.registered_craftitems[itemdef.name] = itemdef
|
||||||
|
elseif itemdef.type == "tool" then
|
||||||
|
core.registered_tools[itemdef.name] = itemdef
|
||||||
|
end
|
||||||
|
core.registered_items[itemdef.name] = itemdef
|
||||||
|
core.registered_aliases[itemdef.name] = nil
|
||||||
|
|
||||||
|
register_item_raw(itemdef)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_register_item_wrapper(the_type)
|
||||||
|
return function(name, itemdef)
|
||||||
|
itemdef.type = the_type
|
||||||
|
return core.register_item(name, itemdef)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
core.register_node = make_register_item_wrapper("node")
|
||||||
|
core.register_craftitem = make_register_item_wrapper("craft")
|
||||||
|
core.register_tool = make_register_item_wrapper("tool")
|
||||||
|
|
||||||
|
function core.unregister_item(name)
|
||||||
|
if not core.registered_items[name] then
|
||||||
|
core.log("warning", "Not unregistering item " ..name..
|
||||||
|
" because it doesn't exist.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Erase from registered_* table
|
||||||
|
core.registered_nodes[name] = nil
|
||||||
|
core.registered_craftitems[name] = nil
|
||||||
|
core.registered_tools[name] = nil
|
||||||
|
core.registered_items[name] = nil
|
||||||
|
|
||||||
|
unregister_item_raw(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function core.register_alias(name, convert_to)
|
function core.register_alias(name, convert_to)
|
||||||
|
@ -300,7 +346,6 @@ function core.register_alias(name, convert_to)
|
||||||
core.log("warning", "Not registering alias, item with same name" ..
|
core.log("warning", "Not registering alias, item with same name" ..
|
||||||
" is already defined: " .. name .. " -> " .. convert_to)
|
" is already defined: " .. name .. " -> " .. convert_to)
|
||||||
else
|
else
|
||||||
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
|
|
||||||
core.registered_aliases[name] = convert_to
|
core.registered_aliases[name] = convert_to
|
||||||
register_alias_raw(name, convert_to)
|
register_alias_raw(name, convert_to)
|
||||||
end
|
end
|
||||||
|
@ -315,7 +360,6 @@ function core.register_alias_force(name, convert_to)
|
||||||
core.log("info", "Removed item " ..name..
|
core.log("info", "Removed item " ..name..
|
||||||
" while attempting to force add an alias")
|
" while attempting to force add an alias")
|
||||||
end
|
end
|
||||||
--core.log("Registering alias: " .. name .. " -> " .. convert_to)
|
|
||||||
core.registered_aliases[name] = convert_to
|
core.registered_aliases[name] = convert_to
|
||||||
register_alias_raw(name, convert_to)
|
register_alias_raw(name, convert_to)
|
||||||
end
|
end
|
||||||
|
@ -406,6 +450,7 @@ core.register_item(":", {
|
||||||
groups = {not_in_creative_inventory=1},
|
groups = {not_in_creative_inventory=1},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local itemdefs_finalized = false
|
||||||
|
|
||||||
function core.override_item(name, redefinition, del_fields)
|
function core.override_item(name, redefinition, del_fields)
|
||||||
if redefinition.name ~= nil then
|
if redefinition.name ~= nil then
|
||||||
|
@ -418,10 +463,16 @@ function core.override_item(name, redefinition, del_fields)
|
||||||
if not item then
|
if not item then
|
||||||
error("Attempt to override non-existent item "..name, 2)
|
error("Attempt to override non-existent item "..name, 2)
|
||||||
end
|
end
|
||||||
|
if itemdefs_finalized then
|
||||||
|
-- TODO: it's not clear if this needs to be allowed at all?
|
||||||
|
core.log("warning", "Overriding item " .. name .. " after server startup. " ..
|
||||||
|
"This is unsupported and can cause problems related to data inconsistency.")
|
||||||
|
end
|
||||||
for k, v in pairs(redefinition) do
|
for k, v in pairs(redefinition) do
|
||||||
rawset(item, k, v)
|
rawset(item, k, v)
|
||||||
end
|
end
|
||||||
for _, field in ipairs(del_fields or {}) do
|
for _, field in ipairs(del_fields or {}) do
|
||||||
|
assert(field ~= "name" and field ~= "type")
|
||||||
rawset(item, field, nil)
|
rawset(item, field, nil)
|
||||||
end
|
end
|
||||||
register_item_raw(item)
|
register_item_raw(item)
|
||||||
|
@ -568,13 +619,57 @@ core.registered_on_rightclickplayers, core.register_on_rightclickplayer = make_r
|
||||||
core.registered_on_liquid_transformed, core.register_on_liquid_transformed = make_registration()
|
core.registered_on_liquid_transformed, core.register_on_liquid_transformed = make_registration()
|
||||||
core.registered_on_mapblocks_changed, core.register_on_mapblocks_changed = make_registration()
|
core.registered_on_mapblocks_changed, core.register_on_mapblocks_changed = make_registration()
|
||||||
|
|
||||||
|
-- A bunch of registrations are read by the C++ side once on env init, so we cannot
|
||||||
|
-- allow them to change afterwards (see s_env.cpp).
|
||||||
|
-- Nodes and items do not have this problem but there are obvious consistency
|
||||||
|
-- problems if this would be allowed.
|
||||||
|
|
||||||
|
local function freeze_table(t)
|
||||||
|
-- Freezing a Lua table is not actually possible without some very intrusive
|
||||||
|
-- metatable hackery, but we can trivially prevent new additions.
|
||||||
|
local mt = table.copy(getmetatable(t) or {})
|
||||||
|
mt.__newindex = function()
|
||||||
|
error("modification forbidden")
|
||||||
|
end
|
||||||
|
setmetatable(t, mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generic_reg_error(what)
|
||||||
|
return function(something)
|
||||||
|
local described = what
|
||||||
|
if type(something) == "table" and type(something.name) == "string" then
|
||||||
|
described = what .. " " .. something.name
|
||||||
|
elseif type(something) == "string" then
|
||||||
|
described = what .. " " .. something
|
||||||
|
end
|
||||||
|
error("Tried to register " .. described .. " after load time!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
core.register_on_mods_loaded(function()
|
core.register_on_mods_loaded(function()
|
||||||
core.after(0, function()
|
core.after(0, function()
|
||||||
setmetatable(core.registered_on_mapblocks_changed, {
|
itemdefs_finalized = true
|
||||||
__newindex = function()
|
|
||||||
error("on_mapblocks_changed callbacks must be registered at load time")
|
-- prevent direct modification
|
||||||
end,
|
freeze_table(core.registered_abms)
|
||||||
})
|
freeze_table(core.registered_lbms)
|
||||||
|
freeze_table(core.registered_items)
|
||||||
|
freeze_table(core.registered_nodes)
|
||||||
|
freeze_table(core.registered_craftitems)
|
||||||
|
freeze_table(core.registered_tools)
|
||||||
|
freeze_table(core.registered_aliases)
|
||||||
|
freeze_table(core.registered_on_mapblocks_changed)
|
||||||
|
|
||||||
|
-- neutralize registration functions
|
||||||
|
core.register_abm = generic_reg_error("ABM")
|
||||||
|
core.register_lbm = generic_reg_error("LBM")
|
||||||
|
core.register_item = generic_reg_error("item")
|
||||||
|
core.unregister_item = function(name)
|
||||||
|
error("Refusing to unregister item " .. name .. " after load time")
|
||||||
|
end
|
||||||
|
core.register_alias = generic_reg_error("alias")
|
||||||
|
core.register_alias_force = generic_reg_error("alias")
|
||||||
|
core.register_on_mapblocks_changed = generic_reg_error("on_mapblocks_changed callback")
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,8 @@ elseif INIT == "client" then
|
||||||
dofile(scriptdir .. "client" .. DIR_DELIM .. "init.lua")
|
dofile(scriptdir .. "client" .. DIR_DELIM .. "init.lua")
|
||||||
elseif INIT == "emerge" then
|
elseif INIT == "emerge" then
|
||||||
dofile(scriptdir .. "emerge" .. DIR_DELIM .. "init.lua")
|
dofile(scriptdir .. "emerge" .. DIR_DELIM .. "init.lua")
|
||||||
|
elseif INIT == "pause_menu" then
|
||||||
|
dofile(scriptdir .. "pause_menu" .. DIR_DELIM .. "init.lua")
|
||||||
else
|
else
|
||||||
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
|
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"#": "https://github.com/orgs/minetest/teams/engine/members",
|
"#": "https://github.com/orgs/luanti-org/teams/engine/members",
|
||||||
"core_developers": [
|
"core_developers": [
|
||||||
"Perttu Ahola (celeron55) <celeron55@gmail.com> [Project founder]",
|
"Perttu Ahola (celeron55) <celeron55@gmail.com> [Project founder]",
|
||||||
"sfan5 <sfan5@live.de>",
|
"sfan5 <sfan5@live.de>",
|
||||||
|
@ -15,7 +15,8 @@
|
||||||
"Gregor Parzefall (grorp)",
|
"Gregor Parzefall (grorp)",
|
||||||
"Lars Müller (luatic)",
|
"Lars Müller (luatic)",
|
||||||
"cx384",
|
"cx384",
|
||||||
"sfence"
|
"sfence",
|
||||||
|
"y5nw"
|
||||||
],
|
],
|
||||||
"previous_core_developers": [
|
"previous_core_developers": [
|
||||||
"BlockMen",
|
"BlockMen",
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
"Hugues Ross <hugues.ross@gmail.com>",
|
"Hugues Ross <hugues.ross@gmail.com>",
|
||||||
"Dmitry Kostenko (x2048) <codeforsmile@gmail.com>"
|
"Dmitry Kostenko (x2048) <codeforsmile@gmail.com>"
|
||||||
],
|
],
|
||||||
"#": "Currently only https://github.com/orgs/minetest/teams/triagers/members",
|
"#": "Currently only https://github.com/orgs/luanti-org/teams/triagers/members",
|
||||||
"core_team": [
|
"core_team": [
|
||||||
"Zughy [Issue triager]",
|
"Zughy [Issue triager]",
|
||||||
"wsor [Issue triager]",
|
"wsor [Issue triager]",
|
||||||
|
@ -47,23 +48,20 @@
|
||||||
"#": "For updating active/previous contributors, see the script in ./util/gather_git_credits.py",
|
"#": "For updating active/previous contributors, see the script in ./util/gather_git_credits.py",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"JosiahWI",
|
"JosiahWI",
|
||||||
"1F616EMO",
|
|
||||||
"y5nw",
|
|
||||||
"Erich Schubert",
|
"Erich Schubert",
|
||||||
"numzero",
|
"wrrrzr",
|
||||||
|
"1F616EMO",
|
||||||
"red-001 <red-001@outlook.ie>",
|
"red-001 <red-001@outlook.ie>",
|
||||||
"David Heidelberg",
|
"veprogames",
|
||||||
"Wuzzy",
|
|
||||||
"paradust7",
|
"paradust7",
|
||||||
"HybridDog",
|
|
||||||
"Zemtzov7",
|
|
||||||
"kromka-chleba",
|
|
||||||
"AFCMS",
|
"AFCMS",
|
||||||
"chmodsayshello",
|
"siliconsniffer",
|
||||||
"OgelGames"
|
"Wuzzy",
|
||||||
|
"Zemtzov7"
|
||||||
],
|
],
|
||||||
"previous_contributors": [
|
"previous_contributors": [
|
||||||
"Ælla Chiana Moskopp (erle) <erle@dieweltistgarnichtso.net> [Logo]",
|
"Ælla Chiana Moskopp (erle) <erle@dieweltistgarnichtso.net> [Logo]",
|
||||||
|
"numzero",
|
||||||
"Giuseppe Bilotta",
|
"Giuseppe Bilotta",
|
||||||
"ClobberXD",
|
"ClobberXD",
|
||||||
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
|
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
|
||||||
|
|
|
@ -21,7 +21,7 @@ local function clients_list_formspec(dialogdata)
|
||||||
"size[6,9.5]",
|
"size[6,9.5]",
|
||||||
TOUCH_GUI and "padding[0.01,0.01]" or "",
|
TOUCH_GUI and "padding[0.01,0.01]" or "",
|
||||||
"hypertext[0,0;6,1.5;;<global margin=5 halign=center valign=middle>",
|
"hypertext[0,0;6,1.5;;<global margin=5 halign=center valign=middle>",
|
||||||
fgettext("This is the list of clients connected to\n$1",
|
fgettext("Players connected to\n$1",
|
||||||
"<b>" .. core.hypertext_escape(servername) .. "</b>") .. "]",
|
"<b>" .. core.hypertext_escape(servername) .. "</b>") .. "]",
|
||||||
"textlist[0.5,1.5;5,6.8;;" .. fmt_formspec_list(clients_list) .. "]",
|
"textlist[0.5,1.5;5,6.8;;" .. fmt_formspec_list(clients_list) .. "]",
|
||||||
"button[1.5,8.5;3,0.8;quit;OK]"
|
"button[1.5,8.5;3,0.8;quit;OK]"
|
||||||
|
|
|
@ -299,7 +299,7 @@ local function handle_buttons(this, fields)
|
||||||
worldfile:set("load_mod_" .. mod.name, mod.virtual_path)
|
worldfile:set("load_mod_" .. mod.name, mod.virtual_path)
|
||||||
was_set[mod.name] = true
|
was_set[mod.name] = true
|
||||||
elseif not was_set[mod.name] then
|
elseif not was_set[mod.name] then
|
||||||
worldfile:set("load_mod_" .. mod.name, "false")
|
worldfile:remove("load_mod_" .. mod.name)
|
||||||
end
|
end
|
||||||
elseif mod.enabled then
|
elseif mod.enabled then
|
||||||
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..
|
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
-- This whole file can be removed after a while.
|
-- This whole file can be removed after a while.
|
||||||
-- It was only directly useful for upgrades from 5.7.0 to 5.8.0, but
|
-- It was only directly useful for upgrades from 5.7.0 to 5.8.0, but
|
||||||
-- maybe some odd fellow directly upgrades from 5.6.1 to 5.9.0 in the future...
|
-- maybe some odd fellow directly upgrades from 5.6.1 to 5.9.0 in the future...
|
||||||
-- see <https://github.com/minetest/minetest/pull/13850> in case it's not obvious
|
-- see <https://github.com/luanti-org/luanti/pull/13850> in case it's not obvious
|
||||||
---- ----
|
---- ----
|
||||||
|
|
||||||
local SETTING_NAME = "no_mtg_notification"
|
local SETTING_NAME = "no_mtg_notification"
|
||||||
|
|
|
@ -47,7 +47,7 @@ dofile(menupath .. DIR_DELIM .. "game_theme.lua")
|
||||||
dofile(menupath .. DIR_DELIM .. "content" .. DIR_DELIM .. "init.lua")
|
dofile(menupath .. DIR_DELIM .. "content" .. DIR_DELIM .. "init.lua")
|
||||||
|
|
||||||
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
|
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
|
||||||
dofile(menupath .. DIR_DELIM .. "settings" .. DIR_DELIM .. "init.lua")
|
dofile(basepath .. "common" .. DIR_DELIM .. "settings" .. DIR_DELIM .. "init.lua")
|
||||||
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
|
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
|
||||||
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
|
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
|
||||||
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
|
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
|
||||||
|
|
|
@ -190,10 +190,10 @@ local function get_formspec(tabview, name, tabdata)
|
||||||
local max_clients = 5
|
local max_clients = 5
|
||||||
if #clients_list > max_clients then
|
if #clients_list > max_clients then
|
||||||
retval = retval .. "tooltip[btn_view_clients;" ..
|
retval = retval .. "tooltip[btn_view_clients;" ..
|
||||||
fgettext("Clients:\n$1", table.concat(clients_list, "\n", 1, max_clients)) .. "\n..." .. "]"
|
fgettext("Players:\n$1", table.concat(clients_list, "\n", 1, max_clients)) .. "\n..." .. "]"
|
||||||
else
|
else
|
||||||
retval = retval .. "tooltip[btn_view_clients;" ..
|
retval = retval .. "tooltip[btn_view_clients;" ..
|
||||||
fgettext("Clients:\n$1", table.concat(clients_list, "\n")) .. "]"
|
fgettext("Players:\n$1", table.concat(clients_list, "\n")) .. "]"
|
||||||
end
|
end
|
||||||
retval = retval .. "style[btn_view_clients;padding=6]"
|
retval = retval .. "style[btn_view_clients;padding=6]"
|
||||||
retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
|
retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
|
||||||
|
@ -391,12 +391,15 @@ local function matches_query(server, query)
|
||||||
return name_matches and 50 or description_matches and 0
|
return name_matches and 50 or description_matches and 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function search_server_list(input)
|
local function search_server_list(input, tabdata)
|
||||||
menudata.search_result = nil
|
menudata.search_result = nil
|
||||||
if #serverlistmgr.servers < 2 then
|
if #serverlistmgr.servers < 2 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
tabdata.pre_search_selection = tabdata.pre_search_selection or find_selected_server()
|
||||||
|
|
||||||
-- setup the search query
|
-- setup the search query
|
||||||
local query = parse_search_input(input)
|
local query = parse_search_input(input)
|
||||||
if not query then
|
if not query then
|
||||||
|
@ -419,10 +422,32 @@ local function search_server_list(input)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local current_server = find_selected_server()
|
||||||
|
|
||||||
table.sort(search_result, function(a, b)
|
table.sort(search_result, function(a, b)
|
||||||
return a.points > b.points
|
return a.points > b.points
|
||||||
end)
|
end)
|
||||||
menudata.search_result = search_result
|
menudata.search_result = search_result
|
||||||
|
|
||||||
|
-- Keep current selection if it's in search results
|
||||||
|
if current_server then
|
||||||
|
for _, server in ipairs(search_result) do
|
||||||
|
if server.address == current_server.address and
|
||||||
|
server.port == current_server.port then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Find first compatible server (favorite or public)
|
||||||
|
for _, server in ipairs(search_result) do
|
||||||
|
if is_server_protocol_compat(server.proto_min, server.proto_max) then
|
||||||
|
set_selected_server(server)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- If no compatible server found, clear selection
|
||||||
|
set_selected_server(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function main_button_handler(tabview, fields, name, tabdata)
|
local function main_button_handler(tabview, fields, name, tabdata)
|
||||||
|
@ -462,6 +487,7 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
||||||
end
|
end
|
||||||
if event.type == "CHG" then
|
if event.type == "CHG" then
|
||||||
set_selected_server(server)
|
set_selected_server(server)
|
||||||
|
tabdata.pre_search_selection = nil
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -475,11 +501,9 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
||||||
if fields.btn_delete_favorite then
|
if fields.btn_delete_favorite then
|
||||||
local idx = core.get_table_index("servers")
|
local idx = core.get_table_index("servers")
|
||||||
if not idx then return end
|
if not idx then return end
|
||||||
local server = tabdata.lookup[idx]
|
|
||||||
if not server then return end
|
|
||||||
|
|
||||||
serverlistmgr.delete_favorite(server)
|
serverlistmgr.delete_favorite(tabdata.lookup[idx])
|
||||||
set_selected_server(server)
|
set_selected_server(tabdata.lookup[idx+1])
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -507,17 +531,16 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
||||||
if fields.btn_mp_clear then
|
if fields.btn_mp_clear then
|
||||||
tabdata.search_for = ""
|
tabdata.search_for = ""
|
||||||
menudata.search_result = nil
|
menudata.search_result = nil
|
||||||
|
if tabdata.pre_search_selection then
|
||||||
|
set_selected_server(tabdata.pre_search_selection)
|
||||||
|
tabdata.pre_search_selection = nil
|
||||||
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
|
if fields.btn_mp_search or fields.key_enter_field == "te_search" then
|
||||||
tabdata.search_for = fields.te_search
|
tabdata.search_for = fields.te_search
|
||||||
search_server_list(fields.te_search)
|
search_server_list(fields.te_search, tabdata)
|
||||||
if menudata.search_result then
|
|
||||||
-- Note: This clears the selection if there are no results
|
|
||||||
set_selected_server(menudata.search_result[1])
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
12
builtin/pause_menu/init.lua
Normal file
12
builtin/pause_menu/init.lua
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
local scriptpath = core.get_builtin_path()
|
||||||
|
local pausepath = scriptpath.."pause_menu"..DIR_DELIM
|
||||||
|
local commonpath = scriptpath.."common"..DIR_DELIM
|
||||||
|
|
||||||
|
-- we're in-game, so no absolute paths are needed
|
||||||
|
defaulttexturedir = ""
|
||||||
|
|
||||||
|
local builtin_shared = {}
|
||||||
|
|
||||||
|
assert(loadfile(commonpath .. "register.lua"))(builtin_shared)
|
||||||
|
assert(loadfile(pausepath .. "register.lua"))(builtin_shared)
|
||||||
|
dofile(commonpath .. "settings" .. DIR_DELIM .. "init.lua")
|
5
builtin/pause_menu/register.lua
Normal file
5
builtin/pause_menu/register.lua
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
local builtin_shared = ...
|
||||||
|
|
||||||
|
local make_registration = builtin_shared.make_registration
|
||||||
|
|
||||||
|
core.registered_on_formspec_input, core.register_on_formspec_input = make_registration()
|
|
@ -2,9 +2,27 @@
|
||||||
#
|
#
|
||||||
# General format:
|
# General format:
|
||||||
# name (Readable name) type type_args
|
# name (Readable name) type type_args
|
||||||
|
# name (Readable name) [context] type type_args
|
||||||
#
|
#
|
||||||
# Note that the parts are separated by exactly one space
|
# Note that the parts are separated by exactly one space
|
||||||
#
|
#
|
||||||
|
# `context` (optional) is used to document where the setting is read. It can be:
|
||||||
|
# - common: Read by both client and server.
|
||||||
|
# - client: Read by the client.
|
||||||
|
# (Includes settings read by the mainmenu.)
|
||||||
|
# - server: Read by the server.
|
||||||
|
# - world_creation: Read at world creation, thus only applied to new worlds.
|
||||||
|
# (Worlds are commonly created in the mainmenu (part of the client), but
|
||||||
|
# world creation is conceptually a server-side thing...)
|
||||||
|
# If not specified, the value is inherited from the context value of the containing
|
||||||
|
# category instead.
|
||||||
|
# For the builtin/settingtypes.txt file, every setting needs to have a context defined,
|
||||||
|
# either via a category containing it or via the setting itself. In game/mod-provided
|
||||||
|
# settingtypes.txt files, context annotations are invalid.
|
||||||
|
# Note: For context annotations, it's irrelevant whether changes to a setting
|
||||||
|
# after startup/game-join will be read. A separate mechanism for declaring that
|
||||||
|
# is needed.
|
||||||
|
#
|
||||||
# `type` can be:
|
# `type` can be:
|
||||||
# - int
|
# - int
|
||||||
# - string
|
# - string
|
||||||
|
@ -77,6 +95,8 @@
|
||||||
# Sections are marked by a single line in the format: [Section Name]
|
# Sections are marked by a single line in the format: [Section Name]
|
||||||
# Sub-section are marked by adding * in front of the section name: [*Sub-section]
|
# Sub-section are marked by adding * in front of the section name: [*Sub-section]
|
||||||
# Sub-sub-sections have two * etc.
|
# Sub-sub-sections have two * etc.
|
||||||
|
# A context (see above) can be specified optionally: [Section Name] [context]
|
||||||
|
# Context annotations on categories cannot be nested.
|
||||||
# There shouldn't be too many settings per category.
|
# There shouldn't be too many settings per category.
|
||||||
#
|
#
|
||||||
# The top-level categories "Advanced", "Client and Server" and "Mapgen" are
|
# The top-level categories "Advanced", "Client and Server" and "Mapgen" are
|
||||||
|
@ -84,7 +104,7 @@
|
||||||
# They contain settings not intended for the "average user".
|
# They contain settings not intended for the "average user".
|
||||||
|
|
||||||
|
|
||||||
[Controls]
|
[Controls] [client]
|
||||||
|
|
||||||
[*General]
|
[*General]
|
||||||
|
|
||||||
|
@ -111,6 +131,13 @@ doubletap_jump (Double tap jump for fly) bool false
|
||||||
# enabled.
|
# enabled.
|
||||||
always_fly_fast (Always fly fast) bool true
|
always_fly_fast (Always fly fast) bool true
|
||||||
|
|
||||||
|
# If enabled, the "Sneak" key will toggle when pressed.
|
||||||
|
# This functionality is ignored when fly is enabled.
|
||||||
|
toggle_sneak_key (Toggle Sneak key) bool false
|
||||||
|
|
||||||
|
# If enabled, the "Aux1" key will toggle when pressed.
|
||||||
|
toggle_aux1_key (Toggle Aux1 key) bool false
|
||||||
|
|
||||||
# The time in seconds it takes between repeated node placements when holding
|
# The time in seconds it takes between repeated node placements when holding
|
||||||
# the place button.
|
# the place button.
|
||||||
#
|
#
|
||||||
|
@ -160,6 +187,36 @@ invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
|
||||||
# Requires: touch_support
|
# Requires: touch_support
|
||||||
touch_controls (Touchscreen controls) enum auto auto,true,false
|
touch_controls (Touchscreen controls) enum auto auto,true,false
|
||||||
|
|
||||||
|
# The kind of digging/placing controls used.
|
||||||
|
#
|
||||||
|
# * Tap
|
||||||
|
# Long/short tap anywhere on the screen to interact.
|
||||||
|
# Interaction happens at finger position.
|
||||||
|
#
|
||||||
|
# * Tap with crosshair
|
||||||
|
# Long/short tap anywhere on the screen to interact.
|
||||||
|
# Interaction happens at crosshair position.
|
||||||
|
#
|
||||||
|
# * Buttons with crosshair
|
||||||
|
# Use dedicated dig/place buttons to interact.
|
||||||
|
# Interaction happens at crosshair position.
|
||||||
|
#
|
||||||
|
# Requires: touchscreen
|
||||||
|
touch_interaction_style (Interaction style) enum tap tap,tap_crosshair,buttons_crosshair
|
||||||
|
|
||||||
|
# The gesture for punching players/entities.
|
||||||
|
# This can be overridden by games and mods.
|
||||||
|
#
|
||||||
|
# * Short tap
|
||||||
|
# Easy to use and well-known from other games that shall not be named.
|
||||||
|
#
|
||||||
|
# * Long tap
|
||||||
|
# Known from the classic Luanti mobile controls.
|
||||||
|
# Combat is more or less impossible.
|
||||||
|
#
|
||||||
|
# Requires: touchscreen, touch_interaction_style_tap
|
||||||
|
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
|
||||||
|
|
||||||
# Touchscreen sensitivity multiplier.
|
# Touchscreen sensitivity multiplier.
|
||||||
#
|
#
|
||||||
# Requires: touchscreen
|
# Requires: touchscreen
|
||||||
|
@ -175,12 +232,6 @@ touchscreen_threshold (Movement threshold) int 20 0 100
|
||||||
# Requires: touchscreen
|
# Requires: touchscreen
|
||||||
touch_long_tap_delay (Threshold for long taps) int 400 100 1000
|
touch_long_tap_delay (Threshold for long taps) int 400 100 1000
|
||||||
|
|
||||||
# Use crosshair to select object instead of whole screen.
|
|
||||||
# If enabled, a crosshair will be shown and will be used for selecting object.
|
|
||||||
#
|
|
||||||
# Requires: touchscreen
|
|
||||||
touch_use_crosshair (Use crosshair for touch screen) bool false
|
|
||||||
|
|
||||||
# Fixes the position of virtual joystick.
|
# Fixes the position of virtual joystick.
|
||||||
# If disabled, virtual joystick will center to first-touch's position.
|
# If disabled, virtual joystick will center to first-touch's position.
|
||||||
#
|
#
|
||||||
|
@ -193,21 +244,7 @@ fixed_virtual_joystick (Fixed virtual joystick) bool false
|
||||||
# Requires: touchscreen
|
# Requires: touchscreen
|
||||||
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
|
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
|
||||||
|
|
||||||
# The gesture for punching players/entities.
|
[Graphics and Audio] [client]
|
||||||
# This can be overridden by games and mods.
|
|
||||||
#
|
|
||||||
# * short_tap
|
|
||||||
# Easy to use and well-known from other games that shall not be named.
|
|
||||||
#
|
|
||||||
# * long_tap
|
|
||||||
# Known from the classic Luanti mobile controls.
|
|
||||||
# Combat is more or less impossible.
|
|
||||||
#
|
|
||||||
# Requires: touchscreen
|
|
||||||
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
|
|
||||||
|
|
||||||
|
|
||||||
[Graphics and Audio]
|
|
||||||
|
|
||||||
[*Graphics]
|
[*Graphics]
|
||||||
|
|
||||||
|
@ -256,8 +293,8 @@ fps_max (Maximum FPS) int 60 1 4294967295
|
||||||
# Vertical screen synchronization. Your system may still force VSync on even if this is disabled.
|
# Vertical screen synchronization. Your system may still force VSync on even if this is disabled.
|
||||||
vsync (VSync) bool false
|
vsync (VSync) bool false
|
||||||
|
|
||||||
# Maximum FPS when the window is not focused, or when the game is paused.
|
# Maximum FPS when the window is not focused.
|
||||||
fps_max_unfocused (FPS when unfocused or paused) int 20 1 4294967295
|
fps_max_unfocused (FPS when unfocused) int 10 1 4294967295
|
||||||
|
|
||||||
# View distance in nodes.
|
# View distance in nodes.
|
||||||
viewing_range (Viewing range) int 190 20 4000
|
viewing_range (Viewing range) int 190 20 4000
|
||||||
|
@ -295,10 +332,6 @@ arm_inertia (Arm inertia) bool true
|
||||||
# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
|
# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
|
||||||
view_bobbing_amount (View bobbing factor) float 1.0 0.0 7.9
|
view_bobbing_amount (View bobbing factor) float 1.0 0.0 7.9
|
||||||
|
|
||||||
# Multiplier for fall bobbing.
|
|
||||||
# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double.
|
|
||||||
fall_bobbing_amount (Fall bobbing factor) float 0.03 0.0 100.0
|
|
||||||
|
|
||||||
[**Camera]
|
[**Camera]
|
||||||
|
|
||||||
# Field of view in degrees.
|
# Field of view in degrees.
|
||||||
|
@ -541,8 +574,8 @@ shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true
|
||||||
# Requires: enable_dynamic_shadows, opengl
|
# Requires: enable_dynamic_shadows, opengl
|
||||||
shadow_filters (Shadow filter quality) enum 1 0,1,2
|
shadow_filters (Shadow filter quality) enum 1 0,1,2
|
||||||
|
|
||||||
# Enable colored shadows.
|
# Enable colored shadows for transculent nodes.
|
||||||
# On true translucent nodes cast colored shadows. This is expensive.
|
# This is expensive.
|
||||||
#
|
#
|
||||||
# Requires: enable_dynamic_shadows, opengl
|
# Requires: enable_dynamic_shadows, opengl
|
||||||
shadow_map_color (Colored shadows) bool false
|
shadow_map_color (Colored shadows) bool false
|
||||||
|
@ -742,9 +775,6 @@ console_color (Console color) string (0,0,0)
|
||||||
# In-game chat console background alpha (opaqueness, between 0 and 255).
|
# In-game chat console background alpha (opaqueness, between 0 and 255).
|
||||||
console_alpha (Console alpha) int 200 0 255
|
console_alpha (Console alpha) int 200 0 255
|
||||||
|
|
||||||
# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
|
|
||||||
clickable_chat_weblinks (Chat weblinks) bool true
|
|
||||||
|
|
||||||
# Optional override for chat weblink color.
|
# Optional override for chat weblink color.
|
||||||
chat_weblink_color (Weblink color) string #8888FF
|
chat_weblink_color (Weblink color) string #8888FF
|
||||||
|
|
||||||
|
@ -777,26 +807,26 @@ contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 1
|
||||||
|
|
||||||
[Client and Server]
|
[Client and Server]
|
||||||
|
|
||||||
[*Client]
|
[*Client] [client]
|
||||||
|
|
||||||
# Save the map received by the client on disk.
|
# Save the map received by the client on disk.
|
||||||
enable_local_map_saving (Saving map received from server) bool false
|
enable_local_map_saving (Saving map received from server) bool false
|
||||||
|
|
||||||
# URL to the server list displayed in the Multiplayer Tab.
|
# URL to the server list displayed in the Multiplayer Tab.
|
||||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
serverlist_url (Serverlist URL) [common] string https://servers.luanti.org
|
||||||
|
|
||||||
# If enabled, account registration is separate from login in the UI.
|
# If enabled, server account registration is separate from login in the UI.
|
||||||
# If disabled, new accounts will be registered automatically when logging in.
|
# If disabled, connecting to a server will automatically register a new account.
|
||||||
enable_split_login_register (Enable split login/register) bool true
|
enable_split_login_register (Enable split login/register) bool true
|
||||||
|
|
||||||
# URL to JSON file which provides information about the newest Luanti release.
|
# URL to JSON file which provides information about the newest Luanti release.
|
||||||
# If this is empty the engine will never check for updates.
|
# If this is empty the engine will never check for updates.
|
||||||
update_information_url (Update information URL) string https://www.minetest.net/release_info.json
|
update_information_url (Update information URL) string https://www.luanti.org/release_info.json
|
||||||
|
|
||||||
[*Server]
|
[*Server] [server]
|
||||||
|
|
||||||
# Name of the player.
|
# Name of the player.
|
||||||
# When running a server, clients connecting with this name are admins.
|
# When running a server, a client connecting with this name is admin.
|
||||||
# When starting from the main menu, this is overridden.
|
# When starting from the main menu, this is overridden.
|
||||||
name (Admin name) string
|
name (Admin name) string
|
||||||
|
|
||||||
|
@ -821,7 +851,7 @@ server_announce (Announce server) bool false
|
||||||
server_announce_send_players (Send player names to the server list) bool true
|
server_announce_send_players (Send player names to the server list) bool true
|
||||||
|
|
||||||
# Announce to this serverlist.
|
# Announce to this serverlist.
|
||||||
serverlist_url (Serverlist URL) string https://servers.luanti.org
|
serverlist_url (Serverlist URL) [common] string https://servers.luanti.org
|
||||||
|
|
||||||
# Message of the day displayed to players connecting.
|
# Message of the day displayed to players connecting.
|
||||||
motd (Message of the day) string
|
motd (Message of the day) string
|
||||||
|
@ -860,12 +890,14 @@ protocol_version_min (Protocol version minimum) int 1 1 65535
|
||||||
# Files that are not present will be fetched the usual way.
|
# Files that are not present will be fetched the usual way.
|
||||||
remote_media (Remote media) string
|
remote_media (Remote media) string
|
||||||
|
|
||||||
# Enable/disable running an IPv6 server.
|
# Enable IPv6 support for server.
|
||||||
|
# Note that clients will be able to connect with both IPv4 and IPv6.
|
||||||
# Ignored if bind_address is set.
|
# Ignored if bind_address is set.
|
||||||
# Needs enable_ipv6 to be enabled.
|
#
|
||||||
ipv6_server (IPv6 server) bool false
|
# Requires: enable_ipv6
|
||||||
|
ipv6_server (IPv6 server) bool true
|
||||||
|
|
||||||
[*Server Security]
|
[*Server Security] [server]
|
||||||
|
|
||||||
# New users need to input this password.
|
# New users need to input this password.
|
||||||
default_password (Default password) string
|
default_password (Default password) string
|
||||||
|
@ -925,7 +957,7 @@ chat_message_limit_per_10sec (Chat message count limit) float 8.0 1.0
|
||||||
# Kick players who sent more than X messages per 10 seconds.
|
# Kick players who sent more than X messages per 10 seconds.
|
||||||
chat_message_limit_trigger_kick (Chat message kick threshold) int 50 1 65535
|
chat_message_limit_trigger_kick (Chat message kick threshold) int 50 1 65535
|
||||||
|
|
||||||
[*Server Gameplay]
|
[*Server Gameplay] [server]
|
||||||
|
|
||||||
# Controls length of day/night cycle.
|
# Controls length of day/night cycle.
|
||||||
# Examples:
|
# Examples:
|
||||||
|
@ -933,7 +965,7 @@ chat_message_limit_trigger_kick (Chat message kick threshold) int 50 1 65535
|
||||||
time_speed (Time speed) int 72 0
|
time_speed (Time speed) int 72 0
|
||||||
|
|
||||||
# Time of day when a new world is started, in millihours (0-23999).
|
# Time of day when a new world is started, in millihours (0-23999).
|
||||||
world_start_time (World start time) int 6125 0 23999
|
world_start_time (World start time) [world_creation] int 6125 0 23999
|
||||||
|
|
||||||
# Time in seconds for item entity (dropped items) to live.
|
# Time in seconds for item entity (dropped items) to live.
|
||||||
# Setting it to -1 disables the feature.
|
# Setting it to -1 disables the feature.
|
||||||
|
@ -988,7 +1020,7 @@ movement_liquid_sink (Liquid sinking) float 10.0
|
||||||
movement_gravity (Gravity) float 9.81
|
movement_gravity (Gravity) float 9.81
|
||||||
|
|
||||||
|
|
||||||
[Mapgen]
|
[Mapgen] [world_creation]
|
||||||
|
|
||||||
# A chosen map seed for a new map, leave empty for random.
|
# A chosen map seed for a new map, leave empty for random.
|
||||||
# Will be overridden when creating a new world in the main menu.
|
# Will be overridden when creating a new world in the main menu.
|
||||||
|
@ -1004,7 +1036,7 @@ mg_name (Mapgen name) enum v7 v7,valleys,carpathian,v5,flat,fractal,singlenode,v
|
||||||
water_level (Water level) int 1 -31000 31000
|
water_level (Water level) int 1 -31000 31000
|
||||||
|
|
||||||
# From how far blocks are generated for clients, stated in mapblocks (16 nodes).
|
# From how far blocks are generated for clients, stated in mapblocks (16 nodes).
|
||||||
max_block_generate_distance (Max block generate distance) int 10 1 32767
|
max_block_generate_distance (Max block generate distance) [server] int 10 1 32767
|
||||||
|
|
||||||
# Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).
|
# Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).
|
||||||
# Only mapchunks completely within the mapgen limit are generated.
|
# Only mapchunks completely within the mapgen limit are generated.
|
||||||
|
@ -1717,12 +1749,12 @@ mgvalleys_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500),
|
||||||
|
|
||||||
# Enable Lua modding support on client.
|
# Enable Lua modding support on client.
|
||||||
# This support is experimental and API can change.
|
# This support is experimental and API can change.
|
||||||
enable_client_modding (Client modding) bool false
|
enable_client_modding (Client modding) [client] bool false
|
||||||
|
|
||||||
# Replaces the default main menu with a custom one.
|
# Replaces the default main menu with a custom one.
|
||||||
main_menu_script (Main menu script) string
|
main_menu_script (Main menu script) [client] string
|
||||||
|
|
||||||
[**Mod Security]
|
[**Mod Security] [server]
|
||||||
|
|
||||||
# Prevent mods from doing insecure things like running shell commands.
|
# Prevent mods from doing insecure things like running shell commands.
|
||||||
secure.enable_security (Enable mod security) bool true
|
secure.enable_security (Enable mod security) bool true
|
||||||
|
@ -1746,33 +1778,33 @@ secure.http_mods (HTTP mods) string
|
||||||
# - info
|
# - info
|
||||||
# - verbose
|
# - verbose
|
||||||
# - trace
|
# - trace
|
||||||
debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose,trace
|
debug_log_level (Debug log level) [common] enum action ,none,error,warning,action,info,verbose,trace
|
||||||
|
|
||||||
# If the file size of debug.txt exceeds the number of megabytes specified in
|
# If the file size of debug.txt exceeds the number of megabytes specified in
|
||||||
# this setting when it is opened, the file is moved to debug.txt.1,
|
# this setting when it is opened, the file is moved to debug.txt.1,
|
||||||
# deleting an older debug.txt.1 if it exists.
|
# deleting an older debug.txt.1 if it exists.
|
||||||
# debug.txt is only moved if this setting is positive.
|
# debug.txt is only moved if this setting is positive.
|
||||||
debug_log_size_max (Debug log file size threshold) int 50 1
|
debug_log_size_max (Debug log file size threshold) [common] int 50 1
|
||||||
|
|
||||||
# Minimal level of logging to be written to chat.
|
# Minimal level of logging to be written to chat.
|
||||||
chat_log_level (Chat log level) enum error ,none,error,warning,action,info,verbose,trace
|
chat_log_level (Chat log level) [client] enum error ,none,error,warning,action,info,verbose,trace
|
||||||
|
|
||||||
# Handling for deprecated Lua API calls:
|
# Handling for deprecated Lua API calls:
|
||||||
# - none: Do not log deprecated calls
|
# - none: Do not log deprecated calls
|
||||||
# - log: mimic and log backtrace of deprecated call (default).
|
# - log: mimic and log backtrace of deprecated call (default).
|
||||||
# - error: abort on usage of deprecated call (suggested for mod developers).
|
# - error: abort on usage of deprecated call (suggested for mod developers).
|
||||||
deprecated_lua_api_handling (Deprecated Lua API handling) enum log none,log,error
|
deprecated_lua_api_handling (Deprecated Lua API handling) [common] enum log none,log,error
|
||||||
|
|
||||||
# Enable random user input (only used for testing).
|
# Enable random user input (only used for testing).
|
||||||
random_input (Random input) bool false
|
random_input (Random input) [client] bool false
|
||||||
|
|
||||||
# Enable random mod loading (mainly used for testing).
|
# Enable random mod loading (mainly used for testing).
|
||||||
random_mod_load_order (Random mod load order) bool false
|
random_mod_load_order (Random mod load order) [server] bool false
|
||||||
|
|
||||||
# Enable mod channels support.
|
# Enable mod channels support.
|
||||||
enable_mod_channels (Mod channels) bool false
|
enable_mod_channels (Mod channels) [server] bool false
|
||||||
|
|
||||||
[**Mod Profiler]
|
[**Mod Profiler] [server]
|
||||||
|
|
||||||
# Load the game profiler to collect game profiling data.
|
# Load the game profiler to collect game profiling data.
|
||||||
# Provides a /profiler command to access the compiled profile.
|
# Provides a /profiler command to access the compiled profile.
|
||||||
|
@ -1812,7 +1844,7 @@ instrument.builtin (Builtin) bool false
|
||||||
# * Instrument the sampler being used to update the statistics.
|
# * Instrument the sampler being used to update the statistics.
|
||||||
instrument.profiler (Profiler) bool false
|
instrument.profiler (Profiler) bool false
|
||||||
|
|
||||||
[**Engine Profiler]
|
[**Engine Profiler] [common]
|
||||||
|
|
||||||
# Print the engine's profiling data in regular intervals (in seconds).
|
# Print the engine's profiling data in regular intervals (in seconds).
|
||||||
# 0 = disable. Useful for developers.
|
# 0 = disable. Useful for developers.
|
||||||
|
@ -1821,15 +1853,7 @@ profiler_print_interval (Engine profiling data print interval) int 0 0
|
||||||
|
|
||||||
[*Advanced]
|
[*Advanced]
|
||||||
|
|
||||||
# Enable IPv6 support (for both client and server).
|
[**Graphics] [client]
|
||||||
# Required for IPv6 connections to work at all.
|
|
||||||
enable_ipv6 (IPv6) bool true
|
|
||||||
|
|
||||||
# If enabled, invalid world data won't cause the server to shut down.
|
|
||||||
# Only enable this if you know what you are doing.
|
|
||||||
ignore_world_load_errors (Ignore world errors) bool false
|
|
||||||
|
|
||||||
[**Graphics]
|
|
||||||
|
|
||||||
# Enables debug and error-checking in the OpenGL driver.
|
# Enables debug and error-checking in the OpenGL driver.
|
||||||
opengl_debug (OpenGL debug) bool false
|
opengl_debug (OpenGL debug) bool false
|
||||||
|
@ -1866,7 +1890,7 @@ mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8
|
||||||
|
|
||||||
# All mesh buffers with less than this number of vertices will be merged
|
# All mesh buffers with less than this number of vertices will be merged
|
||||||
# during map rendering. This improves rendering performance.
|
# during map rendering. This improves rendering performance.
|
||||||
mesh_buffer_min_vertices (Minimum vertex count for mesh buffers) int 100 0 1000
|
mesh_buffer_min_vertices (Minimum vertex count for mesh buffers) int 300 0 1000
|
||||||
|
|
||||||
# True = 256
|
# True = 256
|
||||||
# False = 128
|
# False = 128
|
||||||
|
@ -1906,8 +1930,8 @@ texture_min_size (Base texture size) int 64 1 32768
|
||||||
client_mesh_chunk (Client Mesh Chunksize) int 1 1 16
|
client_mesh_chunk (Client Mesh Chunksize) int 1 1 16
|
||||||
|
|
||||||
# Decide the color depth of the texture used for the post-processing pipeline.
|
# Decide the color depth of the texture used for the post-processing pipeline.
|
||||||
# Reducing this can improve performance, but might cause some effects (e.g. bloom)
|
# Reducing this can improve performance, but some effects (e.g. debanding)
|
||||||
# to not work.
|
# require more than 8 bits to work.
|
||||||
#
|
#
|
||||||
# Requires: enable_post_processing
|
# Requires: enable_post_processing
|
||||||
post_processing_texture_bits (Color depth for post-processing texture) enum 16 8,10,16
|
post_processing_texture_bits (Color depth for post-processing texture) enum 16 8,10,16
|
||||||
|
@ -1918,10 +1942,9 @@ post_processing_texture_bits (Color depth for post-processing texture) enum 16 8
|
||||||
# Requires: enable_dynamic_shadows, opengl
|
# Requires: enable_dynamic_shadows, opengl
|
||||||
shadow_poisson_filter (Poisson filtering) bool true
|
shadow_poisson_filter (Poisson filtering) bool true
|
||||||
|
|
||||||
# Spread a complete update of shadow map over given number of frames.
|
# Spread a complete update of the shadow map over a given number of frames.
|
||||||
# Higher values might make shadows laggy, lower values
|
# Higher values might make shadows laggy, lower values
|
||||||
# will consume more resources.
|
# will consume more resources.
|
||||||
# Minimum value: 1; maximum value: 16
|
|
||||||
#
|
#
|
||||||
# Requires: enable_dynamic_shadows, opengl
|
# Requires: enable_dynamic_shadows, opengl
|
||||||
shadow_update_frames (Map shadows update frames) int 16 1 32
|
shadow_update_frames (Map shadows update frames) int 16 1 32
|
||||||
|
@ -1934,12 +1957,12 @@ shadow_update_frames (Map shadows update frames) int 16 1 32
|
||||||
# Requires: enable_post_processing, enable_bloom
|
# Requires: enable_post_processing, enable_bloom
|
||||||
enable_bloom_debug (Enable Bloom Debug) bool false
|
enable_bloom_debug (Enable Bloom Debug) bool false
|
||||||
|
|
||||||
[**Sound]
|
[**Sound] [client]
|
||||||
# Comma-separated list of AL and ALC extensions that should not be used.
|
# Comma-separated list of AL and ALC extensions that should not be used.
|
||||||
# Useful for testing. See al_extensions.[h,cpp] for details.
|
# Useful for testing. See al_extensions.[h,cpp] for details.
|
||||||
sound_extensions_blacklist (Sound Extensions Blacklist) string
|
sound_extensions_blacklist (Sound Extensions Blacklist) string
|
||||||
|
|
||||||
[**Font]
|
[**Font] [client]
|
||||||
|
|
||||||
font_bold (Font bold by default) bool false
|
font_bold (Font bold by default) bool false
|
||||||
|
|
||||||
|
@ -1989,7 +2012,7 @@ mono_font_path_bold_italic (Bold and italic monospace font path) filepath fonts/
|
||||||
# This font will be used for certain languages or if the default font is unavailable.
|
# This font will be used for certain languages or if the default font is unavailable.
|
||||||
fallback_font_path (Fallback font path) filepath fonts/DroidSansFallbackFull.ttf
|
fallback_font_path (Fallback font path) filepath fonts/DroidSansFallbackFull.ttf
|
||||||
|
|
||||||
[**Lighting]
|
[**Lighting] [client]
|
||||||
|
|
||||||
# Gradient of light curve at minimum light level.
|
# Gradient of light curve at minimum light level.
|
||||||
# Controls the contrast of the lowest light levels.
|
# Controls the contrast of the lowest light levels.
|
||||||
|
@ -2015,43 +2038,49 @@ lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
|
||||||
|
|
||||||
[**Networking]
|
[**Networking]
|
||||||
|
|
||||||
|
# Enable IPv6 support (for both client and server).
|
||||||
|
# Required for IPv6 connections to work at all.
|
||||||
|
enable_ipv6 (IPv6) [common] bool true
|
||||||
|
|
||||||
# Prometheus listener address.
|
# Prometheus listener address.
|
||||||
# If Luanti is compiled with ENABLE_PROMETHEUS option enabled,
|
# If Luanti is compiled with ENABLE_PROMETHEUS option enabled,
|
||||||
# enable metrics listener for Prometheus on that address.
|
# enable metrics listener for Prometheus on that address.
|
||||||
# Metrics can be fetched 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
|
prometheus_listener_address (Prometheus listener address) [server] string 127.0.0.1:30000
|
||||||
|
|
||||||
# Maximum size of the outgoing chat queue.
|
# Maximum size of the client's outgoing chat queue.
|
||||||
# 0 to disable queueing and -1 to make the queue size unlimited.
|
# 0 to disable queueing and -1 to make the queue size unlimited.
|
||||||
max_out_chat_queue_size (Maximum size of the outgoing chat queue) int 20 -1 32767
|
max_out_chat_queue_size (Maximum size of the client's outgoing chat queue) [client] int 20 -1 32767
|
||||||
|
|
||||||
# Timeout for client to remove unused map data from memory, in seconds.
|
# Timeout for client to remove unused map data from memory, in seconds.
|
||||||
client_unload_unused_data_timeout (Mapblock unload timeout) float 600.0 0.0
|
client_unload_unused_data_timeout (Mapblock unload timeout) [client] float 600.0 0.0
|
||||||
|
|
||||||
# Maximum number of mapblocks for client to be kept in memory.
|
# Maximum number of mapblocks for client to be kept in memory.
|
||||||
# Set to -1 for unlimited amount.
|
# Note that there is an internal dynamic minimum number of blocks that
|
||||||
client_mapblock_limit (Mapblock limit) int 7500 -1 2147483647
|
# won't be deleted, depending on the current view range.
|
||||||
|
# Set to -1 for no limit.
|
||||||
|
client_mapblock_limit (Mapblock limit) [client] int 7500 -1 2147483647
|
||||||
|
|
||||||
# Maximum number of blocks that are simultaneously sent per client.
|
# Maximum number of blocks that are simultaneously sent per client.
|
||||||
# The maximum total count is calculated dynamically:
|
# The maximum total count is calculated dynamically:
|
||||||
# max_total = ceil((#clients + max_users) * per_client / 4)
|
# max_total = ceil((#clients + max_users) * per_client / 4)
|
||||||
max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) int 40 1 4294967295
|
max_simultaneous_block_sends_per_client (Maximum simultaneous block sends per client) [server] int 40 1 4294967295
|
||||||
|
|
||||||
# To reduce lag, block transfers are slowed down when a player is building something.
|
# To reduce lag, block transfers are slowed down when a player is building something.
|
||||||
# This determines how long they are slowed down after placing or removing a node.
|
# This determines how long they are slowed down after placing or removing a node.
|
||||||
full_block_send_enable_min_time_from_building (Delay in sending blocks after building) float 2.0 0.0
|
full_block_send_enable_min_time_from_building (Delay in sending blocks after building) [server] float 2.0 0.0
|
||||||
|
|
||||||
# Maximum number of packets sent per send step in the low-level networking code.
|
# Maximum number of packets sent per send step in the low-level networking code.
|
||||||
# You generally don't need to change this, however busy servers may benefit from a higher number.
|
# You generally don't need to change this, however busy servers may benefit from a higher number.
|
||||||
max_packets_per_iteration (Max. packets per iteration) int 1024 1 65535
|
max_packets_per_iteration (Max. packets per iteration) [common] int 1024 1 65535
|
||||||
|
|
||||||
# Compression level to use when sending mapblocks to the client.
|
# Compression level to use when sending mapblocks to the client.
|
||||||
# -1 - use default compression level
|
# -1 - use default compression level
|
||||||
# 0 - least compression, fastest
|
# 0 - least compression, fastest
|
||||||
# 9 - best compression, slowest
|
# 9 - best compression, slowest
|
||||||
map_compression_level_net (Map Compression Level for Network Transfer) int -1 -1 9
|
map_compression_level_net (Map Compression Level for Network Transfer) [server] int -1 -1 9
|
||||||
|
|
||||||
[**Server]
|
[**Server] [server]
|
||||||
|
|
||||||
# Format of player chat messages. The following strings are valid placeholders:
|
# Format of player chat messages. The following strings are valid placeholders:
|
||||||
# @name, @message, @timestamp (optional)
|
# @name, @message, @timestamp (optional)
|
||||||
|
@ -2071,7 +2100,7 @@ kick_msg_crash (Crash message) string This server has experienced an internal er
|
||||||
# Set this to true if your server is set up to restart automatically.
|
# Set this to true if your server is set up to restart automatically.
|
||||||
ask_reconnect_on_crash (Ask to reconnect after crash) bool false
|
ask_reconnect_on_crash (Ask to reconnect after crash) bool false
|
||||||
|
|
||||||
[**Server/Env Performance]
|
[**Server/Env Performance] [server]
|
||||||
|
|
||||||
# Length of a server tick (the interval at which everything is generally updated),
|
# Length of a server tick (the interval at which everything is generally updated),
|
||||||
# stated in seconds.
|
# stated in seconds.
|
||||||
|
@ -2122,14 +2151,14 @@ max_objects_per_block (Maximum objects per block) int 256 256 65535
|
||||||
active_block_mgmt_interval (Active block management interval) float 2.0 0.0
|
active_block_mgmt_interval (Active block management interval) float 2.0 0.0
|
||||||
|
|
||||||
# Length of time between Active Block Modifier (ABM) execution cycles, stated in seconds.
|
# Length of time between Active Block Modifier (ABM) execution cycles, stated in seconds.
|
||||||
abm_interval (ABM interval) float 1.0 0.0
|
abm_interval (ABM interval) float 1.0 0.1 30.0
|
||||||
|
|
||||||
# The time budget allowed for ABMs to execute on each step
|
# The time budget allowed for ABMs to execute on each step
|
||||||
# (as a fraction of the ABM Interval)
|
# (as a fraction of the ABM Interval)
|
||||||
abm_time_budget (ABM time budget) float 0.2 0.1 0.9
|
abm_time_budget (ABM time budget) float 0.2 0.1 0.9
|
||||||
|
|
||||||
# Length of time between NodeTimer execution cycles, stated in seconds.
|
# Length of time between NodeTimer execution cycles, stated in seconds.
|
||||||
nodetimer_interval (NodeTimer interval) float 0.2 0.0
|
nodetimer_interval (NodeTimer interval) float 0.2 0.1 1.0
|
||||||
|
|
||||||
# Max liquids processed per step.
|
# Max liquids processed per step.
|
||||||
liquid_loop_max (Liquid loop max) int 100000 1 4294967295
|
liquid_loop_max (Liquid loop max) int 100000 1 4294967295
|
||||||
|
@ -2164,7 +2193,7 @@ server_side_occlusion_culling (Server-side occlusion culling) bool true
|
||||||
# Stated in MapBlocks (16 nodes).
|
# Stated in MapBlocks (16 nodes).
|
||||||
block_cull_optimize_distance (Block cull optimize distance) int 25 2 2047
|
block_cull_optimize_distance (Block cull optimize distance) int 25 2 2047
|
||||||
|
|
||||||
[**Mapgen]
|
[**Mapgen] [server]
|
||||||
|
|
||||||
# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).
|
# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).
|
||||||
# WARNING: There is no benefit, and there are several dangers, in
|
# WARNING: There is no benefit, and there are several dangers, in
|
||||||
|
@ -2172,7 +2201,7 @@ block_cull_optimize_distance (Block cull optimize distance) int 25 2 2047
|
||||||
# Reducing this value increases cave and dungeon density.
|
# Reducing this value increases cave and dungeon density.
|
||||||
# Altering this value is for special usage, leaving it unchanged is
|
# Altering this value is for special usage, leaving it unchanged is
|
||||||
# recommended.
|
# recommended.
|
||||||
chunksize (Chunk size) int 5 1 10
|
chunksize (Chunk size) [world_creation] int 5 1 10
|
||||||
|
|
||||||
# Dump the mapgen debug information.
|
# Dump the mapgen debug information.
|
||||||
enable_mapgen_debug_info (Mapgen debug) bool false
|
enable_mapgen_debug_info (Mapgen debug) bool false
|
||||||
|
@ -2200,7 +2229,7 @@ emergequeue_limit_generate (Per-player limit of queued blocks to generate) int 1
|
||||||
# 'on_generated'. For many users the optimum setting may be '1'.
|
# 'on_generated'. For many users the optimum setting may be '1'.
|
||||||
num_emerge_threads (Number of emerge threads) int 1 0 32767
|
num_emerge_threads (Number of emerge threads) int 1 0 32767
|
||||||
|
|
||||||
[**cURL]
|
[**cURL] [common]
|
||||||
|
|
||||||
# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
|
# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
|
||||||
curl_timeout (cURL interactive timeout) int 20000 1000 2147483647
|
curl_timeout (cURL interactive timeout) int 20000 1000 2147483647
|
||||||
|
@ -2217,42 +2246,49 @@ curl_file_download_timeout (cURL file download timeout) int 300000 5000 21474836
|
||||||
|
|
||||||
[**Miscellaneous]
|
[**Miscellaneous]
|
||||||
|
|
||||||
|
# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output.
|
||||||
|
clickable_chat_weblinks (Chat weblinks) [client] bool true
|
||||||
|
|
||||||
|
# If enabled, invalid world data won't cause the server to shut down.
|
||||||
|
# Only enable this if you know what you are doing.
|
||||||
|
ignore_world_load_errors (Ignore world errors) [server] bool false
|
||||||
|
|
||||||
# Adjust the detected display density, used for scaling UI elements.
|
# Adjust the detected display density, used for scaling UI elements.
|
||||||
display_density_factor (Display Density Scaling Factor) float 1 0.5 5.0
|
display_density_factor (Display Density Scaling Factor) [client] float 1 0.5 5.0
|
||||||
|
|
||||||
# Windows systems only: Start Luanti with the command line window in the background.
|
# Windows systems only: Start Luanti with the command line window in the background.
|
||||||
# Contains the same information as the file debug.txt (default name).
|
# Contains the same information as the file debug.txt (default name).
|
||||||
enable_console (Enable console window) bool false
|
enable_console (Enable console window) [common] bool false
|
||||||
|
|
||||||
# Number of extra blocks that can be loaded by /clearobjects at once.
|
# Number of extra blocks that can be loaded by /clearobjects at once.
|
||||||
# This is a trade-off between SQLite transaction overhead and
|
# This is a trade-off between SQLite transaction overhead and
|
||||||
# memory consumption (4096=100MB, as a rule of thumb).
|
# memory consumption (4096=100MB, as a rule of thumb).
|
||||||
max_clearobjects_extra_loaded_blocks (Max. clearobjects extra blocks) int 4096 0 4294967295
|
max_clearobjects_extra_loaded_blocks (Max. clearobjects extra blocks) [server] int 4096 0 4294967295
|
||||||
|
|
||||||
# World directory (everything in the world is stored here).
|
# World directory (everything in the world is stored here).
|
||||||
# Not needed if starting from the main menu.
|
# Not needed if starting from the main menu.
|
||||||
map-dir (Map directory) path
|
map-dir (Map directory) [server] path
|
||||||
|
|
||||||
# See https://www.sqlite.org/pragma.html#pragma_synchronous
|
# See https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||||
sqlite_synchronous (Synchronous SQLite) enum 2 0,1,2
|
sqlite_synchronous (Synchronous SQLite) [server] enum 2 0,1,2
|
||||||
|
|
||||||
# Compression level to use when saving mapblocks to disk.
|
# Compression level to use when saving mapblocks to disk.
|
||||||
# -1 - use default compression level
|
# -1 - use default compression level
|
||||||
# 0 - least compression, fastest
|
# 0 - least compression, fastest
|
||||||
# 9 - best compression, slowest
|
# 9 - best compression, slowest
|
||||||
map_compression_level_disk (Map Compression Level for Disk Storage) int -1 -1 9
|
map_compression_level_disk (Map Compression Level for Disk Storage) [server] int -1 -1 9
|
||||||
|
|
||||||
# Enable usage of remote media server (if provided by server).
|
# Enable usage of remote media server (if provided by server).
|
||||||
# Remote servers offer a significantly faster way to download media (e.g. textures)
|
# Remote servers offer a significantly faster way to download media (e.g. textures)
|
||||||
# when connecting to the server.
|
# when connecting to the server.
|
||||||
enable_remote_media_server (Connect to external media server) bool true
|
enable_remote_media_server (Connect to external media server) [client] bool true
|
||||||
|
|
||||||
# File in client/serverlist/ that contains your favorite servers displayed in the
|
# File in client/serverlist/ that contains your favorite servers displayed in the
|
||||||
# Multiplayer Tab.
|
# Multiplayer Tab.
|
||||||
serverlist_file (Serverlist file) string favoriteservers.json
|
serverlist_file (Serverlist file) [client] string favoriteservers.json
|
||||||
|
|
||||||
|
|
||||||
[*Gamepads]
|
[*Gamepads] [client]
|
||||||
|
|
||||||
# Enable joysticks. Requires a restart to take effect
|
# Enable joysticks. Requires a restart to take effect
|
||||||
enable_joysticks (Enable joysticks) bool false
|
enable_joysticks (Enable joysticks) bool false
|
||||||
|
@ -2275,7 +2311,7 @@ joystick_deadzone (Joystick dead zone) int 2048 0 65535
|
||||||
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170.0 0.001
|
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170.0 0.001
|
||||||
|
|
||||||
|
|
||||||
[*Hide: Temporary Settings]
|
[*Hide: Temporary Settings] [common]
|
||||||
|
|
||||||
# Path to texture directory. All textures are first searched from here.
|
# Path to texture directory. All textures are first searched from here.
|
||||||
texture_path (Texture path) path
|
texture_path (Texture path) path
|
||||||
|
|
|
@ -44,8 +44,6 @@ centroid varying float nightRatio;
|
||||||
varying float perspective_factor;
|
varying float perspective_factor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
varying float area_enable_parallax;
|
|
||||||
|
|
||||||
varying highp vec3 eyeVec;
|
varying highp vec3 eyeVec;
|
||||||
varying vec3 sunTint;
|
varying vec3 sunTint;
|
||||||
varying float nightFactor;
|
varying float nightFactor;
|
||||||
|
|
|
@ -70,7 +70,7 @@ vec4 applyBloom(vec4 color, vec2 uv)
|
||||||
equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
|
equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// see https://github.com/minetest/minetest/pull/14688
|
// highp for GLES, see <https://github.com/luanti-org/luanti/pull/14688>
|
||||||
highp vec3 uncharted2Tonemap(highp vec3 x)
|
highp vec3 uncharted2Tonemap(highp vec3 x)
|
||||||
{
|
{
|
||||||
return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333;
|
return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Project properties
|
# Project properties
|
||||||
PROJECT_NAME = @PROJECT_NAME_CAPITALIZED@
|
PROJECT_NAME = @PROJECT_NAME_CAPITALIZED@
|
||||||
PROJECT_NUMBER = @VERSION_STRING@
|
PROJECT_NUMBER = @VERSION_STRING@
|
||||||
PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/misc/minetest.svg
|
PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/misc/luanti.svg
|
||||||
|
|
||||||
# Parsing
|
# Parsing
|
||||||
JAVADOC_AUTOBRIEF = YES
|
JAVADOC_AUTOBRIEF = YES
|
||||||
|
|
|
@ -10,15 +10,16 @@ This list is largely advisory and items may be reevaluated once the time comes.
|
||||||
* `game.conf` name/id mess
|
* `game.conf` name/id mess
|
||||||
* remove `depends.txt` / `description.txt` (would simplify ContentDB and Luanti code a little)
|
* remove `depends.txt` / `description.txt` (would simplify ContentDB and Luanti code a little)
|
||||||
* rotate moon texture by 180°, making it coherent with the sun
|
* rotate moon texture by 180°, making it coherent with the sun
|
||||||
* https://github.com/minetest/minetest/pull/11902
|
* https://github.com/luanti-org/luanti/pull/11902
|
||||||
* remove undocumented `set_physics_override(num, num, num)`
|
* remove undocumented `set_physics_override(num, num, num)`
|
||||||
* remove special handling of `${key}` syntax in metadata values
|
* remove special handling of `${key}` syntax in metadata values
|
||||||
* remove old_move
|
* remove old_move
|
||||||
* change physics_override `sneak` to disable the speed change and not just the node clipping
|
* change physics_override `sneak` to disable the speed change and not just the node clipping
|
||||||
* https://github.com/minetest/minetest/issues/13699
|
* https://github.com/luanti-org/luanti/issues/13699
|
||||||
* migrate from player names to UUIDs, this would enable renaming of accounts and unicode player names (if desired)
|
* migrate from player names to UUIDs, this would enable renaming of accounts and unicode player names (if desired)
|
||||||
* harmonize use_texture_alpha between entities & nodes, change default to 'opaque' and remove bool compat code
|
* harmonize use_texture_alpha between entities & nodes, change default to 'opaque' and remove bool compat code
|
||||||
* merge `sound` and `sounds` table in itemdef
|
* merge `sound` and `sounds` table in itemdef
|
||||||
* remove `DIR_DELIM` from Lua
|
* remove `DIR_DELIM` from Lua
|
||||||
* stop reading initial properties from bare entity def
|
* stop reading initial properties from bare entity def
|
||||||
* change particle default blend mode to `clip`
|
* change particle default blend mode to `clip`
|
||||||
|
* remove built-in knockback and related functions entirely
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
Luanti Lua Client Modding API Reference 5.11.0
|
Luanti Lua Client Modding API Reference 5.12.0
|
||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
**WARNING**: if you're looking for the `minetest` namespace (e.g. `minetest.something`),
|
**WARNING**: if you're looking for the `minetest` namespace (e.g. `minetest.something`),
|
||||||
it's now called `core` due to the renaming of Luanti (formerly Minetest).
|
it's now called `core` due to the renaming of Luanti (formerly Minetest).
|
||||||
`minetest` will keep existing as an alias, so that old code won't break.
|
`minetest` will keep existing as an alias, so that old code won't break.
|
||||||
|
|
||||||
* More information at <http://www.minetest.net/>
|
* More information at <http://www.luanti.org/>
|
||||||
* Developer Wiki: <http://dev.minetest.net/>
|
* Developer Wiki: <https://dev.luanti.org/>
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
@ -23,7 +23,7 @@ Transferring client-sided mods from the server to the client is planned, but not
|
||||||
|
|
||||||
If you see a deficiency in the API, feel free to attempt to add the
|
If you see a deficiency in the API, feel free to attempt to add the
|
||||||
functionality in the engine and API. You can send such improvements as
|
functionality in the engine and API. You can send such improvements as
|
||||||
source code patches on GitHub (https://github.com/minetest/minetest).
|
source code patches on GitHub.
|
||||||
|
|
||||||
Programming in Lua
|
Programming in Lua
|
||||||
------------------
|
------------------
|
||||||
|
|
|
@ -70,14 +70,14 @@ For Void users:
|
||||||
|
|
||||||
Download source (this is the URL to the latest of source repository, which might not work at all times) using Git:
|
Download source (this is the URL to the latest of source repository, which might not work at all times) using Git:
|
||||||
|
|
||||||
git clone --depth 1 https://github.com/minetest/minetest.git
|
git clone --depth 1 https://github.com/luanti-org/luanti
|
||||||
cd minetest
|
cd luanti
|
||||||
|
|
||||||
Download source, without using Git:
|
Download source, without using Git:
|
||||||
|
|
||||||
wget https://github.com/minetest/minetest/archive/master.tar.gz
|
wget https://github.com/luanti-org/luanti/archive/master.tar.gz
|
||||||
tar xf master.tar.gz
|
tar xf master.tar.gz
|
||||||
cd minetest-master
|
cd luanti-master
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ Build a version that runs directly from the source directory:
|
||||||
|
|
||||||
Run it:
|
Run it:
|
||||||
|
|
||||||
./bin/minetest
|
./bin/luanti
|
||||||
|
|
||||||
- Use `cmake . -LH` to see all CMake options and their current state.
|
- Use `cmake . -LH` to see all CMake options and their current state.
|
||||||
- If you want to install it system-wide (or are making a distribution package),
|
- If you want to install it system-wide (or are making a distribution package),
|
||||||
|
|
|
@ -16,7 +16,7 @@ brew install cmake freetype gettext gmp hiredis jpeg-turbo jsoncpp leveldb libog
|
||||||
Download source (this is the URL to the latest of source repository, which might not work at all times) using Git:
|
Download source (this is the URL to the latest of source repository, which might not work at all times) using Git:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone --depth 1 https://github.com/minetest/minetest.git luanti
|
git clone --depth 1 https://github.com/luanti-org/luanti luanti
|
||||||
cd luanti
|
cd luanti
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,8 @@ Use `--triplet` to specify the target triplet, e.g. `x64-windows` or `x86-window
|
||||||
### a) Using the vcpkg toolchain and CMake GUI
|
### a) Using the vcpkg toolchain and CMake GUI
|
||||||
|
|
||||||
1. Start up the CMake GUI
|
1. Start up the CMake GUI
|
||||||
2. Select **Browse Source...** and select DIR/minetest
|
2. Select **Browse Source...** and select DIR/luanti
|
||||||
3. Select **Browse Build...** and select DIR/minetest-build
|
3. Select **Browse Build...** and select DIR/luanti-build
|
||||||
4. Select **Configure**
|
4. Select **Configure**
|
||||||
5. Choose the right visual Studio version and target platform. It has to match the version of the installed dependencies
|
5. Choose the right visual Studio version and target platform. It has to match the version of the installed dependencies
|
||||||
6. Choose **Specify toolchain file for cross-compiling**
|
6. Choose **Specify toolchain file for cross-compiling**
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
## Wiki
|
## Wiki
|
||||||
|
|
||||||
Some important development docs are found in the wiki: https://dev.minetest.net/
|
Some important development docs are found in the wiki: https://dev.luanti.org/
|
||||||
|
|
||||||
Notable pages:
|
Notable pages:
|
||||||
|
|
||||||
- [Releasing Luanti](https://dev.minetest.net/Releasing_Minetest)
|
- [Releasing Luanti](https://dev.luanti.org/Releasing_Luanti)
|
||||||
- [Engine translations](https://dev.minetest.net/Translation#Maintaining_engine_translations)
|
- [Engine translations](https://dev.luanti.org/Translation#Maintaining_engine_translations)
|
||||||
- [Changelog](https://dev.minetest.net/Changelog)
|
- [Changelog](https://dev.luanti.org/Changelog)
|
||||||
- [Organisation](https://dev.minetest.net/Organisation)
|
- [Organisation](https://dev.luanti.org/Organisation)
|
||||||
- [Code style guidelines](https://dev.minetest.net/Code_style_guidelines)
|
- [Code style guidelines](https://dev.luanti.org/Code_style_guidelines)
|
||||||
|
|
||||||
## In this folder
|
## In this folder
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Sign the Android APK from CI
|
## Sign the Android APK from CI
|
||||||
|
|
||||||
The [Github Actions Workflow](https://github.com/minetest/minetest/actions?query=workflow%3Aandroid+event%3Apush)
|
The [Github Actions Workflow](https://github.com/luanti-org/luanti/actions?query=workflow%3Aandroid+event%3Apush)
|
||||||
automatically produces an APK for each architecture.
|
automatically produces an APK for each architecture.
|
||||||
Before installing them onto a device they however need to be signed.
|
Before installing them onto a device they however need to be signed.
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ To get usable results you need to build Luanti with debug symbols
|
||||||
|
|
||||||
Run the client (or server) like this and do whatever you wanted to test:
|
Run the client (or server) like this and do whatever you wanted to test:
|
||||||
```bash
|
```bash
|
||||||
perf record -z --call-graph dwarf -- ./bin/minetest
|
perf record -z --call-graph dwarf -- ./bin/luanti
|
||||||
```
|
```
|
||||||
|
|
||||||
This will leave a file called "perf.data".
|
This will leave a file called "perf.data".
|
||||||
|
|
|
@ -7,7 +7,7 @@ following documents:
|
||||||
|
|
||||||
* [What is Minetest?](http://c55.me/blog/?p=1491)
|
* [What is Minetest?](http://c55.me/blog/?p=1491)
|
||||||
* [celeron55's roadmap](https://forum.luanti.org/viewtopic.php?t=9177)
|
* [celeron55's roadmap](https://forum.luanti.org/viewtopic.php?t=9177)
|
||||||
* [celeron55's comment in "A clear mission statement for Minetest is missing"](https://github.com/minetest/minetest/issues/3476#issuecomment-167399287)
|
* [celeron55's comment in "A clear mission statement for Minetest is missing"](https://github.com/luanti-org/luanti/issues/3476#issuecomment-167399287)
|
||||||
* [Core developer to-do/wish lists](https://forum.luanti.org/viewforum.php?f=7)
|
* [Core developer to-do/wish lists](https://forum.luanti.org/viewforum.php?f=7)
|
||||||
|
|
||||||
## 2. Medium-term Roadmap
|
## 2. Medium-term Roadmap
|
||||||
|
@ -16,7 +16,7 @@ These are the current medium-term goals for Luanti development, in no
|
||||||
particular order.
|
particular order.
|
||||||
|
|
||||||
These goals were created from the top points in a
|
These goals were created from the top points in a
|
||||||
[roadmap brainstorm](https://github.com/minetest/minetest/issues/10461).
|
[roadmap brainstorm](https://github.com/luanti-org/luanti/issues/10461).
|
||||||
This should be reviewed approximately yearly, or when goals are achieved.
|
This should be reviewed approximately yearly, or when goals are achieved.
|
||||||
|
|
||||||
Pull requests that address one of these goals will be labeled as "Roadmap".
|
Pull requests that address one of these goals will be labeled as "Roadmap".
|
||||||
|
@ -32,9 +32,9 @@ Once that is done, fancier features can be worked on, such as water shaders,
|
||||||
shadows, and improved lighting.
|
shadows, and improved lighting.
|
||||||
|
|
||||||
Examples include
|
Examples include
|
||||||
[transparency sorting](https://github.com/minetest/minetest/issues/95),
|
[transparency sorting](https://github.com/luanti-org/luanti/issues/95),
|
||||||
[particle performance](https://github.com/minetest/minetest/issues/1414),
|
[particle performance](https://github.com/luanti-org/luanti/issues/1414),
|
||||||
[general view distance](https://github.com/minetest/minetest/issues/7222).
|
[general view distance](https://github.com/luanti-org/luanti/issues/7222).
|
||||||
|
|
||||||
This includes work on maintaining
|
This includes work on maintaining
|
||||||
[our Irrlicht fork](https://github.com/minetest/irrlicht), and switching to
|
[our Irrlicht fork](https://github.com/minetest/irrlicht), and switching to
|
||||||
|
@ -43,16 +43,16 @@ alternative libraries to replace Irrlicht functionality as needed
|
||||||
### 2.2 Internal code refactoring
|
### 2.2 Internal code refactoring
|
||||||
|
|
||||||
To ensure sustainable development, Luanti's code needs to be
|
To ensure sustainable development, Luanti's code needs to be
|
||||||
[refactored and improved](https://github.com/minetest/minetest/pulls?q=is%3Aopen+sort%3Aupdated-desc+label%3A%22Code+quality%22+).
|
[refactored and improved](https://github.com/luanti-org/luanti/pulls?q=is%3Aopen+sort%3Aupdated-desc+label%3A%22Code+quality%22).
|
||||||
This will remove code rot and allow for more efficient development.
|
This will remove code rot and allow for more efficient development.
|
||||||
|
|
||||||
### 2.3 UI Improvements
|
### 2.3 UI Improvements
|
||||||
|
|
||||||
A [formspec replacement](https://github.com/minetest/minetest/issues/6527) is
|
A [formspec replacement](https://github.com/luanti-org/luanti/issues/6527) is
|
||||||
needed to make GUIs better and easier to create. This replacement could also
|
needed to make GUIs better and easier to create. This replacement could also
|
||||||
be a replacement for HUDs, allowing for a unified API.
|
be a replacement for HUDs, allowing for a unified API.
|
||||||
|
|
||||||
A [new mainmenu](https://github.com/minetest/minetest/issues/6733) is needed to
|
A [new mainmenu](https://github.com/luanti-org/luanti/issues/6733) is needed to
|
||||||
improve user experience. First impressions matter, and the current main menu
|
improve user experience. First impressions matter, and the current main menu
|
||||||
doesn't do a very good job at selling Luanti or explaining what it is.
|
doesn't do a very good job at selling Luanti or explaining what it is.
|
||||||
A new main menu should promote games to users, allowing Minetest Game to no
|
A new main menu should promote games to users, allowing Minetest Game to no
|
||||||
|
@ -65,5 +65,5 @@ an issue for any large changes before spending lots of time.
|
||||||
|
|
||||||
There are still a significant number of issues with objects.
|
There are still a significant number of issues with objects.
|
||||||
Collisions,
|
Collisions,
|
||||||
[performance](https://github.com/minetest/minetest/issues/6453),
|
[performance](https://github.com/luanti-org/luanti/issues/6453),
|
||||||
API convenience, and discrepancies between players and entities.
|
API convenience, and discrepancies between players and entities.
|
||||||
|
|
|
@ -4,22 +4,25 @@ We provide Luanti server Docker images using the GitHub container registry.
|
||||||
|
|
||||||
Images are built on each commit and available using the following tag scheme:
|
Images are built on each commit and available using the following tag scheme:
|
||||||
|
|
||||||
* `ghcr.io/minetest/minetest:master` (latest build)
|
* `ghcr.io/luanti-org/luanti:master` (latest build)
|
||||||
* `ghcr.io/minetest/minetest:<tag>` (specific Git tag)
|
* `ghcr.io/luanti-org/luanti:<tag>` (specific Git tag)
|
||||||
* `ghcr.io/minetest/minetest:latest` (latest Git tag, which is the stable release)
|
* `ghcr.io/luanti-org/luanti:latest` (latest Git tag, which is the stable release)
|
||||||
|
|
||||||
See [here](https://github.com/minetest/minetest/pkgs/container/minetest) for all available tags.
|
See [here](https://github.com/luanti-org/luanti/pkgs/container/luanti) for all available tags.
|
||||||
|
|
||||||
|
Versions released before the project was renamed are available with the same tag scheme at `ghcr.io/minetest/minetest`.
|
||||||
|
See [here](https://github.com/orgs/minetest/packages/container/package/minetest) for all available tags.
|
||||||
|
|
||||||
For a quick test you can easily run:
|
For a quick test you can easily run:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker run ghcr.io/minetest/minetest:master
|
docker run ghcr.io/luanti-org/luanti:master
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it in a production environment, you should use volumes bound to the Docker host to persist data and modify the configuration:
|
To use it in a production environment, you should use volumes bound to the Docker host to persist data and modify the configuration:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker create -v /home/minetest/data/:/var/lib/minetest/ -v /home/minetest/conf/:/etc/minetest/ ghcr.io/minetest/minetest:master
|
docker create -v /home/minetest/data/:/var/lib/minetest/ -v /home/minetest/conf/:/etc/minetest/ ghcr.io/luanti-org/luanti:master
|
||||||
```
|
```
|
||||||
|
|
||||||
You may also want to use [Docker Compose](https://docs.docker.com/compose):
|
You may also want to use [Docker Compose](https://docs.docker.com/compose):
|
||||||
|
@ -29,7 +32,7 @@ You may also want to use [Docker Compose](https://docs.docker.com/compose):
|
||||||
version: "2"
|
version: "2"
|
||||||
services:
|
services:
|
||||||
minetest_server:
|
minetest_server:
|
||||||
image: ghcr.io/minetest/minetest:master
|
image: ghcr.io/luanti-org/luanti:master
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- default
|
- default
|
||||||
|
|
365
doc/lua_api.md
365
doc/lua_api.md
|
@ -5,10 +5,10 @@ Luanti Lua Modding API Reference
|
||||||
it's now called `core` due to the renaming of Luanti (formerly Minetest).
|
it's now called `core` due to the renaming of Luanti (formerly Minetest).
|
||||||
`minetest` will keep existing as an alias, so that old code won't break.
|
`minetest` will keep existing as an alias, so that old code won't break.
|
||||||
|
|
||||||
* More information at <http://www.minetest.net/>
|
* More information at <http://www.luanti.org/>
|
||||||
* Developer Wiki: <http://dev.minetest.net/>
|
* Developer Wiki: <https://dev.luanti.org/>
|
||||||
* (Unofficial) Minetest Modding Book by rubenwardy: <https://rubenwardy.com/minetest_modding_book/>
|
* (Unofficial) Minetest Modding Book by rubenwardy: <https://rubenwardy.com/minetest_modding_book/>
|
||||||
* Modding tools: <https://github.com/minetest/modtools>
|
* Modding tools: <https://github.com/luanti-org/modtools>
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
@ -194,7 +194,8 @@ Mod directory structure
|
||||||
│ │ │ └── another_subfolder
|
│ │ │ └── another_subfolder
|
||||||
│ │ └── bar_subfolder
|
│ │ └── bar_subfolder
|
||||||
│ ├── sounds
|
│ ├── sounds
|
||||||
│ ├── media
|
│ ├── fonts
|
||||||
|
│ ├── media
|
||||||
│ ├── locale
|
│ ├── locale
|
||||||
│ └── <custom data>
|
│ └── <custom data>
|
||||||
└── another
|
└── another
|
||||||
|
@ -265,7 +266,7 @@ The main Lua script. Running this script should register everything it
|
||||||
wants to register. Subsequent execution depends on Luanti calling the
|
wants to register. Subsequent execution depends on Luanti calling the
|
||||||
registered callbacks.
|
registered callbacks.
|
||||||
|
|
||||||
### `textures`, `sounds`, `media`, `models`, `locale`
|
### `textures`, `sounds`, `media`, `models`, `locale`, `fonts`
|
||||||
|
|
||||||
Media files (textures, sounds, whatever) that will be transferred to the
|
Media files (textures, sounds, whatever) that will be transferred to the
|
||||||
client and will be available for use by the mod and translation files for
|
client and will be available for use by the mod and translation files for
|
||||||
|
@ -278,6 +279,7 @@ Accepted formats are:
|
||||||
images: .png, .jpg, .tga
|
images: .png, .jpg, .tga
|
||||||
sounds: .ogg vorbis
|
sounds: .ogg vorbis
|
||||||
models: .x, .b3d, .obj, (since version 5.10:) .gltf, .glb
|
models: .x, .b3d, .obj, (since version 5.10:) .gltf, .glb
|
||||||
|
fonts: .ttf, .woff (both since version 5.11, see notes below)
|
||||||
|
|
||||||
Other formats won't be sent to the client (e.g. you can store .blend files
|
Other formats won't be sent to the client (e.g. you can store .blend files
|
||||||
in a folder for convenience, without the risk that such files are transferred)
|
in a folder for convenience, without the risk that such files are transferred)
|
||||||
|
@ -325,7 +327,7 @@ Many glTF features are not supported *yet*, including:
|
||||||
* Double-sided materials don't work
|
* Double-sided materials don't work
|
||||||
* Alternative means of supplying data
|
* Alternative means of supplying data
|
||||||
* Embedded images. You can use `gltfutil.py` from the
|
* Embedded images. You can use `gltfutil.py` from the
|
||||||
[modding tools](https://github.com/minetest/modtools) to strip or extract embedded images.
|
[modding tools](https://github.com/luanti-org/modtools) to strip or extract embedded images.
|
||||||
* References to files via URIs
|
* References to files via URIs
|
||||||
|
|
||||||
Textures are supplied solely via the same means as for the other model file formats:
|
Textures are supplied solely via the same means as for the other model file formats:
|
||||||
|
@ -342,6 +344,28 @@ For example, if your model used an emissive material,
|
||||||
you should expect that a future version of Luanti may respect this,
|
you should expect that a future version of Luanti may respect this,
|
||||||
and thus cause your model to render differently there.
|
and thus cause your model to render differently there.
|
||||||
|
|
||||||
|
#### Custom fonts
|
||||||
|
|
||||||
|
You can supply custom fonts in TrueType Font (`.ttf`) or Web Open Font Format (`.woff`) format.
|
||||||
|
The former is supported primarily for convenience. The latter is preferred due to its compression.
|
||||||
|
|
||||||
|
In the future, having multiple custom fonts and the ability to switch between them is planned,
|
||||||
|
but for now this feature is limited to the ability to override Luanti's default fonts via mods.
|
||||||
|
It is recommended that this only be used by game mods to set a look and feel.
|
||||||
|
|
||||||
|
The stems (file names without extension) are self-explanatory:
|
||||||
|
|
||||||
|
* Regular variants:
|
||||||
|
* `regular`
|
||||||
|
* `bold`
|
||||||
|
* `italic`
|
||||||
|
* `bold_italic`
|
||||||
|
* Monospaced variants:
|
||||||
|
* `mono`
|
||||||
|
* `mono_bold`
|
||||||
|
* `mono_italic`
|
||||||
|
* `mono_bold_italic`
|
||||||
|
|
||||||
Naming conventions
|
Naming conventions
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -1460,8 +1484,6 @@ Node drawtypes
|
||||||
|
|
||||||
There are a bunch of different looking node types.
|
There are a bunch of different looking node types.
|
||||||
|
|
||||||
Look for examples in `games/devtest` or `games/minetest_game`.
|
|
||||||
|
|
||||||
* `normal`
|
* `normal`
|
||||||
* A node-sized cube.
|
* A node-sized cube.
|
||||||
* `airlike`
|
* `airlike`
|
||||||
|
@ -1500,7 +1522,7 @@ Look for examples in `games/devtest` or `games/minetest_game`.
|
||||||
* `allfaces`
|
* `allfaces`
|
||||||
* Often used for partially-transparent nodes.
|
* Often used for partially-transparent nodes.
|
||||||
* External sides of textures, and unlike other drawtypes, the external sides
|
* External sides of textures, and unlike other drawtypes, the external sides
|
||||||
of other blocks, are visible from the inside.
|
of other nodes, are visible from the inside.
|
||||||
* `allfaces_optional`
|
* `allfaces_optional`
|
||||||
* Often used for leaves nodes.
|
* Often used for leaves nodes.
|
||||||
* This switches between `normal`, `glasslike` and `allfaces` according to
|
* This switches between `normal`, `glasslike` and `allfaces` according to
|
||||||
|
@ -1574,7 +1596,8 @@ Look for examples in `games/devtest` or `games/minetest_game`.
|
||||||
Node boxes
|
Node boxes
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Node selection boxes are defined using "node boxes".
|
Node selection boxes and collision boxes, and the appearance of the `nodebox`
|
||||||
|
drawtype, are defined using "node boxes".
|
||||||
|
|
||||||
A nodebox is defined as any of:
|
A nodebox is defined as any of:
|
||||||
|
|
||||||
|
@ -1659,7 +1682,9 @@ roughly 1x1x1 meters in size.
|
||||||
|
|
||||||
A 'mapblock' (often abbreviated to 'block') is 16x16x16 nodes and is the
|
A 'mapblock' (often abbreviated to 'block') is 16x16x16 nodes and is the
|
||||||
fundamental region of a world that is stored in the world database, sent to
|
fundamental region of a world that is stored in the world database, sent to
|
||||||
clients and handled by many parts of the engine.
|
clients and handled by many parts of the engine. This size is available as the
|
||||||
|
constant `core.MAP_BLOCKSIZE` (=16).
|
||||||
|
|
||||||
'mapblock' is preferred terminology to 'block' to help avoid confusion with
|
'mapblock' is preferred terminology to 'block' to help avoid confusion with
|
||||||
'node', however 'block' often appears in the API.
|
'node', however 'block' often appears in the API.
|
||||||
|
|
||||||
|
@ -1668,6 +1693,38 @@ A 'mapchunk' (sometimes abbreviated to 'chunk') is usually 5x5x5 mapblocks
|
||||||
the map generator.
|
the map generator.
|
||||||
The size in mapblocks has been chosen to optimize map generation.
|
The size in mapblocks has been chosen to optimize map generation.
|
||||||
|
|
||||||
|
### Mapblock status
|
||||||
|
|
||||||
|
A mapblock being "loaded" means that is in memory. These are the mapblocks that
|
||||||
|
API functions like `core.get_node` or `core.set_node` can operate on. To reach
|
||||||
|
this state, the mapblock must first go through the process of being "emerged".
|
||||||
|
This means that it is loaded from disk, and/or, if it isn't yet generated,
|
||||||
|
generated by the map generator.
|
||||||
|
|
||||||
|
Mapblocks are loaded in a broad area around each player. They become "unloaded"
|
||||||
|
again if no player is close enough. The engine commonly represents the contents
|
||||||
|
of unloaded mapblocks as `"ignore"` nodes.
|
||||||
|
|
||||||
|
A mapblock being "active" means that it is not only in memory, but also affected
|
||||||
|
by world simulation:
|
||||||
|
|
||||||
|
* Entities are active
|
||||||
|
* They are in memory as `ServerActiveObject`, exposed to Lua as `ObjectRef`
|
||||||
|
* They exist in Lua as luaentity tables
|
||||||
|
* ABMs are executed
|
||||||
|
* Node timers are executed
|
||||||
|
|
||||||
|
Also, when a mapblock is "activated", LBMs are executed. Mapblocks are active
|
||||||
|
in a smaller area around each player, and are "deactivated" again if no player
|
||||||
|
is close enough.
|
||||||
|
|
||||||
|
Related API functions:
|
||||||
|
|
||||||
|
* `core.compare_block_status`
|
||||||
|
* `core.forceload_block`
|
||||||
|
* `core.load_area`
|
||||||
|
* `core.emerge_area`
|
||||||
|
|
||||||
Coordinates
|
Coordinates
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -1691,7 +1748,7 @@ node position (0,0,0) to node position (15,15,15).
|
||||||
To calculate the blockpos of the mapblock that contains the node at 'nodepos',
|
To calculate the blockpos of the mapblock that contains the node at 'nodepos',
|
||||||
for each axis:
|
for each axis:
|
||||||
|
|
||||||
* blockpos = math.floor(nodepos / 16)
|
* blockpos = math.floor(nodepos / core.MAP_BLOCKSIZE)
|
||||||
|
|
||||||
#### Converting blockpos to min/max node positions
|
#### Converting blockpos to min/max node positions
|
||||||
|
|
||||||
|
@ -1699,9 +1756,9 @@ To calculate the min/max node positions contained in the mapblock at 'blockpos',
|
||||||
for each axis:
|
for each axis:
|
||||||
|
|
||||||
* Minimum:
|
* Minimum:
|
||||||
nodepos = blockpos * 16
|
nodepos = blockpos * core.MAP_BLOCKSIZE
|
||||||
* Maximum:
|
* Maximum:
|
||||||
nodepos = blockpos * 16 + 15
|
nodepos = (blockpos + 1) * core.MAP_BLOCKSIZE - 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2002,6 +2059,21 @@ that acts as tool in a gameplay sense as a craftitem, and vice-versa.
|
||||||
Craftitems can be used for items that neither need to be a node
|
Craftitems can be used for items that neither need to be a node
|
||||||
nor a tool.
|
nor a tool.
|
||||||
|
|
||||||
|
Special Items
|
||||||
|
-------------
|
||||||
|
The following items are predefined and have special properties.
|
||||||
|
|
||||||
|
* `"unknown"`: An item that represents every item which has not been registered
|
||||||
|
* `"air"`: The node which appears everywhere where no other node is
|
||||||
|
* `"ignore"`: Mapblocks that are not loaded are represented using this node.
|
||||||
|
* Also used for nodes that have not yet been set by the map generator.
|
||||||
|
* This is also what appears outside of the map boundary.
|
||||||
|
* `""`: The player's hand, which is in use whenever the player wields no item.
|
||||||
|
* Its range and tool capabilities are also used as a fallback for the wielded item.
|
||||||
|
* It can be overridden to change those properties:
|
||||||
|
* globally using `core.override_item`
|
||||||
|
* per-player using the special `"hand"` inventory list
|
||||||
|
|
||||||
Amount and wear
|
Amount and wear
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -3744,7 +3816,8 @@ Player Inventory lists
|
||||||
* `craftresult`: list containing the crafted output
|
* `craftresult`: list containing the crafted output
|
||||||
* `hand`: list containing an override for the empty hand
|
* `hand`: list containing an override for the empty hand
|
||||||
* Is not created automatically, use `InvRef:set_size`
|
* Is not created automatically, use `InvRef:set_size`
|
||||||
* Is only used to enhance the empty hand's tool capabilities
|
* Players use the first item in this list as their hand
|
||||||
|
* It behaves as if the default hand `""` has been overridden for this specific player
|
||||||
|
|
||||||
Custom lists can be added and deleted with `InvRef:set_size(name, size)` like
|
Custom lists can be added and deleted with `InvRef:set_size(name, size)` like
|
||||||
any other inventory.
|
any other inventory.
|
||||||
|
@ -4120,6 +4193,11 @@ Helper functions
|
||||||
* returns time with microsecond precision. May not return wall time.
|
* returns time with microsecond precision. May not return wall time.
|
||||||
* `table.copy(table)`: returns a table
|
* `table.copy(table)`: returns a table
|
||||||
* returns a deep copy of `table`
|
* returns a deep copy of `table`
|
||||||
|
* strips metatables, but this may change in the future
|
||||||
|
* `table.copy_with_metatables(table)`
|
||||||
|
* since 5.12
|
||||||
|
* `table` can also be non-table value, which will be returned as-is
|
||||||
|
* preserves metatables as they are
|
||||||
* `table.indexof(list, val)`: returns the smallest numerical index containing
|
* `table.indexof(list, val)`: returns the smallest numerical index containing
|
||||||
the value `val` in the table `list`. Non-numerical indices are ignored.
|
the value `val` in the table `list`. Non-numerical indices are ignored.
|
||||||
If `val` could not be found, `-1` is returned. `list` must not have
|
If `val` could not be found, `-1` is returned. `list` must not have
|
||||||
|
@ -4346,7 +4424,7 @@ Hello @1, how are you today?=Hallo @1, wie geht es dir heute?
|
||||||
```
|
```
|
||||||
|
|
||||||
For old translation files, consider using the script `mod_translation_updater.py`
|
For old translation files, consider using the script `mod_translation_updater.py`
|
||||||
in the Luanti [modtools](https://github.com/minetest/modtools) repository to
|
in the Luanti [modtools](https://github.com/luanti-org/modtools) repository to
|
||||||
generate and update translation files automatically from the Lua sources.
|
generate and update translation files automatically from the Lua sources.
|
||||||
|
|
||||||
Gettext translation file format
|
Gettext translation file format
|
||||||
|
@ -4442,22 +4520,25 @@ textdomain match the mod name, but this isn't required.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Perlin noise
|
Fractal value noise
|
||||||
============
|
===================
|
||||||
|
|
||||||
|
Value noise creates a continuously-varying value depending on the input values.
|
||||||
|
It is similar to Perlin noise, but may exhibit more geometric artifacts,
|
||||||
|
as it interpolates between values and not between gradients as in Perlin noise.
|
||||||
|
|
||||||
Perlin noise creates a continuously-varying value depending on the input values.
|
|
||||||
Usually in Luanti the input values are either 2D or 3D coordinates in nodes.
|
Usually in Luanti the input values are either 2D or 3D coordinates in nodes.
|
||||||
The result is used during map generation to create the terrain shape, vary heat
|
The result is used during map generation to create the terrain shape, vary heat
|
||||||
and humidity to distribute biomes, vary the density of decorations or vary the
|
and humidity to distribute biomes, vary the density of decorations or vary the
|
||||||
structure of ores.
|
structure of ores.
|
||||||
|
|
||||||
Structure of perlin noise
|
Structure of fractal value noise
|
||||||
-------------------------
|
--------------------------------
|
||||||
|
|
||||||
An 'octave' is a simple noise generator that outputs a value between -1 and 1.
|
An 'octave' is a simple noise generator that outputs a value between -1 and 1.
|
||||||
The smooth wavy noise it generates has a single characteristic scale, almost
|
The smooth wavy noise it generates has a single characteristic scale, almost
|
||||||
like a 'wavelength', so on its own does not create fine detail.
|
like a 'wavelength', so on its own does not create fine detail.
|
||||||
Due to this perlin noise combines several octaves to create variation on
|
Due to this fractal value noise combines several octaves to create variation on
|
||||||
multiple scales. Each additional octave has a smaller 'wavelength' than the
|
multiple scales. Each additional octave has a smaller 'wavelength' than the
|
||||||
previous.
|
previous.
|
||||||
|
|
||||||
|
@ -4465,7 +4546,7 @@ This combination results in noise varying very roughly between -2.0 and 2.0 and
|
||||||
with an average value of 0.0, so `scale` and `offset` are then used to multiply
|
with an average value of 0.0, so `scale` and `offset` are then used to multiply
|
||||||
and offset the noise variation.
|
and offset the noise variation.
|
||||||
|
|
||||||
The final perlin noise variation is created as follows:
|
The final fractal value noise variation is created as follows:
|
||||||
|
|
||||||
noise = offset + scale * (octave1 +
|
noise = offset + scale * (octave1 +
|
||||||
octave2 * persistence +
|
octave2 * persistence +
|
||||||
|
@ -4583,7 +4664,7 @@ with restraint.
|
||||||
#### `absvalue`
|
#### `absvalue`
|
||||||
|
|
||||||
The absolute value of each octave's noise variation is used when combining the
|
The absolute value of each octave's noise variation is used when combining the
|
||||||
octaves. The final perlin noise variation is created as follows:
|
octaves. The final value noise variation is created as follows:
|
||||||
|
|
||||||
noise = offset + scale * (abs(octave1) +
|
noise = offset + scale * (abs(octave1) +
|
||||||
abs(octave2) * persistence +
|
abs(octave2) * persistence +
|
||||||
|
@ -4593,7 +4674,7 @@ noise = offset + scale * (abs(octave1) +
|
||||||
|
|
||||||
### Format example
|
### Format example
|
||||||
|
|
||||||
For 2D or 3D perlin noise or perlin noise maps:
|
For 2D or 3D value noise or value noise maps:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
np_terrain = {
|
np_terrain = {
|
||||||
|
@ -4628,13 +4709,13 @@ All default ores are of the uniformly-distributed scatter type.
|
||||||
|
|
||||||
Randomly chooses a location and generates a cluster of ore.
|
Randomly chooses a location and generates a cluster of ore.
|
||||||
|
|
||||||
If `noise_params` is specified, the ore will be placed if the 3D perlin noise
|
If `noise_params` is specified, the ore will be placed if the 3D value noise
|
||||||
at that point is greater than the `noise_threshold`, giving the ability to
|
at that point is greater than the `noise_threshold`, giving the ability to
|
||||||
create a non-equal distribution of ore.
|
create a non-equal distribution of ore.
|
||||||
|
|
||||||
### `sheet`
|
### `sheet`
|
||||||
|
|
||||||
Creates a sheet of ore in a blob shape according to the 2D perlin noise
|
Creates a sheet of ore in a blob shape according to the 2D value noise
|
||||||
described by `noise_params` and `noise_threshold`. This is essentially an
|
described by `noise_params` and `noise_threshold`. This is essentially an
|
||||||
improved version of the so-called "stratus" ore seen in some unofficial mods.
|
improved version of the so-called "stratus" ore seen in some unofficial mods.
|
||||||
|
|
||||||
|
@ -4667,14 +4748,14 @@ noise parameters `np_puff_top` and `np_puff_bottom`, respectively.
|
||||||
|
|
||||||
### `blob`
|
### `blob`
|
||||||
|
|
||||||
Creates a deformed sphere of ore according to 3d perlin noise described by
|
Creates a deformed sphere of ore according to 3d value noise described by
|
||||||
`noise_params`. The maximum size of the blob is `clust_size`, and
|
`noise_params`. The maximum size of the blob is `clust_size`, and
|
||||||
`clust_scarcity` has the same meaning as with the `scatter` type.
|
`clust_scarcity` has the same meaning as with the `scatter` type.
|
||||||
|
|
||||||
### `vein`
|
### `vein`
|
||||||
|
|
||||||
Creates veins of ore varying in density by according to the intersection of two
|
Creates veins of ore varying in density by according to the intersection of two
|
||||||
instances of 3d perlin noise with different seeds, both described by
|
instances of 3d value noise with different seeds, both described by
|
||||||
`noise_params`.
|
`noise_params`.
|
||||||
|
|
||||||
`random_factor` varies the influence random chance has on placement of an ore
|
`random_factor` varies the influence random chance has on placement of an ore
|
||||||
|
@ -4709,8 +4790,8 @@ computationally expensive than any other ore.
|
||||||
Creates a single undulating ore stratum that is continuous across mapchunk
|
Creates a single undulating ore stratum that is continuous across mapchunk
|
||||||
borders and horizontally spans the world.
|
borders and horizontally spans the world.
|
||||||
|
|
||||||
The 2D perlin noise described by `noise_params` defines the Y coordinate of
|
The 2D value noise described by `noise_params` defines the Y coordinate of
|
||||||
the stratum midpoint. The 2D perlin noise described by `np_stratum_thickness`
|
the stratum midpoint. The 2D value noise described by `np_stratum_thickness`
|
||||||
defines the stratum's vertical thickness (in units of nodes). Due to being
|
defines the stratum's vertical thickness (in units of nodes). Due to being
|
||||||
continuous across mapchunk borders the stratum's vertical thickness is
|
continuous across mapchunk borders the stratum's vertical thickness is
|
||||||
unlimited.
|
unlimited.
|
||||||
|
@ -4958,7 +5039,7 @@ and the array index for a position p contained completely in p1..p2 is:
|
||||||
`(p.Z - p1.Z) * Ny * Nx + (p.Y - p1.Y) * Nx + (p.X - p1.X) + 1`
|
`(p.Z - p1.Z) * Ny * Nx + (p.Y - p1.Y) * Nx + (p.X - p1.X) + 1`
|
||||||
|
|
||||||
Note that this is the same "flat 3D array" format as
|
Note that this is the same "flat 3D array" format as
|
||||||
`PerlinNoiseMap:get3dMap_flat()`.
|
`ValueNoiseMap:get3dMap_flat()`.
|
||||||
VoxelArea objects (see section [`VoxelArea`]) can be used to simplify calculation
|
VoxelArea objects (see section [`VoxelArea`]) can be used to simplify calculation
|
||||||
of the index for a single point in a flat VoxelManip array.
|
of the index for a single point in a flat VoxelManip array.
|
||||||
|
|
||||||
|
@ -5149,7 +5230,7 @@ The coordinates are *inclusive*, like most other things in Luanti.
|
||||||
* The position (x, y, z) is not checked for being inside the area volume,
|
* The position (x, y, z) is not checked for being inside the area volume,
|
||||||
being outside can cause an incorrect index result.
|
being outside can cause an incorrect index result.
|
||||||
* Useful for things like `VoxelManip`, raw Schematic specifiers,
|
* Useful for things like `VoxelManip`, raw Schematic specifiers,
|
||||||
`PerlinNoiseMap:get2d`/`3dMap`, and so on.
|
`ValueNoiseMap:get2d`/`3dMap`, and so on.
|
||||||
* `indexp(p)`: same functionality as `index(x, y, z)` but takes a vector.
|
* `indexp(p)`: same functionality as `index(x, y, z)` but takes a vector.
|
||||||
* As with `index(x, y, z)`, the components of `p` must be integers, and `p`
|
* As with `index(x, y, z)`, the components of `p` must be integers, and `p`
|
||||||
is not checked for being inside the area volume.
|
is not checked for being inside the area volume.
|
||||||
|
@ -5556,7 +5637,7 @@ Utilities
|
||||||
* It's possible that multiple Luanti instances are running at the same
|
* It's possible that multiple Luanti instances are running at the same
|
||||||
time, which may lead to corruption if you are not careful.
|
time, which may lead to corruption if you are not careful.
|
||||||
* `core.is_singleplayer()`
|
* `core.is_singleplayer()`
|
||||||
* `core.features`: Table containing API feature flags
|
* `core.features`: Table containing *server-side* API feature flags
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
|
@ -5667,10 +5748,13 @@ Utilities
|
||||||
biome_weights = true,
|
biome_weights = true,
|
||||||
-- Particles can specify a "clip" blend mode (5.11.0)
|
-- Particles can specify a "clip" blend mode (5.11.0)
|
||||||
particle_blend_clip = true,
|
particle_blend_clip = true,
|
||||||
|
-- The `match_meta` optional parameter is available for `InvRef:remove_item()` (5.12.0)
|
||||||
|
remove_item_match_meta = true,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* `core.has_feature(arg)`: returns `boolean, missing_features`
|
* `core.has_feature(arg)`: returns `boolean, missing_features`
|
||||||
|
* checks for *server-side* feature availability
|
||||||
* `arg`: string or table in format `{foo=true, bar=true}`
|
* `arg`: string or table in format `{foo=true, bar=true}`
|
||||||
* `missing_features`: `{foo=true, bar=true}`
|
* `missing_features`: `{foo=true, bar=true}`
|
||||||
* `core.get_player_information(player_name)`: Table containing information
|
* `core.get_player_information(player_name)`: Table containing information
|
||||||
|
@ -5692,17 +5776,40 @@ Utilities
|
||||||
min_jitter = 0.01, -- minimum packet time jitter
|
min_jitter = 0.01, -- minimum packet time jitter
|
||||||
max_jitter = 0.5, -- maximum packet time jitter
|
max_jitter = 0.5, -- maximum packet time jitter
|
||||||
avg_jitter = 0.03, -- average packet time jitter
|
avg_jitter = 0.03, -- average packet time jitter
|
||||||
|
|
||||||
|
-- The version information is provided by the client and may be spoofed
|
||||||
|
-- or inconsistent in engine forks. You must not use this for checking
|
||||||
|
-- feature availability of clients. Instead, do use the fields
|
||||||
|
-- `protocol_version` and `formspec_version` where it matters.
|
||||||
|
-- Use `core.protocol_versions` to map Luanti versions to protocol versions.
|
||||||
|
-- This version string is only suitable for analysis purposes.
|
||||||
|
version_string = "0.4.9-git", -- full version string
|
||||||
|
|
||||||
-- the following information is available in a debug build only!!!
|
-- the following information is available in a debug build only!!!
|
||||||
-- DO NOT USE IN MODS
|
-- DO NOT USE IN MODS
|
||||||
--ser_vers = 26, -- serialization version used by client
|
--serialization_version = 26, -- serialization version used by client
|
||||||
--major = 0, -- major version number
|
--major = 0, -- major version number
|
||||||
--minor = 4, -- minor version number
|
--minor = 4, -- minor version number
|
||||||
--patch = 10, -- patch version number
|
--patch = 10, -- patch version number
|
||||||
--vers_string = "0.4.9-git", -- full version string
|
|
||||||
--state = "Active" -- current client state
|
--state = "Active" -- current client state
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* `core.protocol_versions`:
|
||||||
|
* Table mapping Luanti versions to corresponding protocol versions for modder convenience.
|
||||||
|
* For example, to check whether a client has at least the feature set
|
||||||
|
of Luanti 5.8.0 or newer, you could do:
|
||||||
|
`core.get_player_information(player_name).protocol_version >= core.protocol_versions["5.8.0"]`
|
||||||
|
* (available since 5.11)
|
||||||
|
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
[version string] = protocol version at time of release
|
||||||
|
-- every major and minor version has an entry
|
||||||
|
-- patch versions only for the first release whose protocol version is not already present in the table
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
* `core.get_player_window_information(player_name)`:
|
* `core.get_player_window_information(player_name)`:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
@ -5840,16 +5947,23 @@ Call these functions only at load time!
|
||||||
|
|
||||||
### Environment
|
### Environment
|
||||||
|
|
||||||
* `core.register_node(name, node definition)`
|
* `core.register_node(name, nodedef)`
|
||||||
* `core.register_craftitem(name, item definition)`
|
* register a node with its definition
|
||||||
* `core.register_tool(name, item definition)`
|
* Note: you must pass a clean table that hasn't already been used for
|
||||||
|
another registration to this function, as it will be modified.
|
||||||
|
* `core.register_craftitem(name, itemdef)`
|
||||||
|
* register an item with its definition
|
||||||
|
* Note: (as above)
|
||||||
|
* `core.register_tool(name, tooldef)`
|
||||||
|
* register a tool item with its definition
|
||||||
|
* Note: (as above)
|
||||||
* `core.override_item(name, redefinition, del_fields)`
|
* `core.override_item(name, redefinition, del_fields)`
|
||||||
* `redefinition` is a table of fields `[name] = new_value`,
|
* `redefinition` is a table of fields `[name] = new_value`,
|
||||||
overwriting fields of or adding fields to the existing definition.
|
overwriting fields of or adding fields to the existing definition.
|
||||||
* `del_fields` is a list of field names to be set
|
* `del_fields` is a list of field names to be set
|
||||||
to `nil` ("deleted from") the original definition.
|
to `nil` ("deleted from") the original definition.
|
||||||
* Overrides fields of an item registered with register_node/tool/craftitem.
|
* Overrides fields of an item registered with register_node/tool/craftitem.
|
||||||
* Note: Item must already be defined, (opt)depend on the mod defining it.
|
* Note: Item must already be defined.
|
||||||
* Example: `core.override_item("default:mese",
|
* Example: `core.override_item("default:mese",
|
||||||
{light_source=core.LIGHT_MAX}, {"sounds"})`:
|
{light_source=core.LIGHT_MAX}, {"sounds"})`:
|
||||||
Overwrites the `light_source` field,
|
Overwrites the `light_source` field,
|
||||||
|
@ -5857,7 +5971,7 @@ Call these functions only at load time!
|
||||||
* `core.unregister_item(name)`
|
* `core.unregister_item(name)`
|
||||||
* Unregisters the item from the engine, and deletes the entry with key
|
* Unregisters the item from the engine, and deletes the entry with key
|
||||||
`name` from `core.registered_items` and from the associated item table
|
`name` from `core.registered_items` and from the associated item table
|
||||||
according to its nature: `core.registered_nodes`, etc.
|
according to its nature (e.g. `core.registered_nodes`)
|
||||||
* `core.register_entity(name, entity definition)`
|
* `core.register_entity(name, entity definition)`
|
||||||
* `core.register_abm(abm definition)`
|
* `core.register_abm(abm definition)`
|
||||||
* `core.register_lbm(lbm definition)`
|
* `core.register_lbm(lbm definition)`
|
||||||
|
@ -6401,18 +6515,24 @@ Environment access
|
||||||
first value: Table with all node positions
|
first value: Table with all node positions
|
||||||
second value: Table with the count of each node with the node name
|
second value: Table with the count of each node with the node name
|
||||||
as index
|
as index
|
||||||
* Area volume is limited to 4,096,000 nodes
|
* Area volume is limited to 150,000,000 nodes
|
||||||
* `core.find_nodes_in_area_under_air(pos1, pos2, nodenames)`: returns a
|
* `core.find_nodes_in_area_under_air(pos1, pos2, nodenames)`: returns a
|
||||||
list of positions.
|
list of positions.
|
||||||
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
||||||
* Return value: Table with all node positions with a node air above
|
* Return value: Table with all node positions with a node air above
|
||||||
* Area volume is limited to 4,096,000 nodes
|
* Area volume is limited to 150,000,000 nodes
|
||||||
* `core.get_perlin(noiseparams)`
|
* `core.get_value_noise(noiseparams)`
|
||||||
* Return world-specific perlin noise.
|
* Return world-specific value noise.
|
||||||
* The actual seed used is the noiseparams seed plus the world seed.
|
* The actual seed used is the noiseparams seed plus the world seed.
|
||||||
|
* `core.get_value_noise(seeddiff, octaves, persistence, spread)`
|
||||||
|
* Deprecated: use `core.get_value_noise(noiseparams)` instead.
|
||||||
|
* Return world-specific value noise
|
||||||
|
* `core.get_perlin(noiseparams)`
|
||||||
|
* Deprecated: use `core.get_value_noise(noiseparams)` instead.
|
||||||
|
* Return world-specific value noise (was not Perlin noise)
|
||||||
* `core.get_perlin(seeddiff, octaves, persistence, spread)`
|
* `core.get_perlin(seeddiff, octaves, persistence, spread)`
|
||||||
* Deprecated: use `core.get_perlin(noiseparams)` instead.
|
* Deprecated: use `core.get_value_noise(noiseparams)` instead.
|
||||||
* Return world-specific perlin noise.
|
* Return world-specific value noise (was not Perlin noise)
|
||||||
* `core.get_voxel_manip([pos1, pos2])`
|
* `core.get_voxel_manip([pos1, pos2])`
|
||||||
* Return voxel manipulator object.
|
* Return voxel manipulator object.
|
||||||
* Loads the manipulator from the map if positions are passed.
|
* Loads the manipulator from the map if positions are passed.
|
||||||
|
@ -6889,8 +7009,13 @@ Defaults for the `on_place` and `on_drop` item definition functions
|
||||||
* Parameters are the same as in `on_pickup`.
|
* Parameters are the same as in `on_pickup`.
|
||||||
* Returns the leftover itemstack.
|
* Returns the leftover itemstack.
|
||||||
* `core.item_drop(itemstack, dropper, pos)`
|
* `core.item_drop(itemstack, dropper, pos)`
|
||||||
* Drop the item
|
* Converts `itemstack` to an in-world Lua entity.
|
||||||
* returns the leftover itemstack
|
* `itemstack` (`ItemStack`) is modified (cleared) on success.
|
||||||
|
* In versions < 5.12.0, `itemstack` was cleared in all cases.
|
||||||
|
* `dropper` (`ObjectRef`) is optional.
|
||||||
|
* Returned values on success:
|
||||||
|
1. leftover itemstack
|
||||||
|
2. `ObjectRef` of the spawned object (provided since 5.12.0)
|
||||||
* `core.item_eat(hp_change[, replace_with_item])`
|
* `core.item_eat(hp_change[, replace_with_item])`
|
||||||
* Returns `function(itemstack, user, pointed_thing)` as a
|
* Returns `function(itemstack, user, pointed_thing)` as a
|
||||||
function wrapper for `core.do_item_eat`.
|
function wrapper for `core.do_item_eat`.
|
||||||
|
@ -6982,8 +7107,8 @@ Classes:
|
||||||
|
|
||||||
* `AreaStore`
|
* `AreaStore`
|
||||||
* `ItemStack`
|
* `ItemStack`
|
||||||
* `PerlinNoise`
|
* `ValueNoise`
|
||||||
* `PerlinNoiseMap`
|
* `ValueNoiseMap`
|
||||||
* `PseudoRandom`
|
* `PseudoRandom`
|
||||||
* `PcgRandom`
|
* `PcgRandom`
|
||||||
* `SecureRandom`
|
* `SecureRandom`
|
||||||
|
@ -6995,8 +7120,8 @@ Classes:
|
||||||
Class instances that can be transferred between environments:
|
Class instances that can be transferred between environments:
|
||||||
|
|
||||||
* `ItemStack`
|
* `ItemStack`
|
||||||
* `PerlinNoise`
|
* `ValueNoise`
|
||||||
* `PerlinNoiseMap`
|
* `ValueNoiseMap`
|
||||||
* `VoxelManip`
|
* `VoxelManip`
|
||||||
|
|
||||||
Functions:
|
Functions:
|
||||||
|
@ -7062,8 +7187,8 @@ Classes:
|
||||||
|
|
||||||
* `AreaStore`
|
* `AreaStore`
|
||||||
* `ItemStack`
|
* `ItemStack`
|
||||||
* `PerlinNoise`
|
* `ValueNoise`
|
||||||
* `PerlinNoiseMap`
|
* `ValueNoiseMap`
|
||||||
* `PseudoRandom`
|
* `PseudoRandom`
|
||||||
* `PcgRandom`
|
* `PcgRandom`
|
||||||
* `SecureRandom`
|
* `SecureRandom`
|
||||||
|
@ -7408,7 +7533,8 @@ Misc.
|
||||||
* This function can be overridden by mods to change the leave message.
|
* This function can be overridden by mods to change the leave message.
|
||||||
* `core.hash_node_position(pos)`: returns a 48-bit integer
|
* `core.hash_node_position(pos)`: returns a 48-bit integer
|
||||||
* `pos`: table {x=number, y=number, z=number},
|
* `pos`: table {x=number, y=number, z=number},
|
||||||
* Gives a unique hash number for a node position (16+16+16=48bit)
|
* Gives a unique numeric encoding for a node position (16+16+16=48bit)
|
||||||
|
* Despite the name, this is not a hash function (so it doesn't mix or produce collisions).
|
||||||
* `core.get_position_from_hash(hash)`: returns a position
|
* `core.get_position_from_hash(hash)`: returns a position
|
||||||
* Inverse transform of `core.hash_node_position`
|
* Inverse transform of `core.hash_node_position`
|
||||||
* `core.get_item_group(name, group)`: returns a rating
|
* `core.get_item_group(name, group)`: returns a rating
|
||||||
|
@ -7568,6 +7694,8 @@ Misc.
|
||||||
|
|
||||||
* `core.forceload_block(pos[, transient[, limit]])`
|
* `core.forceload_block(pos[, transient[, limit]])`
|
||||||
* forceloads the position `pos`.
|
* forceloads the position `pos`.
|
||||||
|
* this means that the mapblock containing `pos` will always be kept in the
|
||||||
|
`"active"` state, regardless of nearby players or server settings.
|
||||||
* returns `true` if area could be forceloaded
|
* returns `true` if area could be forceloaded
|
||||||
* If `transient` is `false` or absent, the forceload will be persistent
|
* If `transient` is `false` or absent, the forceload will be persistent
|
||||||
(saved between server runs). If `true`, the forceload will be transient
|
(saved between server runs). If `true`, the forceload will be transient
|
||||||
|
@ -7826,13 +7954,15 @@ An `InvRef` is a reference to an inventory.
|
||||||
can be fully added to the list
|
can be fully added to the list
|
||||||
* `contains_item(listname, stack, [match_meta])`: returns `true` if
|
* `contains_item(listname, stack, [match_meta])`: returns `true` if
|
||||||
the stack of items can be fully taken from the list.
|
the stack of items can be fully taken from the list.
|
||||||
If `match_meta` is false, only the items' names are compared
|
* If `match_meta` is `true`, item metadata is also considered when comparing
|
||||||
(default: `false`).
|
items. Otherwise, only the items names are compared. Default: `false`
|
||||||
* `remove_item(listname, stack)`: take as many items as specified from the
|
* The method ignores wear.
|
||||||
list, returns the items that were actually removed (as an `ItemStack`)
|
* `remove_item(listname, stack, [match_meta])`: take as many items as specified from the
|
||||||
-- note that any item metadata is ignored, so attempting to remove a specific
|
list, returns the items that were actually removed (as an `ItemStack`).
|
||||||
unique item this way will likely remove the wrong one -- to do that use
|
* If `match_meta` is `true` (available since feature `remove_item_match_meta`),
|
||||||
`set_stack` with an empty `ItemStack`.
|
item metadata is also considered when comparing items. Otherwise, only the
|
||||||
|
items names are compared. Default: `false`
|
||||||
|
* The method ignores wear.
|
||||||
* `get_location()`: returns a location compatible to
|
* `get_location()`: returns a location compatible to
|
||||||
`core.get_inventory(location)`.
|
`core.get_inventory(location)`.
|
||||||
* returns `{type="undefined"}` in case location is not known
|
* returns `{type="undefined"}` in case location is not known
|
||||||
|
@ -8781,6 +8911,14 @@ child will follow movement and rotation of that bone.
|
||||||
Same limits as for `thirdperson_back` apply.
|
Same limits as for `thirdperson_back` apply.
|
||||||
Defaults to `thirdperson_back` if unspecified.
|
Defaults to `thirdperson_back` if unspecified.
|
||||||
* `get_eye_offset()`: Returns camera offset vectors as set via `set_eye_offset`.
|
* `get_eye_offset()`: Returns camera offset vectors as set via `set_eye_offset`.
|
||||||
|
* `set_camera(params)`: Sets camera parameters.
|
||||||
|
* `mode`: Defines the camera mode used
|
||||||
|
- `any`: free choice between all modes (default)
|
||||||
|
- `first`: first-person camera
|
||||||
|
- `third`: third-person camera
|
||||||
|
- `third_front`: third-person camera, looking opposite of movement direction
|
||||||
|
* Supported by client since 5.12.0.
|
||||||
|
* `get_camera()`: Returns the camera parameters as a table as above.
|
||||||
* `send_mapblock(blockpos)`:
|
* `send_mapblock(blockpos)`:
|
||||||
* Sends an already loaded mapblock to the player.
|
* Sends an already loaded mapblock to the player.
|
||||||
* Returns `false` if nothing was sent (note that this can also mean that
|
* Returns `false` if nothing was sent (note that this can also mean that
|
||||||
|
@ -8895,33 +9033,41 @@ offering very strong randomness.
|
||||||
* `get_state()`: return generator state encoded in string
|
* `get_state()`: return generator state encoded in string
|
||||||
* `set_state(state_string)`: restore generator state from encoded string
|
* `set_state(state_string)`: restore generator state from encoded string
|
||||||
|
|
||||||
`PerlinNoise`
|
`ValueNoise`
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
A perlin noise generator.
|
A value noise generator.
|
||||||
It can be created via `PerlinNoise()` or `core.get_perlin()`.
|
It can be created via `ValueNoise()` or `core.get_value_noise()`.
|
||||||
For `core.get_perlin()`, the actual seed used is the noiseparams seed
|
For legacy reasons, it can also be created via `PerlinNoise()` or `core.get_perlin()`,
|
||||||
|
but the implemented noise is not Perlin noise.
|
||||||
|
For `core.get_value_noise()`, the actual seed used is the noiseparams seed
|
||||||
plus the world seed, to create world-specific noise.
|
plus the world seed, to create world-specific noise.
|
||||||
|
|
||||||
`PerlinNoise(noiseparams)`
|
* `ValueNoise(noiseparams)
|
||||||
`PerlinNoise(seed, octaves, persistence, spread)` (Deprecated).
|
* `ValueNoise(seed, octaves, persistence, spread)` (Deprecated)
|
||||||
|
* `PerlinNoise(noiseparams)` (Deprecated)
|
||||||
|
* `PerlinNoise(seed, octaves, persistence, spread)` (Deprecated)
|
||||||
|
|
||||||
`core.get_perlin(noiseparams)`
|
* `core.get_value_noise(noiseparams)`
|
||||||
`core.get_perlin(seeddiff, octaves, persistence, spread)` (Deprecated).
|
* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (Deprecated)
|
||||||
|
* `core.get_perlin(noiseparams)` (Deprecated)
|
||||||
|
* `core.get_perlin(seeddiff, octaves, persistence, spread)` (Deprecated)
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
* `get_2d(pos)`: returns 2D noise value at `pos={x=,y=}`
|
* `get_2d(pos)`: returns 2D noise value at `pos={x=,y=}`
|
||||||
* `get_3d(pos)`: returns 3D noise value at `pos={x=,y=,z=}`
|
* `get_3d(pos)`: returns 3D noise value at `pos={x=,y=,z=}`
|
||||||
|
|
||||||
`PerlinNoiseMap`
|
`ValueNoiseMap`
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
A fast, bulk perlin noise generator.
|
A fast, bulk noise generator.
|
||||||
|
|
||||||
It can be created via `PerlinNoiseMap(noiseparams, size)` or
|
It can be created via `ValueNoiseMap(noiseparams, size)` or
|
||||||
`core.get_perlin_map(noiseparams, size)`.
|
`core.get_value_noise_map(noiseparams, size)`.
|
||||||
For `core.get_perlin_map()`, the actual seed used is the noiseparams seed
|
For legacy reasons, it can also be created via `PerlinNoiseMap(noiseparams, size)`
|
||||||
|
or `core.get_perlin_map(noiseparams, size)`, but it is not Perlin noise.
|
||||||
|
For `core.get_value_noise_map()`, the actual seed used is the noiseparams seed
|
||||||
plus the world seed, to create world-specific noise.
|
plus the world seed, to create world-specific noise.
|
||||||
|
|
||||||
Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` component is omitted
|
Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` component is omitted
|
||||||
|
@ -8948,7 +9094,7 @@ table.
|
||||||
* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array,
|
* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array,
|
||||||
returns a slice of the most recently computed noise results. The result slice
|
returns a slice of the most recently computed noise results. The result slice
|
||||||
begins at coordinates `slice_offset` and takes a chunk of `slice_size`.
|
begins at coordinates `slice_offset` and takes a chunk of `slice_size`.
|
||||||
E.g. to grab a 2-slice high horizontal 2d plane of noise starting at buffer
|
E.g., to grab a 2-slice high horizontal 2d plane of noise starting at buffer
|
||||||
offset y = 20:
|
offset y = 20:
|
||||||
`noisevals = noise:get_map_slice({y=20}, {y=2})`
|
`noisevals = noise:get_map_slice({y=20}, {y=2})`
|
||||||
It is important to note that `slice_offset` offset coordinates begin at 1,
|
It is important to note that `slice_offset` offset coordinates begin at 1,
|
||||||
|
@ -9194,7 +9340,7 @@ Player properties need to be saved manually.
|
||||||
-- Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`.
|
-- Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`.
|
||||||
-- Can be overridden by the `pointabilities` of the held item.
|
-- Can be overridden by the `pointabilities` of the held item.
|
||||||
|
|
||||||
visual = "cube" / "sprite" / "upright_sprite" / "mesh" / "wielditem" / "item",
|
visual = "",
|
||||||
-- "cube" is a node-sized cube.
|
-- "cube" is a node-sized cube.
|
||||||
-- "sprite" is a flat texture always facing the player.
|
-- "sprite" is a flat texture always facing the player.
|
||||||
-- "upright_sprite" is a vertical flat texture.
|
-- "upright_sprite" is a vertical flat texture.
|
||||||
|
@ -9216,6 +9362,8 @@ Player properties need to be saved manually.
|
||||||
-- Wielditems are scaled a bit. If you want a wielditem to appear
|
-- Wielditems are scaled a bit. If you want a wielditem to appear
|
||||||
-- to be as large as a node, use `0.667` in `visual_size`
|
-- to be as large as a node, use `0.667` in `visual_size`
|
||||||
-- "item" is similar to "wielditem" but ignores the 'wield_image' parameter.
|
-- "item" is similar to "wielditem" but ignores the 'wield_image' parameter.
|
||||||
|
-- "node" looks exactly like a node in-world (supported since 5.12.0)
|
||||||
|
-- Note that visual effects like waving or liquid reflections will not work.
|
||||||
|
|
||||||
visual_size = {x = 1, y = 1, z = 1},
|
visual_size = {x = 1, y = 1, z = 1},
|
||||||
-- Multipliers for the visual size. If `z` is not specified, `x` will be used
|
-- Multipliers for the visual size. If `z` is not specified, `x` will be used
|
||||||
|
@ -9225,7 +9373,7 @@ Player properties need to be saved manually.
|
||||||
-- File name of mesh when using "mesh" visual
|
-- File name of mesh when using "mesh" visual
|
||||||
|
|
||||||
textures = {},
|
textures = {},
|
||||||
-- Number of required textures depends on visual.
|
-- Number of required textures depends on visual:
|
||||||
-- "cube" uses 6 textures just like a node, but all 6 must be defined.
|
-- "cube" uses 6 textures just like a node, but all 6 must be defined.
|
||||||
-- "sprite" uses 1 texture.
|
-- "sprite" uses 1 texture.
|
||||||
-- "upright_sprite" uses 2 textures: {front, back}.
|
-- "upright_sprite" uses 2 textures: {front, back}.
|
||||||
|
@ -9233,13 +9381,16 @@ Player properties need to be saved manually.
|
||||||
-- Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above).
|
-- Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above).
|
||||||
|
|
||||||
colors = {},
|
colors = {},
|
||||||
-- Number of required colors depends on visual
|
-- Currently unused.
|
||||||
|
|
||||||
|
node = {name = "ignore", param1=0, param2=0},
|
||||||
|
-- Node to show when using the "node" visual
|
||||||
|
|
||||||
use_texture_alpha = false,
|
use_texture_alpha = false,
|
||||||
-- Use texture's alpha channel.
|
-- Use texture's alpha channel for transparency blending.
|
||||||
-- Excludes "upright_sprite" and "wielditem".
|
|
||||||
-- Note: currently causes visual issues when viewed through other
|
-- Note: currently causes visual issues when viewed through other
|
||||||
-- semi-transparent materials such as water.
|
-- semi-transparent materials such as water.
|
||||||
|
-- Note: ignored for "item", "wielditem" and "node" visual.
|
||||||
|
|
||||||
spritediv = {x = 1, y = 1},
|
spritediv = {x = 1, y = 1},
|
||||||
-- Used with spritesheet textures for animation and/or frame selection
|
-- Used with spritesheet textures for animation and/or frame selection
|
||||||
|
@ -9256,7 +9407,7 @@ Player properties need to be saved manually.
|
||||||
-- If false, object is invisible and can't be pointed.
|
-- If false, object is invisible and can't be pointed.
|
||||||
|
|
||||||
makes_footstep_sound = false,
|
makes_footstep_sound = false,
|
||||||
-- If true, is able to make footstep sounds of nodes
|
-- If true, object is able to make footstep sounds of nodes
|
||||||
-- (see node sound definition for details).
|
-- (see node sound definition for details).
|
||||||
|
|
||||||
automatic_rotate = 0,
|
automatic_rotate = 0,
|
||||||
|
@ -9279,6 +9430,7 @@ Player properties need to be saved manually.
|
||||||
|
|
||||||
backface_culling = true,
|
backface_culling = true,
|
||||||
-- Set to false to disable backface_culling for model
|
-- Set to false to disable backface_culling for model
|
||||||
|
-- Note: only used by "mesh" and "cube" visual
|
||||||
|
|
||||||
glow = 0,
|
glow = 0,
|
||||||
-- Add this much extra lighting when calculating texture color.
|
-- Add this much extra lighting when calculating texture color.
|
||||||
|
@ -9314,6 +9466,7 @@ Player properties need to be saved manually.
|
||||||
|
|
||||||
shaded = true,
|
shaded = true,
|
||||||
-- Setting this to 'false' disables diffuse lighting of entity
|
-- Setting this to 'false' disables diffuse lighting of entity
|
||||||
|
-- Note: ignored for "item", "wielditem" and "node" visual
|
||||||
|
|
||||||
show_on_minimap = false,
|
show_on_minimap = false,
|
||||||
-- Defaults to true for players, false for other entities.
|
-- Defaults to true for players, false for other entities.
|
||||||
|
@ -9364,6 +9517,10 @@ ABM (ActiveBlockModifier) definition
|
||||||
|
|
||||||
Used by `core.register_abm`.
|
Used by `core.register_abm`.
|
||||||
|
|
||||||
|
An active block modifier (ABM) is used to define a function that is continously
|
||||||
|
and randomly called for specific nodes (defined by `nodenames` and other conditions)
|
||||||
|
in active mapblocks.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
label = "Lava cooling",
|
label = "Lava cooling",
|
||||||
|
@ -9420,12 +9577,29 @@ Used by `core.register_lbm`.
|
||||||
|
|
||||||
A loading block modifier (LBM) is used to define a function that is called for
|
A loading block modifier (LBM) is used to define a function that is called for
|
||||||
specific nodes (defined by `nodenames`) when a mapblock which contains such nodes
|
specific nodes (defined by `nodenames`) when a mapblock which contains such nodes
|
||||||
gets activated (not loaded!).
|
gets **activated** (**not loaded!**).
|
||||||
|
|
||||||
Note: LBMs operate on a "snapshot" of node positions taken once before they are triggered.
|
*Note*: LBMs operate on a "snapshot" of node positions taken once before they are triggered.
|
||||||
That means if an LBM callback adds a node, it won't be taken into account.
|
That means if an LBM callback adds a node, it won't be taken into account.
|
||||||
However the engine guarantees that when the callback is called that all given position(s)
|
However the engine guarantees that at the point in time when the callback is called
|
||||||
contain a matching node.
|
that all given positions contain a matching node.
|
||||||
|
|
||||||
|
For `run_at_every_load = false` to work, both mapblocks and LBMs have timestamps
|
||||||
|
associated with them:
|
||||||
|
|
||||||
|
* Each mapblock has a "last active" timestamp. It is also updated when the
|
||||||
|
mapblock is generated.
|
||||||
|
* For each LBM, an introduction timestamp is stored in the world data, identified
|
||||||
|
by the LBM's `name` field. If an LBM disappears, the corresponding timestamp
|
||||||
|
is cleared.
|
||||||
|
|
||||||
|
When a mapblock is activated, only LBMs whose introduction timestamp is newer
|
||||||
|
than the mapblock's timestamp are run.
|
||||||
|
|
||||||
|
*Note*: For maps generated in 5.11.0 or older, many newly generated mapblocks
|
||||||
|
did not get a timestamp set. This means LBMs introduced between generation time
|
||||||
|
and time of first activation will never run.
|
||||||
|
Currently the only workaround is to use `run_at_every_load = true`.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
|
@ -9442,14 +9616,17 @@ contain a matching node.
|
||||||
-- will work as well.
|
-- will work as well.
|
||||||
|
|
||||||
run_at_every_load = false,
|
run_at_every_load = false,
|
||||||
-- Whether to run the LBM's action every time a block gets activated,
|
-- If `false`: The LBM only runs on mapblocks the first time they are
|
||||||
-- and not only the first time the block gets activated after the LBM
|
-- activated after the LBM was introduced.
|
||||||
-- was introduced.
|
-- It never runs on mapblocks generated after the LBM's introduction.
|
||||||
|
-- See above for details.
|
||||||
|
--
|
||||||
|
-- If `true`: The LBM runs every time a mapblock is activated.
|
||||||
|
|
||||||
action = function(pos, node, dtime_s) end,
|
action = function(pos, node, dtime_s) end,
|
||||||
-- Function triggered for each qualifying node.
|
-- Function triggered for each qualifying node.
|
||||||
-- `dtime_s` is the in-game time (in seconds) elapsed since the block
|
-- `dtime_s` is the in-game time (in seconds) elapsed since the mapblock
|
||||||
-- was last active.
|
-- was last active (available since 5.7.0).
|
||||||
|
|
||||||
bulk_action = function(pos_list, dtime_s) end,
|
bulk_action = function(pos_list, dtime_s) end,
|
||||||
-- Function triggered with a list of all applicable node positions at once.
|
-- Function triggered with a list of all applicable node positions at once.
|
||||||
|
@ -10605,7 +10782,7 @@ See [Ores] section above for essential information.
|
||||||
octaves = 3,
|
octaves = 3,
|
||||||
persistence = 0.7
|
persistence = 0.7
|
||||||
},
|
},
|
||||||
-- NoiseParams structure describing one of the perlin noises used for
|
-- NoiseParams structure describing one of the noises used for
|
||||||
-- ore distribution.
|
-- ore distribution.
|
||||||
-- Needed by "sheet", "puff", "blob" and "vein" ores.
|
-- Needed by "sheet", "puff", "blob" and "vein" ores.
|
||||||
-- Omit from "scatter" ore for a uniform ore distribution.
|
-- Omit from "scatter" ore for a uniform ore distribution.
|
||||||
|
@ -10792,7 +10969,7 @@ See [Decoration types]. Used by `core.register_decoration`.
|
||||||
lacunarity = 2.0,
|
lacunarity = 2.0,
|
||||||
flags = "absvalue"
|
flags = "absvalue"
|
||||||
},
|
},
|
||||||
-- NoiseParams structure describing the perlin noise used for decoration
|
-- NoiseParams structure describing the noise used for decoration
|
||||||
-- distribution.
|
-- distribution.
|
||||||
-- A noise value is calculated for each square division and determines
|
-- A noise value is calculated for each square division and determines
|
||||||
-- 'decorations per surface node' within each division.
|
-- 'decorations per surface node' within each division.
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Moved to lua_api.md
|
Moved to lua_api.md
|
||||||
|
|
||||||
URL: https://github.com/minetest/minetest/blob/master/doc/lua_api.md
|
URL: https://github.com/luanti-org/luanti/blob/master/doc/lua_api.md
|
||||||
|
|
|
@ -124,7 +124,7 @@ Colon delimited list of directories to search for mods.
|
||||||
Path to Luanti user data directory.
|
Path to Luanti user data directory.
|
||||||
|
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
Please report all bugs at https://github.com/minetest/minetest/issues.
|
Please report all bugs at https://github.com/luanti-org/luanti/issues.
|
||||||
|
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.PP
|
.PP
|
||||||
|
@ -134,4 +134,4 @@ This man page was originally written by
|
||||||
Juhani Numminen <juhaninumminen0@gmail.com>.
|
Juhani Numminen <juhaninumminen0@gmail.com>.
|
||||||
|
|
||||||
.SH WWW
|
.SH WWW
|
||||||
http://www.minetest.net/
|
http://www.luanti.org/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/** @mainpage The Minetest engine internal documentation
|
/** @mainpage The Luanti engine internal documentation
|
||||||
|
|
||||||
Welcome to the Minetest engine Doxygen documentation site!\n
|
Welcome to the Luanti engine Doxygen documentation site!\n
|
||||||
This page documents the internal structure of the Minetest engine's C++ code.\n
|
This page documents the internal structure of the Luanti engine's C++ code.\n
|
||||||
Use the tree view at the left to navigate.
|
Use the tree view at the left to navigate.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Luanti Lua Mainmenu API Reference 5.11.0
|
Luanti Lua Mainmenu API Reference 5.12.0
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
|
@ -105,11 +105,6 @@ of manually putting one, as different OSs use different delimiters. E.g.
|
||||||
* `spec` = `SimpleSoundSpec` (see `lua_api.md`)
|
* `spec` = `SimpleSoundSpec` (see `lua_api.md`)
|
||||||
* `looped` = bool
|
* `looped` = bool
|
||||||
* `handle:stop()` or `core.sound_stop(handle)`
|
* `handle:stop()` or `core.sound_stop(handle)`
|
||||||
* `core.get_video_drivers()`
|
|
||||||
* get list of video drivers supported by engine (not all modes are guaranteed to work)
|
|
||||||
* returns list of available video drivers' settings name and 'friendly' display name
|
|
||||||
e.g. `{ {name="opengl", friendly_name="OpenGL"}, {name="software", friendly_name="Software Renderer"} }`
|
|
||||||
* first element of returned list is guaranteed to be the NULL driver
|
|
||||||
* `core.get_mapgen_names([include_hidden=false])` -> table of map generator algorithms
|
* `core.get_mapgen_names([include_hidden=false])` -> table of map generator algorithms
|
||||||
registered in the core (possible in async calls)
|
registered in the core (possible in async calls)
|
||||||
* `core.get_cache_path()` -> path of cache
|
* `core.get_cache_path()` -> path of cache
|
||||||
|
@ -336,7 +331,7 @@ Package - content which is downloadable from the content db, may or may not be i
|
||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
name = "technical_id",
|
name = "technical_id",
|
||||||
type = "mod" or "modpack" or "game" or "txp",
|
type = "mod" or "modpack" or "game" or "txp" or "unknown",
|
||||||
title = "Human readable title",
|
title = "Human readable title",
|
||||||
description = "description",
|
description = "description",
|
||||||
author = "author",
|
author = "author",
|
||||||
|
@ -387,7 +382,7 @@ Settings
|
||||||
* `core.settings:save()` -> nil, save all settings to config file
|
* `core.settings:save()` -> nil, save all settings to config file
|
||||||
|
|
||||||
For a complete list of methods of the `Settings` object see
|
For a complete list of methods of the `Settings` object see
|
||||||
[lua_api.md](https://github.com/minetest/minetest/blob/master/doc/lua_api.md)
|
[lua_api.md](./lua_api.md)
|
||||||
|
|
||||||
|
|
||||||
Worlds
|
Worlds
|
||||||
|
|
|
@ -22,6 +22,11 @@ This is a directory containing the entire contents of a single texture pack.
|
||||||
It can be chosen more or less freely and will also become the name of the
|
It can be chosen more or less freely and will also become the name of the
|
||||||
texture pack. The name must not be “base”.
|
texture pack. The name must not be “base”.
|
||||||
|
|
||||||
|
### The "server" texture pack
|
||||||
|
If a texture pack named `server` exists, the textures in it will replace textures
|
||||||
|
sent to clients.
|
||||||
|
It's independent of the client's texture pack, which will take precedence as usual.
|
||||||
|
|
||||||
### `texture_pack.conf`
|
### `texture_pack.conf`
|
||||||
A key-value config file with the following keys:
|
A key-value config file with the following keys:
|
||||||
|
|
||||||
|
@ -139,21 +144,34 @@ are placeholders intended to be overwritten by the game.
|
||||||
|
|
||||||
### Android textures
|
### Android textures
|
||||||
|
|
||||||
* `drop_btn.png`
|
* `dig_btn.png`
|
||||||
* `fast_btn.png`
|
* `place_btn.png`
|
||||||
* `fly_btn.png`
|
|
||||||
* `jump_btn.png`
|
* `jump_btn.png`
|
||||||
* `noclip_btn.png`
|
* `down.png`
|
||||||
|
* `zoom.png`
|
||||||
|
* `aux1_btn.png`
|
||||||
|
* `overflow_btn.png`
|
||||||
|
|
||||||
* `camera_btn.png`
|
|
||||||
* `chat_btn.png`
|
* `chat_btn.png`
|
||||||
* `inventory_btn.png`
|
* `inventory_btn.png`
|
||||||
* `rangeview_btn.png`
|
* `drop_btn.png`
|
||||||
|
|
||||||
* `debug_btn.png`
|
|
||||||
* `overflow_btn.png`
|
|
||||||
* `exit_btn.png`
|
* `exit_btn.png`
|
||||||
|
|
||||||
|
* `fly_btn.png`
|
||||||
|
* `fast_btn.png`
|
||||||
|
* `noclip_btn.png`
|
||||||
|
* `debug_btn.png`
|
||||||
|
* `camera_btn.png`
|
||||||
|
* `rangeview_btn.png`
|
||||||
|
* `minimap_btn.png`
|
||||||
|
* `chat_hide_btn.png`
|
||||||
|
* `chat_show_btn.png`
|
||||||
|
|
||||||
|
* `joystick_off.png`
|
||||||
|
* `joystick_bg.png`
|
||||||
|
* `joystick_center.png`
|
||||||
|
|
||||||
Texture Overrides
|
Texture Overrides
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
@ -281,46 +281,61 @@ storing coordinates separately), but the format has been kept unchanged for
|
||||||
that part.
|
that part.
|
||||||
|
|
||||||
## `map.sqlite`
|
## `map.sqlite`
|
||||||
`map.sqlite` is a `SQLite3` database, containing a single table, called
|
`map.sqlite` is an `SQLite3` database, containing a single table, called
|
||||||
`blocks`. It looks like this:
|
`blocks`. It looks like this:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE `blocks` (
|
||||||
|
`x` INTEGER, `y` INTEGER, `z` INTEGER,
|
||||||
|
`data` BLOB NOT NULL,
|
||||||
|
PRIMARY KEY (`x`, `z`, `y`)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Before 5.12.0 it looked like this:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY, `data` BLOB);
|
CREATE TABLE `blocks` (`pos` INT NOT NULL PRIMARY KEY, `data` BLOB);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Position Hashing
|
## Position Encoding
|
||||||
|
|
||||||
`pos` (a node position hash) is created from the three coordinates of a
|
Applies to the pre-5.12.0 schema:
|
||||||
`MapBlock` using this algorithm, defined here in Python:
|
|
||||||
|
|
||||||
```python
|
`pos` (a node position encoding) is created from the three coordinates of a
|
||||||
def getBlockAsInteger(p):
|
`MapBlock` using the following simple equation:
|
||||||
return int64(p[2]*16777216 + p[1]*4096 + p[0])
|
|
||||||
|
|
||||||
def int64(u):
|
```C
|
||||||
while u >= 2**63:
|
pos = (z << 24) + (y << 12) + x;
|
||||||
u -= 2**64
|
```
|
||||||
while u <= -2**63:
|
or, equivalently, `pos = (z * 0x1000000) + (y * 0x1000) + x`.
|
||||||
u += 2**64
|
|
||||||
return u
|
A position can be decoded using:
|
||||||
|
|
||||||
|
```C
|
||||||
|
pos = pos + 0x800800800;
|
||||||
|
x = (pos & 0xFFF) - 0x800;
|
||||||
|
y = ((pos >> 12) & 0xFFF) - 0x800;
|
||||||
|
z = ((pos >> 24) & 0xFFF) - 0x800;
|
||||||
```
|
```
|
||||||
|
|
||||||
It can be converted the other way by using this code:
|
Positions are sequential along the x axis (as easily seen from the position equation above).
|
||||||
|
It is possible to retrieve all blocks from an interval using the following SQL statement:
|
||||||
|
|
||||||
```python
|
```sql
|
||||||
def getIntegerAsBlock(i):
|
SELECT
|
||||||
x = unsignedToSigned(i % 4096, 2048)
|
`pos`,
|
||||||
i = int((i - x) / 4096)
|
`data`,
|
||||||
y = unsignedToSigned(i % 4096, 2048)
|
( (`pos` + 0x800800800) & 0xFFF) - 0x800 as x,
|
||||||
i = int((i - y) / 4096)
|
(((`pos` + 0x800800800) >> 12) & 0xFFF) - 0x800 as y,
|
||||||
z = unsignedToSigned(i % 4096, 2048)
|
(((`pos` + 0x800800800) >> 24) & 0xFFF) - 0x800 as z
|
||||||
return x,y,z
|
FROM `blocks` WHERE
|
||||||
|
( (`pos` + 0x800800800) & 0xFFF) - 0x800 >= ? AND -- minx
|
||||||
def unsignedToSigned(i, max_positive):
|
( (`pos` + 0x800800800) & 0xFFF) - 0x800 <= ? AND -- maxx
|
||||||
if i < max_positive:
|
(((`pos` + 0x800800800) >> 12) & 0xFFF) - 0x800 >= ? AND -- miny
|
||||||
return i
|
(((`pos` + 0x800800800) >> 12) & 0xFFF) - 0x800 <= ? AND -- maxy
|
||||||
else:
|
`pos` >= (? << 24) - 0x800800 AND -- minz
|
||||||
return i - 2*max_positive
|
`pos` <= (? << 24) + 0x7FF7FF; -- maxz
|
||||||
```
|
```
|
||||||
|
|
||||||
## Blob
|
## Blob
|
||||||
|
@ -335,8 +350,8 @@ See below for description.
|
||||||
> * NOTE: Byte order is MSB first (big-endian).
|
> * NOTE: Byte order is MSB first (big-endian).
|
||||||
> * NOTE: Zlib data is in such a format that Python's `zlib` at least can
|
> * NOTE: Zlib data is in such a format that Python's `zlib` at least can
|
||||||
> directly decompress.
|
> directly decompress.
|
||||||
> * NOTE: Since version 29 zstd is used instead of zlib. In addition, the entire
|
> * NOTE: Since version 29 zstd is used instead of zlib. In addition, the
|
||||||
> block is first serialized and then compressed (except the version byte).
|
> **entire block** is first serialized and then compressed (except version byte).
|
||||||
|
|
||||||
`u8` version
|
`u8` version
|
||||||
* map format version number, see serialization.h for the latest number
|
* map format version number, see serialization.h for the latest number
|
||||||
|
|
|
@ -31,7 +31,7 @@ read_globals = {
|
||||||
"PcgRandom",
|
"PcgRandom",
|
||||||
|
|
||||||
string = {fields = {"split", "trim"}},
|
string = {fields = {"split", "trim"}},
|
||||||
table = {fields = {"copy", "getn", "indexof", "insert_all"}},
|
table = {fields = {"copy", "getn", "indexof", "insert_all", "key_value_swap"}},
|
||||||
math = {fields = {"hypot", "round"}},
|
math = {fields = {"hypot", "round"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,15 @@ core.register_node("basenodes:desert_stone", {
|
||||||
|
|
||||||
core.register_node("basenodes:dirt_with_grass", {
|
core.register_node("basenodes:dirt_with_grass", {
|
||||||
description = "Dirt with Grass",
|
description = "Dirt with Grass",
|
||||||
tiles ={"default_grass.png",
|
-- Using overlays here has no real merit here but we do it anyway so
|
||||||
|
-- overlay-related bugs become more apparent in devtest.
|
||||||
|
tiles = {"default_dirt.png"},
|
||||||
|
overlay_tiles = {
|
||||||
|
"default_grass.png",
|
||||||
-- a little dot on the bottom to distinguish it from dirt
|
-- a little dot on the bottom to distinguish it from dirt
|
||||||
"default_dirt.png^basenodes_dirt_with_grass_bottom.png",
|
"basenodes_dirt_with_grass_bottom.png",
|
||||||
{name = "default_dirt.png^default_grass_side.png",
|
{name = "default_grass_side.png", tileable_vertical = false},
|
||||||
tileable_vertical = false}},
|
},
|
||||||
groups = {crumbly=3, soil=1},
|
groups = {crumbly=3, soil=1},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,15 @@ core.register_entity("testentities:mesh_unshaded", {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
core.register_entity("testentities:node", {
|
||||||
|
initial_properties = {
|
||||||
|
visual = "node",
|
||||||
|
node = { name = "stairs:stair_stone" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
-- More complex meshes
|
||||||
|
|
||||||
core.register_entity("testentities:sam", {
|
core.register_entity("testentities:sam", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
visual = "mesh",
|
visual = "mesh",
|
||||||
|
|
|
@ -12,7 +12,8 @@ core.register_node("tiled:tiled", {
|
||||||
})
|
})
|
||||||
|
|
||||||
core.register_node("tiled:tiled_rooted", {
|
core.register_node("tiled:tiled_rooted", {
|
||||||
description = "Tiled 'plantlike_rooted' Node (world-aligned)".."\n"..
|
description =
|
||||||
|
"Tiled 'plantlike_rooted' Node (world-aligned)".."\n"..
|
||||||
"Base node texture spans over a space of 8×8 nodes".."\n"..
|
"Base node texture spans over a space of 8×8 nodes".."\n"..
|
||||||
"A plantlike thing grows on top",
|
"A plantlike thing grows on top",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
|
|
@ -234,3 +234,24 @@ local function test_get_bone_rot(_, pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
unittests.register("test_get_bone_rot", test_get_bone_rot, {map=true})
|
unittests.register("test_get_bone_rot", test_get_bone_rot, {map=true})
|
||||||
|
|
||||||
|
---------
|
||||||
|
|
||||||
|
-- Spawn an entity from an ItemStack
|
||||||
|
local function test_item_drop(_, pos)
|
||||||
|
local itemstack_src, itemstack_ret, obj
|
||||||
|
|
||||||
|
-- Try to place something that does not exist (placement fails)
|
||||||
|
itemstack_src = ItemStack("n_np_solution 1")
|
||||||
|
itemstack_ret, obj = core.item_drop(itemstack_src, nil, pos)
|
||||||
|
assert(obj == nil)
|
||||||
|
assert(itemstack_ret == nil)
|
||||||
|
|
||||||
|
-- Test known item (placement successful)
|
||||||
|
itemstack_src = ItemStack("testnodes:normal 69")
|
||||||
|
itemstack_ret, obj = core.item_drop(itemstack_src, nil, pos)
|
||||||
|
assert(obj:get_hp() ~= nil)
|
||||||
|
assert(itemstack_ret and itemstack_ret:is_empty())
|
||||||
|
assert(itemstack_ret:equals(itemstack_src))
|
||||||
|
end
|
||||||
|
unittests.register("test_item_drop", test_item_drop, {map=true})
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
|
|
||||||
unittests.register("test_get_version", function()
|
|
||||||
local version = core.get_version()
|
|
||||||
assert(type(version) == "table")
|
|
||||||
assert(type(version.project) == "string")
|
|
||||||
assert(type(version.string) == "string")
|
|
||||||
assert(type(version.proto_min) == "number")
|
|
||||||
assert(type(version.proto_max) == "number")
|
|
||||||
assert(version.proto_max >= version.proto_min)
|
|
||||||
assert(type(version.is_dev) == "boolean")
|
|
||||||
if version.is_dev then
|
|
||||||
assert(type(version.hash) == "string")
|
|
||||||
else
|
|
||||||
assert(version.hash == nil)
|
|
||||||
end
|
|
||||||
end)
|
|
|
@ -192,7 +192,7 @@ dofile(modpath .. "/crafting.lua")
|
||||||
dofile(modpath .. "/itemdescription.lua")
|
dofile(modpath .. "/itemdescription.lua")
|
||||||
dofile(modpath .. "/async_env.lua")
|
dofile(modpath .. "/async_env.lua")
|
||||||
dofile(modpath .. "/entity.lua")
|
dofile(modpath .. "/entity.lua")
|
||||||
dofile(modpath .. "/get_version.lua")
|
dofile(modpath .. "/version.lua")
|
||||||
dofile(modpath .. "/itemstack_equals.lua")
|
dofile(modpath .. "/itemstack_equals.lua")
|
||||||
dofile(modpath .. "/content_ids.lua")
|
dofile(modpath .. "/content_ids.lua")
|
||||||
dofile(modpath .. "/metadata.lua")
|
dofile(modpath .. "/metadata.lua")
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
local function get_stack_with_meta(count)
|
||||||
local item_with_meta = ItemStack({name = "air", meta = {test = "abc"}})
|
return ItemStack({name = "air", count = count, meta = {test = "abc"}})
|
||||||
|
end
|
||||||
|
|
||||||
local test_list = {
|
local test_list = {
|
||||||
ItemStack("air"),
|
ItemStack("air"),
|
||||||
ItemStack(""),
|
ItemStack(""),
|
||||||
ItemStack(item_with_meta),
|
ItemStack(get_stack_with_meta(1)),
|
||||||
}
|
}
|
||||||
|
|
||||||
local function compare_lists(a, b)
|
local function compare_lists(a, b)
|
||||||
|
@ -34,12 +35,12 @@ local function test_inventory()
|
||||||
assert(not inv:set_width("test", -1))
|
assert(not inv:set_width("test", -1))
|
||||||
|
|
||||||
inv:set_stack("test", 1, "air")
|
inv:set_stack("test", 1, "air")
|
||||||
inv:set_stack("test", 3, item_with_meta)
|
inv:set_stack("test", 3, get_stack_with_meta(1))
|
||||||
assert(not inv:is_empty("test"))
|
assert(not inv:is_empty("test"))
|
||||||
assert(compare_lists(inv:get_list("test"), test_list))
|
assert(compare_lists(inv:get_list("test"), test_list))
|
||||||
|
|
||||||
assert(inv:add_item("test", "air") == ItemStack())
|
assert(inv:add_item("test", "air") == ItemStack())
|
||||||
assert(inv:add_item("test", item_with_meta) == ItemStack())
|
assert(inv:add_item("test", get_stack_with_meta(1)) == ItemStack())
|
||||||
assert(inv:get_stack("test", 1) == ItemStack("air 2"))
|
assert(inv:get_stack("test", 1) == ItemStack("air 2"))
|
||||||
|
|
||||||
assert(inv:room_for_item("test", "air 99"))
|
assert(inv:room_for_item("test", "air 99"))
|
||||||
|
@ -48,16 +49,28 @@ local function test_inventory()
|
||||||
inv:set_stack("test", 2, "")
|
inv:set_stack("test", 2, "")
|
||||||
|
|
||||||
assert(inv:contains_item("test", "air"))
|
assert(inv:contains_item("test", "air"))
|
||||||
|
assert(inv:contains_item("test", "air 4"))
|
||||||
|
assert(not inv:contains_item("test", "air 5"))
|
||||||
assert(not inv:contains_item("test", "air 99"))
|
assert(not inv:contains_item("test", "air 99"))
|
||||||
assert(inv:contains_item("test", item_with_meta, true))
|
assert(inv:contains_item("test", "air 2", true))
|
||||||
|
assert(not inv:contains_item("test", "air 3", true))
|
||||||
|
assert(inv:contains_item("test", get_stack_with_meta(2), true))
|
||||||
|
assert(not inv:contains_item("test", get_stack_with_meta(3), true))
|
||||||
|
|
||||||
-- Items should be removed in reverse and combine with first stack removed
|
-- Items should be removed in reverse and combine with first stack removed
|
||||||
assert(inv:remove_item("test", "air") == item_with_meta)
|
assert(inv:remove_item("test", "air") == get_stack_with_meta(1))
|
||||||
item_with_meta:set_count(2)
|
assert(inv:remove_item("test", "air 2") == get_stack_with_meta(2))
|
||||||
assert(inv:remove_item("test", "air 2") == item_with_meta)
|
|
||||||
assert(inv:remove_item("test", "air") == ItemStack("air"))
|
assert(inv:remove_item("test", "air") == ItemStack("air"))
|
||||||
assert(inv:is_empty("test"))
|
assert(inv:is_empty("test"))
|
||||||
|
|
||||||
|
inv:set_stack("test", 1, "air 3")
|
||||||
|
inv:set_stack("test", 3, get_stack_with_meta(2))
|
||||||
|
assert(inv:remove_item("test", "air 4", true) == ItemStack("air 3"))
|
||||||
|
inv:set_stack("test", 1, "air 3")
|
||||||
|
assert(inv:remove_item("test", get_stack_with_meta(3), true) == get_stack_with_meta(2))
|
||||||
|
assert(inv:remove_item("test", "air 3", true) == ItemStack("air 3"))
|
||||||
|
assert(inv:is_empty("test"))
|
||||||
|
|
||||||
-- Failure of set_list(s) should not change inventory
|
-- Failure of set_list(s) should not change inventory
|
||||||
local before = inv:get_list("test")
|
local before = inv:get_list("test")
|
||||||
pcall(inv.set_lists, inv, {test = true})
|
pcall(inv.set_lists, inv, {test = true})
|
||||||
|
|
|
@ -189,6 +189,29 @@ local function test_write_json()
|
||||||
end
|
end
|
||||||
unittests.register("test_write_json", test_write_json)
|
unittests.register("test_write_json", test_write_json)
|
||||||
|
|
||||||
|
local function lint_json_files()
|
||||||
|
-- Check that files we ship with Luanti are valid JSON
|
||||||
|
local stack = {core.get_builtin_path()}
|
||||||
|
local checked = 0
|
||||||
|
while #stack > 0 do
|
||||||
|
local path = table.remove(stack)
|
||||||
|
for _, name in ipairs(core.get_dir_list(path, true)) do
|
||||||
|
stack[#stack+1] = path .. "/" .. name
|
||||||
|
end
|
||||||
|
for _, name in ipairs(core.get_dir_list(path, false)) do
|
||||||
|
if name:match("%.json$") then
|
||||||
|
local f = io.open(path .. "/" .. name, "rb")
|
||||||
|
print(path .. "/" .. name)
|
||||||
|
assert(core.parse_json(f:read("*all"), -1) ~= nil)
|
||||||
|
f:close()
|
||||||
|
checked = checked + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(checked > 0, "no files found?!")
|
||||||
|
end
|
||||||
|
unittests.register("lint_json_files", lint_json_files)
|
||||||
|
|
||||||
local function test_game_info()
|
local function test_game_info()
|
||||||
local info = core.get_game_info()
|
local info = core.get_game_info()
|
||||||
local game_conf = Settings(info.path .. "/game.conf")
|
local game_conf = Settings(info.path .. "/game.conf")
|
||||||
|
|
40
games/devtest/mods/unittests/version.lua
Normal file
40
games/devtest/mods/unittests/version.lua
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
unittests.register("test_get_version", function()
|
||||||
|
local version = core.get_version()
|
||||||
|
assert(type(version) == "table")
|
||||||
|
assert(type(version.project) == "string")
|
||||||
|
assert(type(version.string) == "string")
|
||||||
|
assert(type(version.proto_min) == "number")
|
||||||
|
assert(type(version.proto_max) == "number")
|
||||||
|
assert(version.proto_max >= version.proto_min)
|
||||||
|
assert(type(version.is_dev) == "boolean")
|
||||||
|
if version.is_dev then
|
||||||
|
assert(type(version.hash) == "string")
|
||||||
|
else
|
||||||
|
assert(version.hash == nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
unittests.register("test_protocol_version", function(player)
|
||||||
|
local info = core.get_player_information(player:get_player_name())
|
||||||
|
|
||||||
|
local maxver = 0
|
||||||
|
for _, v in pairs(core.protocol_versions) do
|
||||||
|
maxver = math.max(maxver, v)
|
||||||
|
end
|
||||||
|
assert(maxver > 0) -- table must contain something valid
|
||||||
|
|
||||||
|
-- If the client is older than a known version then it's pointless.
|
||||||
|
if info.protocol_version < maxver then
|
||||||
|
core.log("warning", "test_protocol_version: client is outdated, skipping test!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local info_server = core.get_version()
|
||||||
|
if info.version_string ~= (info_server.hash or info_server.string) then
|
||||||
|
core.log("warning", "test_protocol_version: client is not the same version. False-positive possible.")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The protocol version the client and server agreed on must exist in the table.
|
||||||
|
local match = table.key_value_swap(core.protocol_versions)[info.protocol_version]
|
||||||
|
print(string.format("client proto matched: %s sent: %s", match, info.version_string))
|
||||||
|
assert(match ~= nil)
|
||||||
|
end, {player = true})
|
|
@ -132,6 +132,9 @@ enum E_VIDEO_DRIVER_FEATURE
|
||||||
//! Support for multisample textures.
|
//! Support for multisample textures.
|
||||||
EVDF_TEXTURE_MULTISAMPLE,
|
EVDF_TEXTURE_MULTISAMPLE,
|
||||||
|
|
||||||
|
//! Support for 2D array textures.
|
||||||
|
EVDF_TEXTURE_2D_ARRAY,
|
||||||
|
|
||||||
//! Only used for counting the elements of this enum
|
//! Only used for counting the elements of this enum
|
||||||
EVDF_COUNT
|
EVDF_COUNT
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,12 +26,6 @@ enum E_FILE_ARCHIVE_TYPE
|
||||||
//! A PKZIP archive
|
//! A PKZIP archive
|
||||||
EFAT_ZIP = MAKE_IRR_ID('Z', 'I', 'P', 0),
|
EFAT_ZIP = MAKE_IRR_ID('Z', 'I', 'P', 0),
|
||||||
|
|
||||||
//! A gzip archive
|
|
||||||
EFAT_GZIP = MAKE_IRR_ID('g', 'z', 'i', 'p'),
|
|
||||||
|
|
||||||
//! An Android asset file archive
|
|
||||||
EFAT_ANDROID_ASSET = MAKE_IRR_ID('A', 'S', 'S', 'E'),
|
|
||||||
|
|
||||||
//! The type of this archive is unknown
|
//! The type of this archive is unknown
|
||||||
EFAT_UNKNOWN = MAKE_IRR_ID('u', 'n', 'k', 'n')
|
EFAT_UNKNOWN = MAKE_IRR_ID('u', 'n', 'k', 'n')
|
||||||
};
|
};
|
||||||
|
@ -73,13 +67,6 @@ public:
|
||||||
but checks if file exists will fail.
|
but checks if file exists will fail.
|
||||||
*/
|
*/
|
||||||
virtual void addDirectoryToFileList(const io::path &filename) {}
|
virtual void addDirectoryToFileList(const io::path &filename) {}
|
||||||
|
|
||||||
//! An optionally used password string
|
|
||||||
/** This variable is publicly accessible from the interface in order to
|
|
||||||
avoid single access patterns to this place, and hence allow some more
|
|
||||||
obscurity.
|
|
||||||
*/
|
|
||||||
core::stringc Password;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Class which is able to create an archive from a file.
|
//! Class which is able to create an archive from a file.
|
||||||
|
|
|
@ -25,7 +25,7 @@ class IImage : public virtual IReferenceCounted
|
||||||
public:
|
public:
|
||||||
//! constructor
|
//! constructor
|
||||||
IImage(ECOLOR_FORMAT format, const core::dimension2d<u32> &size, bool deleteMemory) :
|
IImage(ECOLOR_FORMAT format, const core::dimension2d<u32> &size, bool deleteMemory) :
|
||||||
Format(format), Size(size), Data(0), MipMapsData(0), BytesPerPixel(0), Pitch(0), DeleteMemory(deleteMemory), DeleteMipMapsMemory(false)
|
Format(format), Size(size), Data(0), BytesPerPixel(0), Pitch(0), DeleteMemory(deleteMemory)
|
||||||
{
|
{
|
||||||
BytesPerPixel = getBitsPerPixelFromFormat(Format) / 8;
|
BytesPerPixel = getBitsPerPixelFromFormat(Format) / 8;
|
||||||
Pitch = BytesPerPixel * Size.Width;
|
Pitch = BytesPerPixel * Size.Width;
|
||||||
|
@ -36,9 +36,6 @@ public:
|
||||||
{
|
{
|
||||||
if (DeleteMemory)
|
if (DeleteMemory)
|
||||||
delete[] Data;
|
delete[] Data;
|
||||||
|
|
||||||
if (DeleteMipMapsMemory)
|
|
||||||
delete[] MipMapsData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the color format
|
//! Returns the color format
|
||||||
|
@ -56,7 +53,6 @@ public:
|
||||||
//! Returns bits per pixel.
|
//! Returns bits per pixel.
|
||||||
u32 getBitsPerPixel() const
|
u32 getBitsPerPixel() const
|
||||||
{
|
{
|
||||||
|
|
||||||
return getBitsPerPixelFromFormat(Format);
|
return getBitsPerPixelFromFormat(Format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,87 +185,6 @@ public:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Get mipmaps data.
|
|
||||||
/** Note that different mip levels are just behind each other in memory block.
|
|
||||||
So if you just get level 1 you also have the data for all other levels.
|
|
||||||
There is no level 0 - use getData to get the original image data.
|
|
||||||
*/
|
|
||||||
void *getMipMapsData(irr::u32 mipLevel = 1) const
|
|
||||||
{
|
|
||||||
if (MipMapsData && mipLevel > 0) {
|
|
||||||
size_t dataSize = 0;
|
|
||||||
core::dimension2du mipSize(Size);
|
|
||||||
u32 i = 1; // We want the start of data for this level, not end.
|
|
||||||
|
|
||||||
while (i != mipLevel) {
|
|
||||||
if (mipSize.Width > 1)
|
|
||||||
mipSize.Width >>= 1;
|
|
||||||
|
|
||||||
if (mipSize.Height > 1)
|
|
||||||
mipSize.Height >>= 1;
|
|
||||||
|
|
||||||
dataSize += getDataSizeFromFormat(Format, mipSize.Width, mipSize.Height);
|
|
||||||
|
|
||||||
++i;
|
|
||||||
if (mipSize.Width == 1 && mipSize.Height == 1 && i < mipLevel)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MipMapsData + dataSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Set mipmaps data.
|
|
||||||
/** This method allows you to put custom mipmaps data for
|
|
||||||
image.
|
|
||||||
\param data A byte array with pixel color information
|
|
||||||
\param ownForeignMemory If true, the image will use the data
|
|
||||||
pointer directly and own it afterward. If false, the memory
|
|
||||||
will by copied internally.
|
|
||||||
\param deleteMemory Whether the memory is deallocated upon
|
|
||||||
destruction. */
|
|
||||||
void setMipMapsData(void *data, bool ownForeignMemory)
|
|
||||||
{
|
|
||||||
if (data != MipMapsData) {
|
|
||||||
if (DeleteMipMapsMemory) {
|
|
||||||
delete[] MipMapsData;
|
|
||||||
|
|
||||||
DeleteMipMapsMemory = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
if (ownForeignMemory) {
|
|
||||||
MipMapsData = static_cast<u8 *>(data);
|
|
||||||
|
|
||||||
DeleteMipMapsMemory = false;
|
|
||||||
} else {
|
|
||||||
u32 dataSize = 0;
|
|
||||||
u32 width = Size.Width;
|
|
||||||
u32 height = Size.Height;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (width > 1)
|
|
||||||
width >>= 1;
|
|
||||||
|
|
||||||
if (height > 1)
|
|
||||||
height >>= 1;
|
|
||||||
|
|
||||||
dataSize += getDataSizeFromFormat(Format, width, height);
|
|
||||||
} while (width != 1 || height != 1);
|
|
||||||
|
|
||||||
MipMapsData = new u8[dataSize];
|
|
||||||
memcpy(MipMapsData, data, dataSize);
|
|
||||||
|
|
||||||
DeleteMipMapsMemory = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
MipMapsData = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Returns a pixel
|
//! Returns a pixel
|
||||||
virtual SColor getPixel(u32 x, u32 y) const = 0;
|
virtual SColor getPixel(u32 x, u32 y) const = 0;
|
||||||
|
|
||||||
|
@ -277,30 +192,24 @@ public:
|
||||||
virtual void setPixel(u32 x, u32 y, const SColor &color, bool blend = false) = 0;
|
virtual void setPixel(u32 x, u32 y, const SColor &color, bool blend = false) = 0;
|
||||||
|
|
||||||
//! Copies this surface into another, if it has the exact same size and format.
|
//! Copies this surface into another, if it has the exact same size and format.
|
||||||
/** NOTE: mipmaps are ignored
|
/** \return True if it was copied, false otherwise.
|
||||||
\return True if it was copied, false otherwise.
|
|
||||||
*/
|
*/
|
||||||
virtual bool copyToNoScaling(void *target, u32 width, u32 height, ECOLOR_FORMAT format = ECF_A8R8G8B8, u32 pitch = 0) const = 0;
|
virtual bool copyToNoScaling(void *target, u32 width, u32 height, ECOLOR_FORMAT format = ECF_A8R8G8B8, u32 pitch = 0) const = 0;
|
||||||
|
|
||||||
//! Copies the image into the target, scaling the image to fit
|
//! Copies the image into the target, scaling the image to fit
|
||||||
/** NOTE: mipmaps are ignored */
|
|
||||||
virtual void copyToScaling(void *target, u32 width, u32 height, ECOLOR_FORMAT format = ECF_A8R8G8B8, u32 pitch = 0) = 0;
|
virtual void copyToScaling(void *target, u32 width, u32 height, ECOLOR_FORMAT format = ECF_A8R8G8B8, u32 pitch = 0) = 0;
|
||||||
|
|
||||||
//! Copies the image into the target, scaling the image to fit
|
//! Copies the image into the target, scaling the image to fit
|
||||||
/** NOTE: mipmaps are ignored */
|
|
||||||
virtual void copyToScaling(IImage *target) = 0;
|
virtual void copyToScaling(IImage *target) = 0;
|
||||||
|
|
||||||
//! copies this surface into another
|
//! copies this surface into another
|
||||||
/** NOTE: mipmaps are ignored */
|
|
||||||
virtual void copyTo(IImage *target, const core::position2d<s32> &pos = core::position2d<s32>(0, 0)) = 0;
|
virtual void copyTo(IImage *target, const core::position2d<s32> &pos = core::position2d<s32>(0, 0)) = 0;
|
||||||
|
|
||||||
//! copies this surface into another
|
//! copies this surface into another
|
||||||
/** NOTE: mipmaps are ignored */
|
|
||||||
virtual void copyTo(IImage *target, const core::position2d<s32> &pos, const core::rect<s32> &sourceRect, const core::rect<s32> *clipRect = 0) = 0;
|
virtual void copyTo(IImage *target, const core::position2d<s32> &pos, const core::rect<s32> &sourceRect, const core::rect<s32> *clipRect = 0) = 0;
|
||||||
|
|
||||||
//! copies this surface into another, using the alpha mask and cliprect and a color to add with
|
//! copies this surface into another, using the alpha mask and cliprect and a color to add with
|
||||||
/** NOTE: mipmaps are ignored
|
/** \param combineAlpha - When true then combine alpha channels. When false replace target image alpha with source image alpha.
|
||||||
\param combineAlpha - When true then combine alpha channels. When false replace target image alpha with source image alpha.
|
|
||||||
*/
|
*/
|
||||||
virtual void copyToWithAlpha(IImage *target, const core::position2d<s32> &pos,
|
virtual void copyToWithAlpha(IImage *target, const core::position2d<s32> &pos,
|
||||||
const core::rect<s32> &sourceRect, const SColor &color,
|
const core::rect<s32> &sourceRect, const SColor &color,
|
||||||
|
@ -308,7 +217,6 @@ public:
|
||||||
bool combineAlpha = false) = 0;
|
bool combineAlpha = false) = 0;
|
||||||
|
|
||||||
//! copies this surface into another, scaling it to fit, applying a box filter
|
//! copies this surface into another, scaling it to fit, applying a box filter
|
||||||
/** NOTE: mipmaps are ignored */
|
|
||||||
virtual void copyToScalingBoxFilter(IImage *target, s32 bias = 0, bool blend = false) = 0;
|
virtual void copyToScalingBoxFilter(IImage *target, s32 bias = 0, bool blend = false) = 0;
|
||||||
|
|
||||||
//! fills the surface with given color
|
//! fills the surface with given color
|
||||||
|
@ -416,13 +324,11 @@ protected:
|
||||||
core::dimension2d<u32> Size;
|
core::dimension2d<u32> Size;
|
||||||
|
|
||||||
u8 *Data;
|
u8 *Data;
|
||||||
u8 *MipMapsData;
|
|
||||||
|
|
||||||
u32 BytesPerPixel;
|
u32 BytesPerPixel;
|
||||||
u32 Pitch;
|
u32 Pitch;
|
||||||
|
|
||||||
bool DeleteMemory;
|
bool DeleteMemory;
|
||||||
bool DeleteMipMapsMemory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace video
|
} // end namespace video
|
||||||
|
|
|
@ -34,16 +34,16 @@ public:
|
||||||
/** \return Pointer to mesh which is displayed by this node. */
|
/** \return Pointer to mesh which is displayed by this node. */
|
||||||
virtual IMesh *getMesh(void) = 0;
|
virtual IMesh *getMesh(void) = 0;
|
||||||
|
|
||||||
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
|
//! Sets if the scene node should not copy the materials of the mesh but use them directly.
|
||||||
/** In this way it is possible to change the materials of a mesh
|
/** In this way it is possible to change the materials of a mesh
|
||||||
causing all mesh scene nodes referencing this mesh to change, too.
|
causing all mesh scene nodes referencing this mesh to change, too.
|
||||||
\param readonly Flag if the materials shall be read-only. */
|
\param shared Flag if the materials shall be shared. */
|
||||||
virtual void setReadOnlyMaterials(bool readonly) = 0;
|
virtual void setSharedMaterials(bool shared) = 0;
|
||||||
|
|
||||||
//! Check if the scene node should not copy the materials of the mesh but use them in a read only style
|
//! Check if the scene node does not copy the materials of the mesh but uses them directly.
|
||||||
/** This flag can be set by setReadOnlyMaterials().
|
/** This flag can be set by setSharedMaterials().
|
||||||
\return Whether the materials are read-only. */
|
\return Whether the materials are shared. */
|
||||||
virtual bool isReadOnlyMaterials() const = 0;
|
virtual bool isSharedMaterials() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace scene
|
} // end namespace scene
|
||||||
|
|
|
@ -310,7 +310,11 @@ public:
|
||||||
\return The material at that index. */
|
\return The material at that index. */
|
||||||
virtual video::SMaterial &getMaterial(u32 num)
|
virtual video::SMaterial &getMaterial(u32 num)
|
||||||
{
|
{
|
||||||
return video::IdentityMaterial;
|
// We return a default material since a reference can't be null,
|
||||||
|
// but note that writing to this is a mistake either by a child class
|
||||||
|
// or the caller, because getMaterialCount() is zero.
|
||||||
|
// Doing so will helpfully cause a segfault.
|
||||||
|
return const_cast<video::SMaterial&>(video::IdentityMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Get amount of materials used by this scene node.
|
//! Get amount of materials used by this scene node.
|
||||||
|
|
|
@ -68,30 +68,12 @@ enum E_TEXTURE_CREATION_FLAG
|
||||||
not recommended to enable this flag. */
|
not recommended to enable this flag. */
|
||||||
ETCF_NO_ALPHA_CHANNEL = 0x00000020,
|
ETCF_NO_ALPHA_CHANNEL = 0x00000020,
|
||||||
|
|
||||||
//! Allow the Driver to use Non-Power-2-Textures
|
|
||||||
/** BurningVideo can handle Non-Power-2 Textures in 2D (GUI), but not in 3D. */
|
|
||||||
ETCF_ALLOW_NON_POWER_2 = 0x00000040,
|
|
||||||
|
|
||||||
//! Allow the driver to keep a copy of the texture in memory
|
//! Allow the driver to keep a copy of the texture in memory
|
||||||
/** Enabling this makes calls to ITexture::lock a lot faster, but costs main memory.
|
/** Enabling this makes calls to ITexture::lock a lot faster, but costs main memory.
|
||||||
This is disabled by default.
|
This is disabled by default.
|
||||||
*/
|
*/
|
||||||
ETCF_ALLOW_MEMORY_COPY = 0x00000080,
|
ETCF_ALLOW_MEMORY_COPY = 0x00000080,
|
||||||
|
|
||||||
//! Enable automatic updating mip maps when the base texture changes.
|
|
||||||
/** Default is true.
|
|
||||||
This flag is only used when ETCF_CREATE_MIP_MAPS is also enabled and if the driver supports it.
|
|
||||||
Please note:
|
|
||||||
- On D3D (and maybe older OGL?) you can no longer manually set mipmap data when enabled
|
|
||||||
(for example mips from image loading will be ignored).
|
|
||||||
- On D3D (and maybe older OGL?) texture locking for mipmap levels usually won't work anymore.
|
|
||||||
- On new OGL this flag is ignored.
|
|
||||||
- When disabled you do _not_ get hardware mipmaps on D3D, so mipmap generation can be slower.
|
|
||||||
- When disabled you can still update your mipmaps when the texture changed by manually calling regenerateMipMapLevels.
|
|
||||||
- You can still call regenerateMipMapLevels when this flag is enabled (it will be a hint on d3d to update mips immediately)
|
|
||||||
*/
|
|
||||||
ETCF_AUTO_GENERATE_MIP_MAPS = 0x00000100,
|
|
||||||
|
|
||||||
/** This flag is never used, it only forces the compiler to compile
|
/** This flag is never used, it only forces the compiler to compile
|
||||||
these enumeration values to 32 bit. */
|
these enumeration values to 32 bit. */
|
||||||
ETCF_FORCE_32_BIT_DO_NOT_USE = 0x7fffffff
|
ETCF_FORCE_32_BIT_DO_NOT_USE = 0x7fffffff
|
||||||
|
@ -137,19 +119,6 @@ enum E_TEXTURE_LOCK_FLAGS
|
||||||
ETLF_FLIP_Y_UP_RTT = 1
|
ETLF_FLIP_Y_UP_RTT = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Where did the last IVideoDriver::getTexture call find this texture
|
|
||||||
enum E_TEXTURE_SOURCE
|
|
||||||
{
|
|
||||||
//! IVideoDriver::getTexture was never called (texture created otherwise)
|
|
||||||
ETS_UNKNOWN,
|
|
||||||
|
|
||||||
//! Texture has been found in cache
|
|
||||||
ETS_FROM_CACHE,
|
|
||||||
|
|
||||||
//! Texture had to be loaded
|
|
||||||
ETS_FROM_FILE
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Enumeration describing the type of ITexture.
|
//! Enumeration describing the type of ITexture.
|
||||||
enum E_TEXTURE_TYPE
|
enum E_TEXTURE_TYPE
|
||||||
{
|
{
|
||||||
|
@ -160,7 +129,10 @@ enum E_TEXTURE_TYPE
|
||||||
ETT_2D_MS,
|
ETT_2D_MS,
|
||||||
|
|
||||||
//! Cubemap texture.
|
//! Cubemap texture.
|
||||||
ETT_CUBEMAP
|
ETT_CUBEMAP,
|
||||||
|
|
||||||
|
//! 2D array texture
|
||||||
|
ETT_2D_ARRAY
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Interface of a Video Driver dependent Texture.
|
//! Interface of a Video Driver dependent Texture.
|
||||||
|
@ -178,7 +150,7 @@ public:
|
||||||
//! constructor
|
//! constructor
|
||||||
ITexture(const io::path &name, E_TEXTURE_TYPE type) :
|
ITexture(const io::path &name, E_TEXTURE_TYPE type) :
|
||||||
NamedPath(name), DriverType(EDT_NULL), OriginalColorFormat(ECF_UNKNOWN),
|
NamedPath(name), DriverType(EDT_NULL), OriginalColorFormat(ECF_UNKNOWN),
|
||||||
ColorFormat(ECF_UNKNOWN), Pitch(0), HasMipMaps(false), IsRenderTarget(false), Source(ETS_UNKNOWN), Type(type)
|
ColorFormat(ECF_UNKNOWN), Pitch(0), HasMipMaps(false), IsRenderTarget(false), Type(type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,9 +169,7 @@ public:
|
||||||
only mode or read from in write only mode.
|
only mode or read from in write only mode.
|
||||||
Support for this feature depends on the driver, so don't rely on the
|
Support for this feature depends on the driver, so don't rely on the
|
||||||
texture being write-protected when locking with read-only, etc.
|
texture being write-protected when locking with read-only, etc.
|
||||||
\param mipmapLevel NOTE: Currently broken, sorry, we try if we can repair it for 1.9 release.
|
\param mipmapLevel Number of the mipmapLevel to lock. 0 is main texture.
|
||||||
Number of the mipmapLevel to lock. 0 is main texture.
|
|
||||||
Non-existing levels will silently fail and return 0.
|
|
||||||
\param layer It determines which cubemap face or texture array layer should be locked.
|
\param layer It determines which cubemap face or texture array layer should be locked.
|
||||||
\param lockFlags See E_TEXTURE_LOCK_FLAGS documentation.
|
\param lockFlags See E_TEXTURE_LOCK_FLAGS documentation.
|
||||||
\return Returns a pointer to the pixel data. The format of the pixel can
|
\return Returns a pointer to the pixel data. The format of the pixel can
|
||||||
|
@ -215,14 +185,9 @@ public:
|
||||||
|
|
||||||
//! Regenerates the mip map levels of the texture.
|
//! Regenerates the mip map levels of the texture.
|
||||||
/** Required after modifying the texture, usually after calling unlock().
|
/** Required after modifying the texture, usually after calling unlock().
|
||||||
\param data Optional parameter to pass in image data which will be
|
|
||||||
used instead of the previously stored or automatically generated mipmap
|
|
||||||
data. The data has to be a continuous pixel data for all mipmaps until
|
|
||||||
1x1 pixel. Each mipmap has to be half the width and height of the previous
|
|
||||||
level. At least one pixel will be always kept.
|
|
||||||
\param layer It informs a texture about which cubemap or texture array layer
|
\param layer It informs a texture about which cubemap or texture array layer
|
||||||
needs mipmap regeneration. */
|
needs mipmap regeneration. */
|
||||||
virtual void regenerateMipMapLevels(void *data = 0, u32 layer = 0) = 0;
|
virtual void regenerateMipMapLevels(u32 layer = 0) = 0;
|
||||||
|
|
||||||
//! Get original size of the texture.
|
//! Get original size of the texture.
|
||||||
/** The texture is usually scaled, if it was created with an unoptimal
|
/** The texture is usually scaled, if it was created with an unoptimal
|
||||||
|
@ -275,12 +240,6 @@ public:
|
||||||
//! Get name of texture (in most cases this is the filename)
|
//! Get name of texture (in most cases this is the filename)
|
||||||
const io::SNamedPath &getName() const { return NamedPath; }
|
const io::SNamedPath &getName() const { return NamedPath; }
|
||||||
|
|
||||||
//! Check where the last IVideoDriver::getTexture found this texture
|
|
||||||
E_TEXTURE_SOURCE getSource() const { return Source; }
|
|
||||||
|
|
||||||
//! Used internally by the engine to update Source status on IVideoDriver::getTexture calls.
|
|
||||||
void updateSource(E_TEXTURE_SOURCE source) { Source = source; }
|
|
||||||
|
|
||||||
//! Returns if the texture has an alpha channel
|
//! Returns if the texture has an alpha channel
|
||||||
bool hasAlpha() const
|
bool hasAlpha() const
|
||||||
{
|
{
|
||||||
|
@ -329,7 +288,6 @@ protected:
|
||||||
u32 Pitch;
|
u32 Pitch;
|
||||||
bool HasMipMaps;
|
bool HasMipMaps;
|
||||||
bool IsRenderTarget;
|
bool IsRenderTarget;
|
||||||
E_TEXTURE_SOURCE Source;
|
|
||||||
E_TEXTURE_TYPE Type;
|
E_TEXTURE_TYPE Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -232,6 +232,15 @@ public:
|
||||||
information. */
|
information. */
|
||||||
virtual ITexture *addTexture(const io::path &name, IImage *image) = 0;
|
virtual ITexture *addTexture(const io::path &name, IImage *image) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an array texture from IImages.
|
||||||
|
* @param name A name for the texture.
|
||||||
|
* @param images Pointer to array of images
|
||||||
|
* @param count Number of images (must be at least 1)
|
||||||
|
* @return Pointer to the newly created texture
|
||||||
|
*/
|
||||||
|
virtual ITexture *addArrayTexture(const io::path &name, IImage **images, u32 count) = 0;
|
||||||
|
|
||||||
//! Creates a cubemap texture from loaded IImages.
|
//! Creates a cubemap texture from loaded IImages.
|
||||||
/** \param name A name for the texture. Later calls of getTexture() with this name will return this texture.
|
/** \param name A name for the texture. Later calls of getTexture() with this name will return this texture.
|
||||||
The name can _not_ be empty.
|
The name can _not_ be empty.
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "IrrCompileConfig.h"
|
#include "IrrCompileConfig.h"
|
||||||
#include "position2d.h"
|
#include "position2d.h"
|
||||||
#include "SColor.h" // video::ECOLOR_FORMAT
|
#include "SColor.h" // video::ECOLOR_FORMAT
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -342,6 +343,27 @@ public:
|
||||||
{
|
{
|
||||||
return video::isDriverSupported(driver);
|
return video::isDriverSupported(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Get the corresponding scancode for the keycode.
|
||||||
|
/**
|
||||||
|
\param key The keycode to convert.
|
||||||
|
\return The implementation-dependent scancode for the key (represented by the u32 component) or, if a scancode is not
|
||||||
|
available, the corresponding Irrlicht keycode (represented by the EKEY_CODE component).
|
||||||
|
*/
|
||||||
|
virtual std::variant<u32, EKEY_CODE> getScancodeFromKey(const Keycode &key) const {
|
||||||
|
if (auto pv = std::get_if<EKEY_CODE>(&key))
|
||||||
|
return *pv;
|
||||||
|
return (u32)std::get<wchar_t>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the corresponding keycode for the scancode.
|
||||||
|
/**
|
||||||
|
\param scancode The implementation-dependent scancode for the key.
|
||||||
|
\return The corresponding keycode.
|
||||||
|
*/
|
||||||
|
virtual Keycode getKeyFromScancode(const u32 scancode) const {
|
||||||
|
return Keycode(KEY_UNKNOWN, (wchar_t)scancode);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace irr
|
} // end namespace irr
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
|
@ -182,4 +183,30 @@ enum EKEY_CODE
|
||||||
KEY_KEY_CODES_COUNT = 0x100 // this is not a key, but the amount of keycodes there are.
|
KEY_KEY_CODES_COUNT = 0x100 // this is not a key, but the amount of keycodes there are.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A Keycode is either a character produced by the key or one of Irrlicht's codes (EKEY_CODE)
|
||||||
|
class Keycode : public std::variant<EKEY_CODE, wchar_t> {
|
||||||
|
using super = std::variant<EKEY_CODE, wchar_t>;
|
||||||
|
public:
|
||||||
|
Keycode() : Keycode(KEY_KEY_CODES_COUNT, L'\0') {}
|
||||||
|
|
||||||
|
Keycode(EKEY_CODE code, wchar_t ch)
|
||||||
|
{
|
||||||
|
emplace(code, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
using super::emplace;
|
||||||
|
void emplace(EKEY_CODE code, wchar_t ch)
|
||||||
|
{
|
||||||
|
if (isValid(code))
|
||||||
|
emplace<EKEY_CODE>(code);
|
||||||
|
else
|
||||||
|
emplace<wchar_t>(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isValid(EKEY_CODE code)
|
||||||
|
{
|
||||||
|
return code > 0 && code < KEY_KEY_CODES_COUNT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // end namespace irr
|
} // end namespace irr
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue