Compare commits

...

728 Commits

Author SHA1 Message Date
Gregor Parzefall
d445638265 Bump version to 5.8.1 2024-05-06 20:58:14 +02:00
Gregor Parzefall
f61f6626b7 Fix Android build for 5.8.1 2024-05-06 20:58:14 +02:00
Gregor Parzefall
857ba25115 Android CI: Additionally make an AAB for uploading to the Play Store (#14584) 2024-05-06 20:58:14 +02:00
grorp
00774bc28b Fix some Game members not being freed after some startup errors (#14561) 2024-05-06 20:58:14 +02:00
Gregor Parzefall
f572266f19 Fix local server startup and shutdown blocking the main thread
Co-authored-by: sfan5 <sfan5@live.de>
2024-05-06 20:58:14 +02:00
Gregor Parzefall
c3893064a3 Fix all cached media being loaded at once on the main thread 2024-05-06 20:58:14 +02:00
grorp
4183443f02 Allow sync HTTP fetches to be interrupted to fix hanging (#14412)
Co-authored-by: Jude Melton-Houghton <jwmhjwmh@gmail.com>
2024-05-06 20:58:14 +02:00
sfan5
5715434d5e Skip Android deps download if they already exist
It's close to impossible to test locally built changes otherwise.
2024-05-06 20:58:14 +02:00
lhofhansl
ab2419db24 Allow shaders with disabled post processing pipeline (#14338)
- Allow disabling of the post processing pipeline while leaving shaders enabled
- Also disable post processing on Android by default
2024-05-06 20:58:14 +02:00
David Heidelberg
35a83c3514 Enable IPO/LTO by default except for debug builds (#14198)
Test case:

```
$ cmake . -DRUN_IN_PLACE=TRUE -DCMAKE_BUILD_TYPE=Release -DBUILD_SERVER=TRUE -DENABLE_TOUCH=FALSE

         minetest minetestserver
W/o LTO:      13M           7.3M
W/  LTO:      11M           5.9M
difference:   15%            19%
```

Also fixes various compiler warnings resulting from compilation using LTO.

---------

Signed-off-by: David Heidelberg <david@ixit.cz>
2024-05-06 20:58:14 +02:00
sfan5
de09cac1e9 Drop valgrind from CI and instead enable ASan
The recently added ioctl use is reported as a false-positive by valgrind.
I tried moving it to different compilers/versions two times and only
hit further issues that were valgrind's fault.

Also includes a tiny fix.
2024-05-06 20:58:14 +02:00
sfan5
b64f4bdb3a Optimize fs::CopyFileContents on Linux and Windows 2024-05-06 20:58:14 +02:00
sfan5
008310aad9 Add unit tests for fs::CopyFileContents 2024-05-06 20:58:14 +02:00
sfan5
4d024d737c Bypass media transfer in single player 2024-05-06 20:58:14 +02:00
grorp
50edb30a18 Save the settings in more cases to avoid losing setting changes (especially on Android) (#14266) 2024-05-06 20:58:14 +02:00
Muhammad Rifqi Priyo Susanto
00f6bd0f08 Android: Use the correct value for notification (#14209)
The notification channel creation is moved into MainActivity.
The notification channel ID string is stored into a static variable.
The name and description of the notification channel are stored into the strings resource file.

Co-authored-by: sfan5 <sfan5@live.de>
2024-05-06 20:58:14 +02:00
Maintainer_
81e40a1172 Fix GameUI text staying visible during shutdown. (#14197) 2024-05-06 20:58:14 +02:00
grorp
fe4f89f3fa Touchscreen: Make server-sent overrides of button textures work (#14145) 2024-05-06 20:58:14 +02:00
Gregor Parzefall
0d372250c1 Fix TouchScreenGUI ignoring server-sent pitch changes 2024-05-06 20:58:14 +02:00
Gregor Parzefall
367720020c Fix touch input on Linux
The code relied on touch IDs being consecutive. This is true on Android, but not on Linux.
Therefore, touch input on Linux was broken since 53886dcdb5.
2024-05-06 20:58:14 +02:00
grorp
0dab82085d Fix unittest failure for release versions (#14067) 2024-05-06 20:58:14 +02:00
SmallJoker
cb211d63cd Merge remote-tracking branch 'upstream/stable-5' into HEAD 2023-12-04 19:04:18 +01:00
rubenwardy
49ce5a2de6 Bump version to 5.8.0 2023-12-04 17:15:36 +00:00
updatepo.sh
30769589bf Remove junk translation file 2023-12-03 19:11:32 +01:00
updatepo.sh
6cf9b7472a Run mod_translation_updater.py 2023-12-03 19:03:45 +01:00
updatepo.sh
4be8b77598 Run updatepo.sh 2023-12-03 18:48:54 +01:00
updatepo.sh
bae9f65411 Update from builtin/settingtypes.txt 2023-12-03 18:47:50 +01:00
Krock
0a20d30f83 Various little translation fixups 2023-12-03 18:41:15 +01:00
Nisa Syazwani
7245bcc614 Translated using Weblate (Malay)
Currently translated at 100.0% (1310 of 1310 strings)
2023-12-03 18:41:15 +01:00
chocomint
51136780d6 Translated using Weblate (Spanish)
Currently translated at 89.6% (1174 of 1310 strings)
2023-12-03 18:41:15 +01:00
gallegonovato
ea6eb0dfc8 Translated using Weblate (Spanish)
Currently translated at 89.6% (1174 of 1310 strings)
2023-12-03 18:41:15 +01:00
nyommer
ab88fc6835 Translated using Weblate (Hungarian)
Currently translated at 96.7% (1268 of 1310 strings)
2023-12-03 18:41:15 +01:00
AlexTECPlayz
30b28280eb Translated using Weblate (Romanian)
Currently translated at 49.3% (647 of 1310 strings)
2023-12-03 18:41:15 +01:00
BreadW
e5672111d2 Translated using Weblate (Japanese)
Currently translated at 100.0% (1310 of 1310 strings)
2023-12-03 18:41:15 +01:00
Spurnita
ce0aca49c2 Translated using Weblate (Catalan)
Currently translated at 22.5% (296 of 1310 strings)
2023-12-03 18:41:15 +01:00
Muhammad Rifqi Priyo Susanto
0d3b71564f Translated using Weblate (Javanese)
Currently translated at 12.9% (170 of 1310 strings)
2023-12-03 18:41:15 +01:00
Ritwik
0a51fde971 Translated using Weblate (Hindi)
Currently translated at 29.8% (391 of 1310 strings)
2023-12-03 18:41:15 +01:00
milewood
a13a165e9b Translated using Weblate (Chinese (Simplified))
Currently translated at 84.0% (1101 of 1310 strings)
2023-12-03 18:41:15 +01:00
Wuzzy
8a7d3d07de Translated using Weblate (German)
Currently translated at 100.0% (1310 of 1310 strings)
2023-12-03 18:41:15 +01:00
Giov4
0977728ea0 Translated using Weblate (Italian)
Currently translated at 93.7% (1228 of 1310 strings)
2023-12-03 18:41:15 +01:00
Yaya - Nurul Azeera Hidayah @ Muhammad Nur Hidayat Yasuyoshi
92eb63c867 Translated using Weblate (Malay + Jawi) 2023-12-03 18:41:07 +01:00
YearOfFuture
0c4a15fa16 Translated using Weblate (Ukrainian)
Currently translated at 75.4% (989 of 1310 strings)
2023-12-03 18:39:34 +01:00
Nanashi Mumei
01ac9e15ef Translated using Weblate (Russian)
Currently translated at 100.0% (1310 of 1310 strings)
2023-12-03 18:39:34 +01:00
Muhammad Rifqi Priyo Susanto
dd3fc83777 Translated using Weblate (Indonesian)
Currently translated at 100.0% (1310 of 1310 strings)
2023-12-03 18:39:34 +01:00
waxtatect
6a5e480a58 Translated using Weblate (French)
Currently translated at 100.0% (1310 of 1310 strings)
2023-12-03 18:39:34 +01:00
Lars Müller
419d971891 Translated using Weblate (German)
Currently translated at 99.0% (1297 of 1310 strings)
2023-12-03 18:17:42 +01:00
sfan5
9e62cb5c04 Translated using Weblate (German)
Currently translated at 99.0% (1297 of 1310 strings)
2023-12-03 18:17:42 +01:00
Desour
bf53e7e1ca Fix anticheat false positives whith speed physics override 2023-12-03 12:23:17 +01:00
AFCMS
91134015e7 Document minetest.get_gametime() returning nil at init time (#14047)
Co-authored-by: sfan5 <sfan5@live.de>
2023-12-03 15:00:29 +07:00
Muhammad Rifqi Priyo Susanto
047520d91e Inventory: Add remaining items into the source slot directly (#14021)
Remaining items are added into the source slot directly when left-dragging over the source slot.
2023-12-03 15:00:07 +07:00
DS
6106e4e72b Fix sound and particlespawner id generation (#14059)
* Fix server sound ids being reused to early

* Fix particlespawner id generation

It always returned 0.
Also, now the ids always grow, to make a conflict with ids in lua unlikely.
2023-12-01 00:09:53 +01:00
SmallJoker
a7e5456099 Server: avoid re-use of recent ParticleSpawner and Sound IDs (#14045)
This improves the reliability when removing and re-adding handles quickly.
Looping through the entire ID range avoids collisions caused by any race condition.
2023-11-29 21:10:19 +01:00
sfan5
d6a8b546e4 Enable clean transparent filter in more cases
It was determined that this fixes scaling artifacts that can happen with bilinear,
trilinear or anisotropic filtering alone.
Since the previous commit did not bring back the relevant setting, we fix this
shortcoming by just enabling it in all cases where it is known to help.
2023-11-29 21:09:21 +01:00
sfan5
7f9326805c Return texture filter settings to previous state
This partially reverts commit 72ef90885d.

fixes #14007
2023-11-29 21:09:21 +01:00
sfan5
36f4953502 Update credits for 5.8.0 release (#14017) 2023-11-28 23:11:29 +01:00
grorp
dc6452db1b Don't copy user texture packs into Android bundle (#14053) 2023-11-28 21:02:56 +01:00
grorp
cfe1953c2d Take aliases into account for automatic package installation (#14052) 2023-11-28 21:02:41 +01:00
Wuzzy
dfe00f88e1 Fix missing word in German builtin translation (#14051) 2023-11-28 21:02:19 +01:00
Muhammad Rifqi Priyo Susanto
53886dcdb5 Formspec: Pass the second-touch event as is (#13872)
The second-touch event is passed to the GUIFormSpecMenu::OnEvent() function as a touch event.
There are two types of event for inventory formspec: (1) mouse event and (2) touch event.
The touch event is just a modifier of the mouse event.


Co-authored-by: Gregor Parzefall <82708541+grorp@users.noreply.github.com>
2023-11-28 07:00:07 +07:00
grorp
771da80bbb Make it possible again to see item tooltips on Android (#14029)
This change is a quick fix so that item tooltips show again on Android.
2023-11-25 17:07:07 +01:00
Zughy
0f3ac7c956 Update Italian builtin translation (#13997) 2023-11-25 17:05:07 +01:00
Muhammad Rifqi Priyo Susanto
71490a417e Update Indonesian translation of builtin (#13996)
U+0020 (Space) is changed to U+00A0 (No-Break Space) to match the original string.
2023-11-25 17:04:44 +01:00
grorp
4255ac3022 Mainmenu: Avoid the header being displayed behind the formspec (#13924)
This change keeps the current header placement code, but adds additional code to make sure the header doesn't end up behind the formspec.
2023-11-25 17:04:33 +01:00
ZenonSeth
6783734612 Wireshark dissector: Made sure var 'pos' was only assigned locally to function (#14027) 2023-11-23 18:26:00 +01:00
Wuzzy
61db32beee Fix mod translation updater bugs (#13974) 2023-11-19 20:46:52 +01:00
MisterE123
31ee7af3ab lua_api.md: Add tick marks to position HUD element 2023-11-19 20:46:40 +01:00
jordan4ibanez
72edfe3d04 Fix openSUSE build dependencies
They were incomplete.
2023-11-19 20:46:03 +01:00
Desour
7199ee4ff8 Devtest: Fix testnodes bouncy color calculation
Values were out of range.
2023-11-19 20:45:18 +01:00
Desour
585e6aa80b Clamp values in read_ARGB8 2023-11-19 20:45:18 +01:00
Desour
1bc74b0ba1 Fix undefined inf to s32 cast in GUIScrollBar::setPos 2023-11-19 20:45:18 +01:00
Desour
73e85b2ebb Fix cached wanted_range and camera_fov being written with out-of-range value 2023-11-19 20:45:18 +01:00
sfan5
0e4de28988 Try to fix VS build failures 2023-11-19 16:22:20 +01:00
Muhammad Rifqi Priyo Susanto
aa912e90a7 Make text containers wider in the Volume Change dialog (#13995)
These containers are widened to account for translations.
2023-11-15 07:00:03 +07:00
DS
8cf76e004f Add new flags to minetest.features for 5.8.0 features (#13978) 2023-11-12 20:08:57 +01:00
superfloh247
7cb20dd6c2 Fix undefined behaviour in modulo360f (#13976)
Resolves a crash on macOS/arm64 by no longer depending on UB.
2023-11-12 20:08:33 +01:00
updatepo.sh
2bc0d76f63 Update translation files 2023-11-11 12:11:09 +01:00
updatepo.sh
8abb5796ed Update example conf and settings translations 2023-11-11 12:09:35 +01:00
YearOfFuture
7a658c1a6a Translated using Weblate (Ukrainian)
Currently translated at 76.3% (1023 of 1340 strings)
2023-11-11 12:06:10 +01:00
Maksim Gamarnik
1b0a34b9d1 Translated using Weblate (Ukrainian)
Currently translated at 72.4% (971 of 1340 strings)
2023-11-11 12:06:10 +01:00
YearOfFuture
8b5fc7f23a Translated using Weblate (Ukrainian)
Currently translated at 72.4% (971 of 1340 strings)
2023-11-11 12:06:10 +01:00
Maksim Gamarnik
ee35d7df58 Translated using Weblate (Ukrainian)
Currently translated at 69.8% (936 of 1340 strings)
2023-11-11 12:06:10 +01:00
dandelionsmellr
8d1f1b4704 Translated using Weblate (Ukrainian)
Currently translated at 67.3% (902 of 1340 strings)
2023-11-11 12:06:10 +01:00
Maksim Gamarnik
50f48ce9df Translated using Weblate (Ukrainian)
Currently translated at 67.2% (901 of 1340 strings)
2023-11-11 12:06:10 +01:00
Yaya - Nurul Azeera Hidayah @ Muhammad Nur Hidayat Yasuyoshi
e14f905299 Translated using Weblate (Malay (Jawi))
Currently translated at 53.9% (723 of 1340 strings)
2023-11-11 12:06:10 +01:00
Nanashi Mumei
6980f516d4 Translated using Weblate (Russian)
Currently translated at 100.0% (1340 of 1340 strings)
2023-11-11 12:06:10 +01:00
dandelionsmellr
52e66b6dfe Translated using Weblate (Ukrainian)
Currently translated at 59.8% (802 of 1340 strings)
2023-11-11 12:06:10 +01:00
Maksim Gamarnik
645e4abf52 Translated using Weblate (Ukrainian)
Currently translated at 59.8% (802 of 1340 strings)
2023-11-11 12:06:10 +01:00
dandelionsmellr
b0932ef458 Translated using Weblate (Ukrainian)
Currently translated at 59.8% (802 of 1340 strings)
2023-11-11 12:06:10 +01:00
Muhammad Rifqi Priyo Susanto
330aee974e Translated using Weblate (Javanese)
Currently translated at 0.0% (0 of 1340 strings)
2023-11-11 12:06:10 +01:00
Timur Seber
a1d7c25587 Translated using Weblate (Tatar)
Currently translated at 7.6% (103 of 1340 strings)
2023-11-11 12:06:10 +01:00
109247019824
6c4352eaf9 Translated using Weblate (Bulgarian)
Currently translated at 32.5% (436 of 1340 strings)
2023-11-11 12:06:10 +01:00
Spurnita
2f279d2403 Translated using Weblate (Catalan)
Currently translated at 18.6% (250 of 1340 strings)
2023-11-11 12:06:10 +01:00
chocomint
842b2bbd36 Translated using Weblate (Spanish)
Currently translated at 90.8% (1218 of 1340 strings)
2023-11-11 12:06:10 +01:00
BreadW
d056bb3ee7 Translated using Weblate (Japanese)
Currently translated at 94.4% (1265 of 1340 strings)
2023-11-11 12:06:10 +01:00
waxtatect
adf9a3953b Translated using Weblate (French)
Currently translated at 100.0% (1340 of 1340 strings)
2023-11-11 12:06:10 +01:00
Ярослав Рукавицын
c7dd8c18ed Translated using Weblate (Russian)
Currently translated at 94.1% (1262 of 1340 strings)
2023-11-11 12:06:10 +01:00
Lemente
d8c8bf1897 Translated using Weblate (French)
Currently translated at 96.9% (1299 of 1340 strings)
2023-11-11 12:06:10 +01:00
waxtatect
b0c92e885e Translated using Weblate (French)
Currently translated at 96.9% (1299 of 1340 strings)
2023-11-11 12:06:10 +01:00
ROllerozxa
80ae408eb9 Translated using Weblate (Swedish)
Currently translated at 65.5% (879 of 1340 strings)
2023-11-11 12:06:10 +01:00
Yaya - Nurul Azeera Hidayah @ Muhammad Nur Hidayat Yasuyoshi
9720eb50b3 Translated using Weblate (Malay)
Currently translated at 100.0% (1340 of 1340 strings)
2023-11-11 12:06:10 +01:00
Bas Huis
1efa3a165e Translated using Weblate (Dutch)
Currently translated at 83.9% (1125 of 1340 strings)
2023-11-11 12:06:10 +01:00
ROllerozxa
b730c0aa9a Translated using Weblate (Norwegian Bokmål)
Currently translated at 52.4% (703 of 1340 strings)
2023-11-11 12:06:10 +01:00
Muhammad Rifqi Priyo Susanto
bc26bdc2bf Translated using Weblate (Indonesian)
Currently translated at 100.0% (1340 of 1340 strings)
2023-11-11 12:06:09 +01:00
Translator
3187aca3c9 Translated using Weblate (French)
Currently translated at 94.4% (1265 of 1340 strings)
2023-11-11 12:06:09 +01:00
Janar Leas
c4b7876a1a Translated using Weblate (Estonian)
Currently translated at 44.7% (600 of 1340 strings)
2023-11-11 12:06:09 +01:00
Wuzzy
904dbe730d Translated using Weblate (German)
Currently translated at 100.0% (1340 of 1340 strings)
2023-11-11 12:06:09 +01:00
Gregor Parzefall
8bf2031310 Get rid of hidden settings in settings_translation_file.cpp 2023-11-11 11:59:38 +01:00
Wuzzy
af474d10a4 Fix bad translation function names in builtin (#13977) 2023-11-10 07:00:17 +07:00
MisterE123
fe8d04d0b3 Fix misrendered fall_damage_add_percent calculation formula (#13969)
Co-authored-by: rubenwardy <rw@rubenwardy.com>
2023-11-09 19:55:26 +01:00
Gregor Parzefall
394450758e Fix auto_install_spec being used as a table (#13970)
(It's a string since #13906.)
2023-11-09 19:54:47 +01:00
JosiahWI
56902745c8 Extract updateClouds method from updateFrame (#13939)
Co-authored-by: Gregor Parzefall <82708541+grorp@users.noreply.github.com>
2023-11-08 07:00:59 +07:00
corpserot
9e952603b2 Lump MT_LOGCOLOR env together with other color env (#13887) 2023-11-08 07:00:36 +07:00
Thresher
80c4c260ae Refactor and move world_format.txt to world_format.md (#13504)
Co-authored-by: Muhammad Rifqi Priyo Susanto <muhammadrifqipriyosusanto@gmail.com>
2023-11-08 07:00:04 +07:00
ROllerozxa
570fc90bf6 Debundle Minetest Game (#13818) 2023-11-07 22:18:26 +01:00
Muhammad Rifqi Priyo Susanto
7213ff7a00 Resolves some warnings for Android version (#13862) 2023-11-05 19:02:01 +01:00
Gregor Parzefall
adec16790b Offer ContentDB updates for leftover bundled Minetest Game (#13906) 2023-11-05 19:01:19 +01:00
Zughy
726326924d Clarify get_translated_string string argument (#13948)
Co-authored-by: sfan5 <sfan5@live.de>
Co-authored-by: Muhammad Rifqi Priyo Susanto <muhammadrifqipriyosusanto@gmail.com>
Co-authored-by: rubenwardy <rw@rubenwardy.com>
2023-11-05 19:00:32 +01:00
Muhammad Rifqi Priyo Susanto
4d2227cfa5 Rename mtt_update to mod_translation_updater (#13952)
Clarifies the purpose of the translation update script by giving it a more explanatory name.
2023-11-05 09:11:30 +01:00
Nils Dagsson Moskopp
2025dcffbd Revert "Don't trigger a key event if a key with the same associated char was pressed (#13773)"
This partially reverts commit d57c936b08.

The reverted commit prevented recognition of key combinations.
It correctly changed a test case to no longer use “KEY_NUMPAD_5”.

Several keyboard layouts use a key combination to input a “+” (e.g. Neo2);
therefore some users could no longer input “+” to increase the view range.

Co-authored-by: savilli <78875209+savilli@users.noreply.github.com>
2023-10-30 21:23:59 +01:00
Desour
ec7a1f02e7 Fix out-of-bounds access in NodeDefManager::nodeboxConnects 2023-10-30 21:23:47 +01:00
Desour
1d31533601 Reformat rot array in NodeDefManager::nodeboxConnects, to make it less magic 2023-10-30 21:23:47 +01:00
Desour
64104585c5 Devtest: Add more connected nodebox test nodes 2023-10-30 21:23:47 +01:00
Gregor Parzefall
96197025b9 Fix hypertext[] sometimes calculating incorrect scrollbar height (#13943) 2023-10-29 17:54:31 +01:00
Muhammad Rifqi Priyo Susanto
1363059416 Fix issues in Minetest's English texts (#13913)
Co-authored-by: Gregor Parzefall <82708541+grorp@users.noreply.github.com>
Co-authored-by: rubenwardy <rw@rubenwardy.com>
Co-authored-by: Desour <ds.desour@proton.me>
Co-authored-by: sfan5 <sfan5@live.de>
2023-10-29 12:24:39 +01:00
Desour
b3988d964a Sounds: Do not fade paused sounds 2023-10-29 00:40:07 +02:00
Desour
2ad17136dc Sounds: Fix dtime being in milliseconds 2023-10-29 00:40:07 +02:00
Desour
b2aa5d9261 Sounds: Don't pause new sounds when paused 2023-10-29 00:39:38 +02:00
rubenwardy
4ee32c5441 Add package update detection on Content tab (#13807) 2023-10-28 17:33:44 +01:00
sfan5
ddce858c34 Speed up macOS CI
- skip nonsense during package installation
- use actual number of available cores
2023-10-27 20:22:40 +02:00
sfan5
00be802c5c Use macos-latest for CI
Old versions lose support relatively quickly and then silently degrade
to e.g. compiling all dependencies from source which takes a long time.
2023-10-27 20:22:40 +02:00
sfan5
8d2e1289a4 Use newer IrrlichtMt 2023-10-27 19:00:04 +02:00
Desour
454eb3901d Inventory: Fix deleted inventory being used for regaining locked lists 2023-10-27 18:47:07 +02:00
Desour
a464b41d99 Inventory: Release resizes-locked lists on all on_-callbacks 2023-10-27 18:47:07 +02:00
ROllerozxa
1a562ca144 Prevent Windows Defender warnings in singleplayer (Bind singleplayer server to 127.0.0.1) 2023-10-27 12:03:43 +02:00
sfan5
03ba9370b9 Deprecate .bmp format 2023-10-27 11:05:27 +02:00
Nils Dagsson Moskopp
2f16227302 Set color of scrollbar/dropdown button symbols and checkmarks to white
Before this patch, the symbols were rendered black on dark background.

Previous images were edited like this:

1. The colors were inverted with GIMP's “linear inversion” method.
2. Image files were optimized using “optipng -o7 -zm1-9 -strip all”.

Co-authored-by: ROllerozxa <rollerozxa@voxelmanip.se>
Co-authored-by: rubenwardy <rw@rubenwardy.com>
2023-10-27 11:05:00 +02:00
sfan5
15c3fb7b7a Amend list of planned breakages 2023-10-24 18:17:18 +02:00
Gregor Parzefall
2ce14ce4eb Use hypertext[] for credits so that long lines are wrapped (#13914) 2023-10-22 15:32:14 +02:00
SmallJoker
906417cc0d GUI: Autofocus newly opened GUIModalMenu instances (#13911)
This in particular fixes incorrect event propagation to menus that
are no longer shown, such as the key change menu when opened within
the settings tab.
2023-10-22 15:31:42 +02:00
SmallJoker
2fbf5f4250 CSM: Fix duplicate player names (#13910) 2023-10-22 15:31:29 +02:00
Alexander Chibrikin
3491509b21 Add Russian translation of builtin (#13896)
Co-authored-by: Zemtzov7 <72821250+zmv7@users.noreply.github.com>
2023-10-22 15:31:11 +02:00
DS
7e8831a414 Inventory: Don't throw resize lock exception in destructor (#13894)
... of nodemeta inventories.
2023-10-22 15:30:11 +02:00
Cora de la Mouche
341e53f2e2 Remove deprecation mark on TGA texture format (#13877) 2023-10-22 15:29:28 +02:00
Muhammad Rifqi Priyo Susanto
c9655e54ce Change some keys to be triggered once every key press (#13883)
Those keys are below:
- KeyType::CAMERA_MODE
- KeyType::SCREENSHOT
- KeyType::TOGGLE_BLOCK_BOUNDS
- KeyType::TOGGLE_HUD
- KeyType::MINIMAP
- KeyType::TOGGLE_CHAT
- KeyType::TOGGLE_FOG
- KeyType::TOGGLE_DEBUG
- KeyType::TOGGLE_PROFILER
- KeyType::RANGESELECT


Co-authored-by: Gregor Parzefall <82708541+grorp@users.noreply.github.com>
2023-10-22 02:00:08 +07:00
updatepo.sh
8a9855241c Update translation files 2023-10-20 23:14:25 +02:00
updatepo.sh
72fc564758 Update example conf and settings translations 2023-10-20 23:12:43 +02:00
BRN Systems
81fee2207e Translated using Weblate (Slovak)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:05 +02:00
gallegonovato
425db09ede Translated using Weblate (Spanish)
Currently translated at 92.1% (1248 of 1355 strings)
2023-10-20 22:54:05 +02:00
Gábriel
0f2b196b32 Translated using Weblate (Hungarian)
Currently translated at 98.2% (1331 of 1355 strings)
2023-10-20 22:54:05 +02:00
watilin
bb7c0ceea0 Translated using Weblate (French)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:05 +02:00
Jorge Batista Ramos Junior
24c2ef2996 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.0% (1342 of 1355 strings)
2023-10-20 22:54:04 +02:00
Filippo Alfieri
f7775640d5 Translated using Weblate (Italian)
Currently translated at 99.5% (1349 of 1355 strings)
2023-10-20 22:54:04 +02:00
Christian Elbrianno
3127dd902a Added translation using Weblate (Javanese) 2023-10-20 22:54:04 +02:00
Wuzzy
6445fbaadc Translated using Weblate (German)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Tirifto
4a4861c26f Translated using Weblate (Esperanto)
Currently translated at 85.9% (1164 of 1355 strings)
2023-10-20 22:54:04 +02:00
Farooq Karimi Zadeh
332f1af325 Translated using Weblate (Persian)
Currently translated at 0.1% (1 of 1355 strings)
2023-10-20 22:54:04 +02:00
José Douglas
520cfaf13e Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.9% (1327 of 1355 strings)
2023-10-20 22:54:04 +02:00
Farooq Karimi Zadeh
7b14b867f5 Added translation using Weblate (Persian) 2023-10-20 22:54:04 +02:00
Marco Ciampa
8ab517d242 Translated using Weblate (Esperanto)
Currently translated at 85.2% (1155 of 1355 strings)
2023-10-20 22:54:04 +02:00
Claybiokiller
c0f0770f65 Translated using Weblate (Chinese (Simplified))
Currently translated at 91.0% (1234 of 1355 strings)
2023-10-20 22:54:04 +02:00
Linerly
28e06f7d9c Translated using Weblate (Indonesian)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Nanashi Mumei
77f2c94395 Translated using Weblate (Russian)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Emmily
17e0ec27eb Translated using Weblate (Esperanto)
Currently translated at 84.7% (1149 of 1355 strings)
2023-10-20 22:54:04 +02:00
yue weikai
d62abbc938 Translated using Weblate (Chinese (Simplified))
Currently translated at 90.4% (1226 of 1355 strings)
2023-10-20 22:54:04 +02:00
Eoghan Murray
00b7208b5a Translated using Weblate (Irish)
Currently translated at 1.7% (24 of 1355 strings)
2023-10-20 22:54:04 +02:00
Eoghan Murray
92248e8018 Translated using Weblate (Gaelic)
Currently translated at 11.1% (151 of 1355 strings)
2023-10-20 22:54:04 +02:00
Yic95
78aad07be9 Translated using Weblate (Chinese (Traditional))
Currently translated at 70.9% (961 of 1355 strings)
2023-10-20 22:54:04 +02:00
Eoghan Murray
50cdf0e9bf Added translation using Weblate (Irish) 2023-10-20 22:54:04 +02:00
Muhammad Rifqi Priyo Susanto
a644e8c70a Translated using Weblate (Indonesian)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Hugo Carvalho
2e96f99e9c Translated using Weblate (Portuguese)
Currently translated at 98.8% (1339 of 1355 strings)
2023-10-20 22:54:04 +02:00
Milan Šalka
57cc054bb3 Translated using Weblate (Slovak)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Hugo Rosa
8df315378d Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.9% (1327 of 1355 strings)
2023-10-20 22:54:04 +02:00
Jynweythek Vordhosbn
bcfd1fcdba Translated using Weblate (Spanish)
Currently translated at 92.1% (1248 of 1355 strings)
2023-10-20 22:54:04 +02:00
Joaquín Villalba
6f93853e65 Translated using Weblate (Spanish)
Currently translated at 92.1% (1248 of 1355 strings)
2023-10-20 22:54:04 +02:00
joserene-007
c8b98d1eeb Translated using Weblate (Spanish)
Currently translated at 92.1% (1248 of 1355 strings)
2023-10-20 22:54:04 +02:00
Skrripy
356ee9d2a9 Translated using Weblate (Ukrainian)
Currently translated at 55.2% (749 of 1355 strings)
2023-10-20 22:54:04 +02:00
Ács Zoltán
db5a15e14c Translated using Weblate (Hungarian)
Currently translated at 97.9% (1327 of 1355 strings)
2023-10-20 22:54:04 +02:00
Salif Mehmed
e2ab89d253 Translated using Weblate (Bulgarian)
Currently translated at 34.2% (464 of 1355 strings)
2023-10-20 22:54:04 +02:00
Jakub Z
85884c15e7 Translated using Weblate (Polish)
Currently translated at 87.3% (1183 of 1355 strings)
2023-10-20 22:54:04 +02:00
Dominik Gęgotek
fc5ff8d8c7 Translated using Weblate (Polish)
Currently translated at 87.3% (1183 of 1355 strings)
2023-10-20 22:54:04 +02:00
Janar Leas
34e566f726 Translated using Weblate (Estonian)
Currently translated at 46.8% (635 of 1355 strings)
2023-10-20 22:54:04 +02:00
MikeL
a18be49827 Translated using Weblate (Maori)
Currently translated at 0.8% (11 of 1355 strings)
2023-10-20 22:54:04 +02:00
MikeL
2871a9fee8 Added translation using Weblate (Maori) 2023-10-20 22:54:04 +02:00
ROllerozxa
2817b9d84b Translated using Weblate (Swedish)
Currently translated at 66.6% (903 of 1355 strings)
2023-10-20 22:54:04 +02:00
Timur Seber
4cc05906bd Translated using Weblate (Tatar)
Currently translated at 0.9% (13 of 1355 strings)
2023-10-20 22:54:04 +02:00
facilitas
d04c1b5d73 Added translation using Weblate (Interlingua) 2023-10-20 22:54:04 +02:00
Артём Котлубай
2a518d8661 Translated using Weblate (Russian)
Currently translated at 99.3% (1346 of 1355 strings)
2023-10-20 22:54:04 +02:00
Application-maker
9b71b2f5d9 Translated using Weblate (Russian)
Currently translated at 99.3% (1346 of 1355 strings)
2023-10-20 22:54:04 +02:00
Robinson
261bf52440 Translated using Weblate (Czech)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Pexauteau Santander
9b76946540 Translated using Weblate (Czech)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Martin Šimek
9c0b546942 Translated using Weblate (Czech)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Roland Meier
ac3bb40692 Translated using Weblate (German)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Vít Skalický
54a39e3c4e Translated using Weblate (Czech)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Martin Šimek
def9db9d16 Translated using Weblate (Czech)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Nicolae Crefelean
ed1c6b432c Translated using Weblate (Romanian)
Currently translated at 53.5% (725 of 1355 strings)
2023-10-20 22:54:04 +02:00
Yaya - Nurul Azeera Hidayah @ Muhammad Nur Hidayat Yasuyoshi
dc88e6f927 Translated using Weblate (Malay (Jawi))
Currently translated at 59.0% (800 of 1355 strings)
2023-10-20 22:54:04 +02:00
Yaya - Nurul Azeera Hidayah @ Muhammad Nur Hidayat Yasuyoshi
ce53230ab2 Translated using Weblate (Malay)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
José Muñoz
cd17caab7e Translated using Weblate (Spanish)
Currently translated at 89.6% (1215 of 1355 strings)
2023-10-20 22:54:04 +02:00
nyommer
d5bf34271f Translated using Weblate (Hungarian)
Currently translated at 97.6% (1323 of 1355 strings)
2023-10-20 22:54:04 +02:00
Sharpik
941896ef28 Translated using Weblate (Czech)
Currently translated at 68.2% (925 of 1355 strings)
2023-10-20 22:54:04 +02:00
Furkan Baytekin
f362ed0880 Translated using Weblate (Turkish)
Currently translated at 89.0% (1207 of 1355 strings)
2023-10-20 22:54:04 +02:00
Sava Kujundžić
be1c441157 Translated using Weblate (Serbian (latin))
Currently translated at 7.4% (101 of 1355 strings)
2023-10-20 22:54:04 +02:00
Pexauteau Santander
8c3b8b7b4c Translated using Weblate (Slovak)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:04 +02:00
Mimi Kush
be1e781399 Translated using Weblate (Spanish)
Currently translated at 89.6% (1215 of 1355 strings)
2023-10-20 22:54:04 +02:00
Šimon Brandner
b10fe4ddd6 Translated using Weblate (Czech)
Currently translated at 68.1% (924 of 1355 strings)
2023-10-20 22:54:04 +02:00
José Muñoz
d54d4b4618 Translated using Weblate (Spanish)
Currently translated at 88.5% (1200 of 1355 strings)
2023-10-20 22:54:04 +02:00
jolesh
09104e17a0 Translated using Weblate (Esperanto)
Currently translated at 84.3% (1143 of 1355 strings)
2023-10-20 22:54:04 +02:00
Walter Bulbazor
7a5247cc33 Translated using Weblate (Occitan)
Currently translated at 24.3% (330 of 1355 strings)
2023-10-20 22:54:04 +02:00
Tor Egil Hoftun Kvæstad
475809ed40 Translated using Weblate (Norwegian Nynorsk)
Currently translated at 43.2% (586 of 1355 strings)
2023-10-20 22:54:04 +02:00
Артём Котлубай
2f9742c64f Translated using Weblate (Russian)
Currently translated at 99.1% (1344 of 1355 strings)
2023-10-20 22:54:03 +02:00
Tsaqib Fadhlurrahman Soka
85c9c27e42 Translated using Weblate (Indonesian)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:03 +02:00
Marian
8c9a4d9a05 Translated using Weblate (Slovak)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:03 +02:00
Ács Zoltán
1b2396ee9e Translated using Weblate (Hungarian)
Currently translated at 97.0% (1315 of 1355 strings)
2023-10-20 22:54:03 +02:00
Alexandros Koutroulis
dd587aa30d Translated using Weblate (Greek)
Currently translated at 27.8% (377 of 1355 strings)
2023-10-20 22:54:03 +02:00
waxtatect
9ccc0bd27e Translated using Weblate (French)
Currently translated at 100.0% (1355 of 1355 strings)
2023-10-20 22:54:03 +02:00
Gregor Parzefall
b1dec37adb Clean up and improve mainmenu theme / game theme code (#13885) 2023-10-18 20:18:50 +02:00
JosiahWI
62eb6cfed0 Extract updatePauseState from Game::run (#13893) 2023-10-18 20:17:30 +02:00
DS
6026003508 Warn only once about positional stereo sounds (#13895) 2023-10-18 20:16:45 +02:00
Gregor Parzefall
6fdc7e0dad Make hypertext[] respect font size settings (#13858) 2023-10-16 20:47:16 +02:00
DS
3c41195986 Inventory: Fix picking up items via drop and pickup doubleclick (#13891) 2023-10-16 20:46:57 +02:00
Desour
5e0f14266d Fix forgotten CLANG_MINIMUM_VERSION update 2023-10-14 13:23:17 +02:00
DS
12e98678f6 Particle cleanup (#13394) 2023-10-11 17:07:30 +02:00
Thresher
352a403bd0 Optimize PNG files (#13509) 2023-10-09 17:13:44 +02:00
Muhammad Rifqi Priyo Susanto
7e678b5686 Prevent early respawns caused by up/down button in the death screen (#13870) 2023-10-09 17:13:33 +02:00
sfan5
b270c2bd68 Don't print ASCII art when using ncurses 2023-10-09 17:13:18 +02:00
DS
11ec75c2ad ActiveObjectMgr fixes (#13560) 2023-10-09 17:13:04 +02:00
Loïc Blot
929a13a9a0 build: Allow disabling documentation build + print more build flags (#13871)
* build: permit to disable documentation build

* build: add a message about some BUILD_* flags
2023-10-09 15:35:12 +02:00
Wuzzy
2c74797d34 Add script to update/generate mod translations (#13739) 2023-10-08 16:47:11 +01:00
Gregor Parzefall
d05da513be Notify users to reinstall MTG if worlds exist (#13850) 2023-10-08 16:47:00 +01:00
Gregor Parzefall
26bb397852 Add advanced settings checkbox and hide advanced settings by default (#13861)
Co-authored-by: rubenwardy <rw@rubenwardy.com>
2023-10-07 21:34:59 +02:00
sfan5
01d26c0e0e Warn when ignoring bind_address 2023-10-05 17:29:49 +02:00
sfan5
e02bf9fb1a Log timeout when a httpfetch times out 2023-10-05 17:29:49 +02:00
sfan5
9ec40ce8e9 Enforce minimum for curl(_file_download)_timeout 2023-10-05 17:29:49 +02:00
rvenson
ac8a9f9502 Update range values of meta set functions in the documentation 2023-10-05 17:29:26 +02:00
Muhammad Rifqi Priyo Susanto
c60d971bc4 Move unsupported language list into a separate file (#13865) 2023-10-05 17:29:02 +02:00
DS
8db4381304 MapblockMeshGenerator: Use more verbose member names (#13244) 2023-10-04 00:28:43 +02:00
corpserot
5a5697273b lua_api_deploy: fix code blocks parsing (#13847) 2023-10-03 20:34:24 +02:00
sfan5
de0036f4c1 Document air_equivalent as deprecated 2023-10-02 13:44:12 +02:00
Gregor Parzefall
33cc29bbda Allow setting custom third person front view camera offset (#13686)
Co-authored-by: Muhammad Rifqi Priyo Susanto <muhammadrifqipriyosusanto@gmail.com>
Co-authored-by: SmallJoker <SmallJoker@users.noreply.github.com>
2023-10-02 13:44:03 +02:00
Caleb Butler
3a4bf14c20 Replace all core::unicode::ustring with std::u32string (#13775) 2023-10-02 13:43:38 +02:00
Gregor Parzefall
56965bc814 Android: Add field_enter_after_edit[] formspec element (#13836) 2023-10-01 11:20:50 +02:00
Gregor Parzefall
94eba15c34 Misc. mainmenu fixes (#13859)
* settingstypes.txt: Fix wrong default value for profiler.report_path

* Disable Irrlicht file picker on Android
  (It doesn't work.)

* Join Game tab: Fix server description textarea being misaligned with background

* Reduce distance between tab and gamebar on Android
  Allows using a higher gui_scaling value without the gamebar going off-screen.

Co-authored-by: ROllerozxa <rollerozxa@voxelmanip.se>
2023-10-01 11:19:52 +02:00
Desour
c90c545d33 Put the internal sound definitions into a new sound namespace 2023-09-30 18:54:26 +02:00
Desour
bbc64a2eb5 Split sound_openal_internal into serval files 2023-09-30 18:54:26 +02:00
Desour
606215fae9 Move sound_openal and sound_openal_internal into new src/client/sound directory 2023-09-30 18:54:26 +02:00
Desour
8fa2ea71ef Move soundmanager into its own thread
Fixes sound queues running empty on client step hiccups.
2023-09-26 22:10:57 +02:00
Desour
591e45657f Bump minimum clang version to 7.0.1
std::variant is broken in clang < 7.0.1 with libstdc++
see: https://github.com/llvm/llvm-project/issues/32569
2023-09-26 22:10:57 +02:00
sfan5
b0d5cedeb6 Fix missing initialization for m_game_focused 2023-09-24 16:46:18 +02:00
sfan5
d113636a43 Fix UB in NetworkPacket class 2023-09-24 16:46:18 +02:00
sfan5
5109fa7eda Fix crash when processing empty mesh buffers 2023-09-24 16:46:18 +02:00
Gregor Parzefall
ff87be6e5f Remove unused "mNormal" uniform to fix crash on GLES2 with shaders 2023-09-24 16:46:05 +02:00
Gregor Parzefall
4cf900c779 Fix error when enabling texture packs (#13829) 2023-09-23 18:20:23 +02:00
ROllerozxa
c247761213 Escape package description in content tab 2023-09-22 21:25:58 +02:00
savilli
d57c936b08 Don't trigger a key event if a key with the same associated char was pressed (#13773) 2023-09-22 21:25:13 +02:00
David Leal
9f47e123d2 animaition -> animation (#13827)
Also changed `range` to `frame_range`,
2023-09-22 18:41:33 +02:00
sfan5
c3114132d3 Improve readability and infos in verbose log (#13828) 2023-09-22 18:41:10 +02:00
ROllerozxa
5949172735 Build MkDocs Lua API docs using GitHub CI, deploy to api.minetest.net (#13675)
* Build MkDocs Lua API documentation using GitHub CI and Pages instead

* Remove Lua highlight hack as codeblocks are correctly marked as Lua now

* fix line endings
2023-09-18 19:17:18 +03:00
x2048
e36b2226b9 Skip face culling in shadows for double-sided materials (e.g. plantlike) (#13500)
* Skip face culling in shadows for double-sided materials (e.g. plantlike)

* Keep previous face culling for transparent surfaces e.g. water
2023-09-17 21:42:14 +02:00
ROllerozxa
a88e61c2cf Improve UX when no game exists and drop default_game (#13550) 2023-09-17 18:45:28 +01:00
Gregor Parzefall
5bfc5d44c0 Two ContentDB GUI fixes (#13806) 2023-09-16 18:36:28 +02:00
Gregor Parzefall
4f735fba05 Settings GUI: Noise parameter setting fixes (#13797) 2023-09-16 18:35:35 +02:00
Wuzzy
8ebaf753d3 New physics overrides (#11465) 2023-09-15 20:10:08 +02:00
sfan5
2479d51cc6 Fix double-free of minimap textures 2023-09-13 15:27:07 +02:00
sfan5
033128d8dc Show better description to users when std::bad_alloc happens 2023-09-13 13:58:59 +02:00
SmallJoker
4ef93fe25f Allow place_param2 = 0 node placement predictions (#13787)
The placement prediction value 0 was accidentally ignored
and made the clients fall back to automatic rotation based
on the node paramtype2 value.

This now changes the internal representation to properly
indicate the disabled state (e.g. 'nil' in Lua).
2023-09-13 13:57:57 +02:00
Gregor Parzefall
833c324498 Make the crosshair DPI-aware (#13772) 2023-09-11 18:59:32 +02:00
rubenwardy
48ab1835da Replace settings tab with button 2023-09-09 18:49:33 +02:00
Zughy
798b9eae4a Add settings button icon 2023-09-09 18:49:33 +02:00
Desour
010d08f6a4 Fix -Wmissing-braces warnings in mapblock_mesh.cpp 2023-09-09 18:48:56 +02:00
Desour
7897450b27 Fix -Winconsistent-missing-override warnings 2023-09-09 18:48:56 +02:00
Desour
2ad4c9e0ce Fix -Wunused-but-set-variable warnings 2023-09-09 18:48:56 +02:00
Gregor Parzefall
95056f9783 Higher default graphics settings on Android (#13780) 2023-09-07 17:55:11 +02:00
Gregor Parzefall
1a568cc491 Fix that negative integer values for float settings don't get a ".0" suffix (#13779) 2023-09-05 15:36:05 +02:00
Gregor Parzefall
83b85ba16a Rewrite the gamebar (#13768) 2023-09-02 23:02:02 +02:00
chmodsayshello
294ad98776 Send ever lasting particle spawners to all players (#13774) 2023-09-02 22:58:11 +02:00
sfan5
f080aa29b5 Remove usage of obsolete HighPrecisionFPU field 2023-09-01 12:46:36 +02:00
Gregor Parzefall
4252f9d4d5 Restore the appearance of the "Start Game" tab after #13761 (#13769) 2023-08-30 14:45:44 +02:00
rubenwardy
0cbf96cc83 Use formspec version 6 in the main menu (#13761) 2023-08-28 22:36:54 +01:00
Gregor Parzefall
7b56daa236 Small setting-related fixes (#13755) 2023-08-27 20:18:41 +02:00
savilli
852d6a7976 Fix potential freeze in core.check_for_falling 2023-08-27 20:12:53 +02:00
SmallJoker
bf9f831cb2 Inventory: skip redundant stack movement
The list of dragged stacks includes the source stack, which
however does not need to be moved onto itself.
This is an optimization.
2023-08-27 20:12:10 +02:00
SmallJoker
0ba899e239 Inventory: Fix assertion caused by a no-op stack movement 2023-08-27 20:12:10 +02:00
Rising Leaf
660151572f Do not render objects that are invisble into the shadow map 2023-08-26 20:12:17 +02:00
1F616EMO~nya
54eacca287 Use issue templates for creating issues (#13222) 2023-08-25 22:00:05 +07:00
Desour
f47b00426a Revert "Get rid of guiroot"
This reverts commit 45e7a80057.
2023-08-24 22:14:44 +02:00
Desour
7e4dccb3b5 Revert "Get rid of global guienv variable"
This reverts commit 16da954bd7.
2023-08-24 22:14:44 +02:00
Desour
f98726c516 Revert "Use our GUIButton in touchscreengui"
This reverts commit f7f3aaf43c.
Fixes #13743.
2023-08-24 22:14:44 +02:00
Gregor Parzefall
aea9242a96 Allow nodes to have their post_effect_color affected by lighting (#13637)
Co-authored-by: DS <ds.desour@proton.me>
2023-08-24 20:16:36 +02:00
Gregor Parzefall
92b6ff4721 TouchScreenGUI: Fix only 9 hotbar slots being usable (#13698)
Co-authored-by: Muhammad Rifqi Priyo Susanto <muhammadrifqipriyosusanto@gmail.com>
2023-08-24 17:45:51 +02:00
Gregor Parzefall
72ef90885d Clean up texture filtering settings (#13683) 2023-08-24 10:50:47 +02:00
gamefreq0
d0ee63c766 Enable shift-click crafting (#13729) 2023-08-24 12:00:54 +07:00
fluxionary
587e2b2526 Set item description as infotext for item entities (#13728) 2023-08-24 12:00:18 +07:00
rubenwardy
a65cdbe66e Settings GUI: Use language names rather than codes (#13752) 2023-08-24 00:33:23 +01:00
Montandalar
7b3ed32003 Persist text inputs in mainmenu local tab
Co-authored-by: archfan <33993466+archfan7411@users.noreply.github.com>
2023-08-14 18:17:53 +02:00
sfan5
2c987b66c1 Move implementations of some LuaVoxelManip functions to l_mapgen 2023-08-14 18:16:36 +02:00
sfan5
e48f15c135 Skip liquid updates in MapgenSinglenode if not applicable 2023-08-14 18:16:36 +02:00
sfan5
bf36a90579 Optimize Mapgen::updateLiquid()
-55% runtime in singlenode usage, which is the best case
2023-08-14 18:16:36 +02:00
sfan5
43c9c38a28 Fix itemdef defaults not being applied in async env 2023-08-14 18:16:36 +02:00
sfan5
f6bddc4e8d Fix registered_craftitems not populated in async env 2023-08-14 18:16:36 +02:00
sfan5
f9c881eb5a Add two missing classes to async environment 2023-08-14 18:16:36 +02:00
Desour
16da954bd7 Get rid of global guienv variable
(It can already be accessed via the renderingengine.)
2023-08-14 18:13:47 +02:00
Desour
45e7a80057 Get rid of guiroot
The guienvironment already provides a root gui element, we don't need to add another one.
(For CGUIEnvironment, the env itself is the root element.)
2023-08-14 18:13:47 +02:00
Desour
7e7aceb8c1 Replace all actual uses of irrlicht CGUIStaticText with our StaticText 2023-08-14 18:13:47 +02:00
Desour
d75c956dbc Remove ugly hack in static_text.h
Just use the root element, like GUIButton:add().
2023-08-14 18:13:47 +02:00
Desour
f7f3aaf43c Use our GUIButton in touchscreengui 2023-08-14 18:13:47 +02:00
Desour
91c0439922 Use our GUIButton in our GUIScrollBar
Note that GUIScrollBar needs an ISimpleTextureSource now due to button styling.
2023-08-14 18:13:47 +02:00
Desour
9d62abbe46 Replace any uses of CGUIScrollBar and IGUIScrollBar with GUIScrollBar 2023-08-14 18:13:47 +02:00
Desour
124d064015 GUIButton: Default BgColor to white, as opposed to unintialized
(Same as what CGUIButton uses (via colors=0).)
2023-08-14 18:13:47 +02:00
Desour
2903f692ba GUIButton: Use default member initializers 2023-08-14 18:13:47 +02:00
Desour
7f9de5db0b Make touchscreengui compile 2023-08-14 18:13:47 +02:00
jordan4ibanez
14441a289e Document openSUSE Required Packages 2023-08-14 18:13:36 +02:00
rubenwardy
137e4ce866 Fix hypertext in the mainmenu (#13731) 2023-08-13 13:28:33 +01:00
Gregor Parzefall
526c5f2348 ContentDB GUI: Load package list asynchronously (#13551) 2023-08-13 13:28:24 +01:00
ROllerozxa
e4bedc7ea8 Make content tab use real coordinates and minor cleanups (#13719) 2023-08-13 13:28:16 +01:00
rubenwardy
c6a0ead72d Add warning for initial properties directly inside definition (#9650) 2023-08-13 00:19:03 +01:00
Zughy
98f097dc2f Warn about unsupported file extensions for media 2023-08-06 14:16:00 +02:00
ROllerozxa
c816aa5374 Settings GUI: Fix path settings on Windows 2023-08-06 14:15:49 +02:00
Zughy
4d9a67682d DOCS: state that get_wielded_item returns a copy of the item 2023-08-06 14:15:34 +02:00
rubenwardy
d16d1a1341 Settings GUI: Add setting dependencies (#13704) 2023-08-05 17:55:27 +01:00
rubenwardy
752ce1a1b2 Settings GUI: Move shadow presets to Shaders, remove Most Used (#13713) 2023-08-05 17:33:18 +01:00
JosiahWI
28fce8aad5 Add dev stage to docker image (#13573) 2023-07-30 15:29:25 +01:00
Nikita K
e0948f42ab Add Void Linux specifics to build documentation (#13693) 2023-07-30 14:55:06 +01:00
Joachim Stolberg
21ecdd5681 Fix textarea scrollbar inside border=false (#13678) 2023-07-30 14:54:52 +01:00
Wuzzy
20e9969313 Improve object documentation in lua_api.md (#13239)
Co-authored-by: DS <ds.desour@proton.me>
2023-07-30 14:54:01 +01:00
OgelGames
3f2a10bb4b Fix decode_base64 returning nothing instead of nil (#13697) 2023-07-30 14:53:47 +01:00
doxygen-spammer
9f25378ddd Add performance test nodes, using complex meshes. (#13161) 2023-07-30 14:53:08 +01:00
Gregor Parzefall
cc8280426f Minor additions to the VoxelManip docs 2023-07-28 00:40:01 +02:00
Stvk imension
ba6de431a2 Android: Remove Migration Code (#13590)
Co-authored-by: Muhammad Rifqi Priyo Susanto <muhammadrifqipriyosusanto@gmail.com>
2023-07-27 14:09:17 +02:00
Gregor Parzefall
c14e4d1795 Increase the resolution of the logo shown on the about tab 2023-07-22 17:20:12 +02:00
Desour
e0192e256f Fix incorrect rounding in GUIInventoryList::getItemIndexAtPos 2023-07-22 17:19:57 +02:00
ndren
53c594abe0 Introduce and start using microsecond sleep on Linux (#13445) 2023-07-22 17:19:49 +02:00
sfan5
72ed8514c5 Use newer IrrlichtMt 2023-07-20 22:15:47 +02:00
Gregor Parzefall
6f0d36c41a Fixes and improvements 2023-07-20 22:15:47 +02:00
Gregor Parzefall
7473e4cafd Expose all OpenGL filtering modes, use OpenGL names for them
Because of a review comment on the Irrlicht PR by numberZero.
2023-07-20 22:15:47 +02:00
Gregor Parzefall
6bf63d4b41 Rename SMaterial::TextureLayer -> SMaterial::TextureLayers
It's not the "texture layer" of the material, but an array of texture layers.
2023-07-20 22:15:47 +02:00
Gregor Parzefall
05ebe2418b Rename E_MATERIAL_FLAG -> E_MATERIAL_PROP
The enum values don't reference material flags, but material properties.
2023-07-20 22:15:47 +02:00
Gregor Parzefall
9bef3c136a Split up texture filtering properties of SMaterialLayer into MinFilter and MagFilter
You can	now set	the filter used	when scaling textures down and the filter used when scaling textures up separately.
2023-07-20 22:15:47 +02:00
Gregor Parzefall
307e380f30 Refactor the way you set material properties
Instead of using SMaterial::setFlag, you now set them directly on SMaterial or SMaterialLayer.
2023-07-20 22:15:47 +02:00
SmallJoker
128d22e6ee GUI: Automatic scaling of checkboxes and scrollbars (#13666)
Mainly helpful on high-DPI screens or when 'gui_scaling' is changed
2023-07-17 20:46:15 +02:00
Nekobit
50234b8e5c Fix string conversion for FreeBSD (#13648) 2023-07-17 20:46:06 +02:00
Gregor Parzefall
3552537fc4 Fix that transparent text still draws a text shadow (#13649)
Makes fade out animations of text more pleasant to look at.
2023-07-17 20:45:56 +02:00
DS
f41e9e3e0f Add Irrlicht device info to the mainmenu About tab (#13636) 2023-07-17 20:44:54 +02:00
archfan
9b310a6e6f Decrease sneak margin to combat phasing through thin walls (#13607)
A 1/16th-node-thick wall is 0.625 meters thick, and the previous margin of 0.1 meters meant that these walls could be phased through by sneaking against them. A margin lower than 0.625 prevents this.
2023-07-17 20:44:33 +02:00
Muhammad Rifqi Priyo Susanto
2061984313 Simplifies code by using Irrlicht's operator overloads
New variables are added to replace in-place calculations.
2023-07-14 21:00:29 +07:00
Muhammad Rifqi Priyo Susanto
3a47559e86 Fix some memory leaks and code style issues
Maximum line length is 95 characters.
Some members' name are changed.
Struct initialisations use brace syntax; eliminating the usage of the memset function.
Iterations use for-each-loop instead of while-loop+iterator.
char * -> std::string
button_info * -> std::shared_ptr<button_info>
2023-07-14 21:00:29 +07:00
Desour
8e09077de8 Fix sound manager not being stepped by GUIEngine 2023-07-14 14:42:00 +02:00
Gregor Parzefall
1837a11c22 Improve messages when changing viewing range and exceeding server-set limit (#13647) 2023-07-14 14:41:45 +02:00
sfan5
bf987bf58a Handle blit_back_with_light with empty area
fixes #13306
2023-07-13 20:42:39 +02:00
sfan5
4a14a18799 Fix mapgen_v6 crashing
this variable was accidentally shadowed in 20b10b569
2023-07-09 20:59:57 +02:00
lhofhansl
136a93f628 Reverse eye-offset Z-coordinate in 3rd person front view (#13369) 2023-07-08 12:00:15 +07:00
Gregor Parzefall
0218963f1b Fix max_formspec_size not taking gui_scaling into account (#13493) 2023-07-07 21:42:43 +02:00
SmallJoker
078bd95a49 Formspec: prevent infinite loop caused by negative background9[] size (#13624) 2023-07-07 21:42:10 +02:00
lhofhansl
869df17ddf Server enforcement for fog_distance (#13448) to block cheating (#13643)
This enforces the fog_distance (if set) at the server, so that a hacked client could not cheat and retrieve blocks beyond the set distance.
2023-07-06 09:36:46 -07:00
Gregor Parzefall
26453df2f7 Don't crash if a Lua error occurs inside get_staticdata 2023-07-03 20:34:02 +02:00
ROllerozxa
d71872af23 Fix texture paths for system-installed builds
* window icon
* custom touchscreen checkbox sprites
2023-07-03 20:31:03 +02:00
Lars Müller
25ef8f3934 Fix local animations not resetting
Converts `LocalPlayerAnimation` to a scoped enum to prevent such bugs in the future
2023-07-02 12:47:18 +02:00
Muhammad Rifqi Priyo Susanto
ff498fc206 Android: Reliably showing an IME for text input dialog (#13521)
This commit is inspired by this blog post: https://developer.squareup.com/blog/showing-the-android-keyboard-reliably/
2023-07-01 14:00:30 +07:00
lhofhansl
0ade097e99 Allow the server to control fog_distance and fog_start via the sky-api (#13448) 2023-06-30 19:11:17 -07:00
numzero
dde8f0e20a Replace a non-aligned cuboid with a cylinder in client::ActiveObjectMgr::getActiveSelectableObjects 2023-06-29 18:58:10 +02:00
numzero
21035bf5d4 Add unit test on client::ActiveObjectMgr::getActiveSelectableObjects 2023-06-29 18:58:10 +02:00
numzero
d7291e0600 Update client::ActiveObjectMgr::getActiveSelectableObjects API 2023-06-29 18:58:10 +02:00
AFCMS
aaae9d5a77 Fix .clang-format file config values 2023-06-29 18:57:55 +02:00
x2048
c09a3a52ac Add antialiasing filters (FXAA, SSAA) (#13253) 2023-06-28 05:30:08 +02:00
sfan5
442d5fc75c Add unit tests for isBlockInSight() 2023-06-26 22:51:49 +02:00
numzero
3b74cc4a41 Replace PP with direct printing 2023-06-26 22:51:32 +02:00
numzero
de77fe8ade Allow printing irr::core::vector[23]d directly to an std::ostream 2023-06-26 22:51:32 +02:00
Vitaliy
2f6a9d12f1 Allow running individual unit tests 2023-06-25 11:13:48 +02:00
Vitaliy
aada2403c9 Try all known video drivers if the requested one fails to initialize 2023-06-25 11:13:23 +02:00
LoneWolfHT
35ad3dabab Fix MSVC github action 2023-06-24 20:38:31 +02:00
s20
4fb6754903 Adding gettext in the compilation dependency packages list 2023-06-24 20:38:11 +02:00
Gregor Parzefall
7e51e2dea6 Fix compiler error on MSVC with ENABLE_TOUCH=TRUE 2023-06-24 20:37:59 +02:00
sfan5
84fb663d6c Add VoxelArea::intersect() 2023-06-23 09:05:26 +02:00
sfan5
659828b142 Rename ModApiEnvMod and ModApiItemMod
The 'mod' could have meant module in the past but no other classes do this.
2023-06-23 09:05:26 +02:00
sfan5
610578e3e2 Use swapNode for set_node_level and add_node_level
While this is a behaviour change I don't think the old one made any sense.
It's possible that someone hit this before and wrote a workaround for it,
they won't be affected by this change.
It only makes things work that didn't before.
2023-06-23 09:05:26 +02:00
sfan5
62629939ff Genericize find_node_near and find_node_in implementations in C++ 2023-06-23 09:05:26 +02:00
sfan5
20b10b5691 Refactor EmergeParams owner 2023-06-23 09:05:26 +02:00
sfan5
32ff832108 Save Lua globals after mod loading
These are used for the async env currently and will be needed elsewhere soon.
2023-06-23 09:05:26 +02:00
sfan5
4fdd2dec59 Move core.run_callbacks and related to common folder 2023-06-23 09:05:26 +02:00
sfan5
524d446757 Minor script api fixes/cleanups 2023-06-23 09:05:26 +02:00
wsor4035
5b6bc8a12b Remove unsupported media formats from client.cpp 2023-06-22 17:52:48 +02:00
LoneWolfHT
6a328197a5 MSVC CI job: Compile with gettext and LuaJIT 2023-06-22 17:52:35 +02:00
Gregor Parzefall
03ffc2618c TouchScreenGUI: Add an exit / "ESC" button to the rare controls bar (#13574) 2023-06-22 17:50:36 +02:00
numzero
7c26cb1c35 Drop unused tile rotations 2023-06-22 17:50:20 +02:00
numzero
1102f92dac Use a enum for tile rotation 2023-06-22 17:50:20 +02:00
numzero
729671d6ae In getNodeTile, use a descriptive struct for the lookup table 2023-06-22 17:50:20 +02:00
numzero
d676520526 Optimize trigonometry out of MapblockMeshGenerator::drawCuboid 2023-06-22 17:50:20 +02:00
numzero
c29d897854 Optimize trigonometry out of MapblockMeshGenerator::drawLiquidTop 2023-06-22 17:50:09 +02:00
numzero
b8ddde0a96 Store liquid data as dimensionless fractions instead of BS multiplies 2023-06-22 17:50:09 +02:00
Vitaliy
43c9647fe5 Use absolute URL for the roadmap (#13617) 2023-06-21 16:00:04 +07:00
Desour
03dda13910 OpenALSoundManager: Fix a buffer overflow 2023-06-20 20:54:39 +02:00
AFCMS
531122ee86 Add .fleet folder to gitignore (#13611) 2023-06-20 22:00:15 +07:00
lhofhansl
8f25f487fe Instrument touchMapBlocks and block loading/deserialization. (#13314) 2023-06-19 16:59:08 -07:00
Vitaliy
f1feeb319c Cull liquid back face on liquid-glasslike interface (#13594) 2023-06-18 13:52:14 -07:00
DS
edcbfa31c9 Sound refactor and improvements (#12764) 2023-06-16 20:15:21 +02:00
Wuzzy
8e1af25738 DevTest: Add example nodes for disable_descend 2023-06-16 20:14:08 +02:00
Wuzzy
6b3deaa170 Add disable_descend to disable active node sinking 2023-06-16 20:14:08 +02:00
Muhammad Rifqi Priyo Susanto
a4e69d6843 TouchScreenGUI: Read coordinates directly for virtual joystick (#13567)
The movement's direction and speed are calculated directly from the button's relative screen coordinate. The previous method was to trigger the movement using a keyboard event.
The only virtual joystick status left is Aux1 button.

---------

Co-authored-by: Gregor Parzefall <gregor.parzefall@posteo.de>
2023-06-16 22:40:16 +07:00
Desour
c549e84abb Silence a -Wsign-compare warning for invlist indices 2023-06-15 13:55:20 +02:00
Desour
dade95e142 Fix curl deprecation warnings, and set minimum curl version to 7.56.0 2023-06-15 13:55:20 +02:00
Desour
f947e2afec Fix some gcc -Wself-move warnings 2023-06-15 13:55:20 +02:00
Desour
6a05d63993 Use [[noreturn]] 2023-06-15 10:38:44 +02:00
Desour
5e6d144567 Enable -Wimplicit-fallthrough and use [[fallthrough]] attribute 2023-06-15 10:38:44 +02:00
Desour
9c348d057e Replace the old STATIC_ASSERT macro with static_assert 2023-06-15 10:38:44 +02:00
Desour
8b108ed5f2 Use nicer syntax for nested namespace definitions 2023-06-15 10:38:44 +02:00
Desour
e700182f44 Replace Optional with std::optional 2023-06-15 10:38:44 +02:00
Desour
34ad551efc Use MutexAutoLock for Thread::m_start_finished_mutex 2023-06-15 10:38:44 +02:00
Desour
5d863d7e9c Bump C++ std to 17 2023-06-15 10:38:44 +02:00
Desour
28766d1879 Bump minimum gcc and clang versions 2023-06-15 10:38:44 +02:00
Pascal Abresch
ba80d1ce1f Implement check_offset for decorations 2023-06-15 10:36:46 +02:00
DS
c91182e1b3 Move the platform-dependent stuff in renderingengine.cpp to irrlicht (#13348) 2023-06-11 14:17:39 +02:00
DS
553dc02deb Fix some memleaks from GUIButtonImage (#13564)
* `m_foreground_image` was grabbed, but not dropped in the destructor.
* `m_image` was created with new. It is grabbed by itself and by the env (not only by the env!, so it's an owning ptr). This owning ptr also was never dropped.
2023-06-06 19:01:32 +02:00
Desour
1b51ff333a Use unique_ptr for ServerInventoryManager::DetachedInventory::inventory 2023-06-05 20:43:33 +02:00
Desour
1780d1bbde Use unique_ptrs for MapSector::m_blocks 2023-06-05 20:43:33 +02:00
Desour
08ea467bfe Use unique_ptr for g_httpfetch_thread 2023-06-05 20:43:33 +02:00
Desour
cfb1b879e0 Use unique_ptrs for CurlFetchThread::m_all_ongoing 2023-06-05 20:43:33 +02:00
Desour
d0bcdff5ce Use unique_ptrs for leveldb db and iterators 2023-06-05 20:43:33 +02:00
Zughy
8445c5fe60 Extend roadmap approval time from one week to one month 2023-06-05 12:02:59 +02:00
Gregor Parzefall
a1463263b5 Auto-detect locale on Android (#13561) 2023-06-05 12:02:10 +02:00
Gregor Parzefall
a857c46e6e Make the settings GUI more usable on Android (#13543) 2023-06-05 12:01:54 +02:00
Desour
d9f478cbfb Remove a misleading MutexAutoLock in l_to_table
The temporary is immediately destructed, so the mutex isn't locked
after the line.
Removed the lock, because the Settings member-functions used by
push_settings_table lock the mutex and are thread-safe, but would
cause a dead-lock.
2023-06-05 12:01:08 +02:00
OgelGames
252c79d53a Inventory mouse shortcut improvements (#13146)
Co-authored-by: Muhammad Rifqi Priyo Susanto <muhammadrifqipriyosusanto@gmail.com>
2023-06-05 12:00:32 +02:00
mazes-80
23f7aab354 Item Entity: prevent moveresult assert when attached (#13353) 2023-06-05 12:00:11 +02:00
Gregor Parzefall
e5a5d5a672 Fix various cases of double-escaped error messages 2023-06-05 11:59:37 +02:00
Riley Adams
29b7aea38b Cavegen y biome check (#13472) 2023-06-05 11:59:22 +02:00
sfan5
1ef9fc9d1f Bump used IrrlichtMt version 2023-06-04 20:36:46 +02:00
Muhammad Rifqi Priyo Susanto
7221de6ede Option to invert direction or disable mouse wheel for hotbar item selection
More changed callbacks for the settings are added in readSettings(). Those are also deregistered when the Game object is destroyed.
2023-05-31 12:40:00 +07:00
Treer
8cd1296049 Add additional texture modifiers (#10100)
* Adjust hue, saturation, and lightness
* Colorize using hue, saturation, and lightness
* Adjust contrast & brightness
* Hard light
* Overlay
* Screen
* Create texture of a given size and color
2023-05-29 20:17:39 +01:00
lhofhansl
a8ec6092e2 Load blocks and objects behind player when in third-persion front-view (#13431) 2023-05-29 10:26:42 -07:00
Gregor Parzefall
fc3d6c1dd9 Place nodes with single tap on Android (+ bugfix) (#13187)
Don't place nodes when closing button bars.
Update docs (also in-game).
Rename "Default controls" -> "Controls" in Android pause menu since players can't change them (normally), so calling them "default" doesn't make sense.
2023-05-29 12:30:30 +07:00
lhofhansl
6832bf044e Avoid jittering when player is attached (#12439)
* Avoid very jittering when player is attached.

Co-authored-by: sfan5 <sfan5@live.de>
Co-authored-by: Vitaliy <numzer0@yandex.ru>
2023-05-28 11:36:34 -07:00
ROllerozxa
394dd9ffa5 Fix settings dialog not resetting filter when closed (#13513) 2023-05-27 15:35:01 +01:00
sfan5
8cccd75e81 Android build via CMake (#13528)
* the thing

* the thing 2
2023-05-26 15:21:23 +02:00
Thresher
00c647e4cc Convert spaces to tabs (#13506)
* Convert spaces to tabs

* Desour reviews 1-3 fix

* Desour fixes

* Undo alignment changes
2023-05-26 15:13:57 +02:00
ROllerozxa
f4cb16cc2d Disable desynchronize_mapblock_texture_animation by default (#13514) 2023-05-26 13:48:37 +02:00
Zughy
d6eb6ff973 Reset player lighting when passing no arguments (#13525)
Co-authored-by: Zughy <4279489-marco_a@users.noreply.gitlab.com>
2023-05-26 13:47:16 +02:00
Zughy
b60d38b7f9 Reset day/night ratio even when passing no arguments (#13524)
* reset day_night_ratio when passing zero fields

* Update lua_api.md

---------

Co-authored-by: Zughy <4279489-marco_a@users.noreply.gitlab.com>
2023-05-26 13:45:42 +02:00
Thresher
180ec92ef9 Remove trailing whitespace (#13505) 2023-05-18 20:34:18 +02:00
SmallJoker
95a9f4ab7c Inventory: Allow InvRef:set_list with new_size >= old_size (#13497)
Fixes a regression introduced by enforced checks to work with
valid pointers within inventory actions.
2023-05-18 20:32:55 +02:00
Gregor Parzefall
f393214fef Settings menu improvements regarding default values (#13489)
The reset button now removes the setting from minetest.conf instead of setting it to its default value.
The reset button is now shown whenever a value is present in minetest.conf
Float settings now get a .0 suffix if they have no decimal places.
2023-05-18 20:32:26 +02:00
savilli
5ba70cf5ef Fix crash on handling wallmounted nodes with invalid param2 (#13487) 2023-05-18 20:31:04 +02:00
Zemtzov7
35112f2453 Disable vertical movement when both jump and sneak keys are pressed (#13426) 2023-05-18 20:30:21 +02:00
Gregor Parzefall
15fb4cab15 Fix Android segfault when game exits before TouchScreenGUI is initalized 2023-05-11 22:51:16 +02:00
sfan5
15445a0fbe Raise and clean up _WIN32_WINNT constant 2023-05-11 22:51:01 +02:00
Wuzzy
80574cdbe8 Fix rotation of 4dir in schematic placement (#13432) 2023-05-11 22:50:52 +02:00
Stvk imension
3de54039ae Document Android controls (#13061) 2023-05-11 22:50:38 +02:00
Buckaroo Banzai
65692ad1b5 Add min/max protocol version to minetest.get_version() (#13482) 2023-05-06 16:16:21 +01:00
rubenwardy
bc4fc6d648 Fix shadows dropdown and clean up shader settings (#13481) 2023-05-03 22:28:02 +01:00
rubenwardy
ad37df7f2e Fix crash when multiple mods with the same name provide settings 2023-05-01 21:39:12 +01:00
rubenwardy
d35672e78e Redesign/unify mainmenu settings interface 2023-05-01 17:11:41 +01:00
Zughy
a421a1d764 Add setting icons 2023-05-01 17:11:41 +01:00
DS
bec9c68bf3 Release invlist resizelock while doing the recursive callback in move_somewhere mode (#13470)
Fixes a crash in popular creative inventory mods that set the list when you put
something into trash.
2023-04-30 18:20:48 +02:00
lhofhansl
b35aa10579 Guarantee ActiveObjectMgr::m_active_object is not modified while iterating (#13468)
Currently if a mod creates new active objects in on_deactivate the server could crash.
2023-04-28 11:17:48 -07:00
Desour
7f6b09dce8 Use json forward-declarations 2023-04-27 18:50:33 +02:00
Desour
8b73743baa Reduce number of recursively included headers
This should improve compilation speed.

Things changed:
* Prefer forward-declarations in headers.
* Move header-includes out of headers if possible.
* Move some functions definitions out of headers.
* Put some member variables into unique_ptrs (see Client).
2023-04-27 18:50:33 +02:00
Desour
e9e8eed360 GUIChatConsole: Use primary selection 2023-04-27 18:50:17 +02:00
Desour
062b4d036a GUIEditBox: Use primary selection 2023-04-27 18:50:17 +02:00
AFCMS
d197ff0f9d Use Lua code blocks in lua_api.md 2023-04-26 20:09:08 +02:00
rubenwardy
9c90358912 Split compilation instructions from README.md (#13457) 2023-04-25 21:02:02 +01:00
SmallJoker
0fb6dbab36 InventoryManager: Disallow resizing or deleting inventory lists that are in use (#13360)
Naive solution to prevent InventoryList UAF and OOB ItemStack access caused by shrink/clear operations on InventoryLists within callbacks of an inventory action.

Co-authored-by: Desour <ds.desour@proton.me>
2023-04-22 17:42:36 +02:00
rubenwardy
4158b72971 Add ability to override item images using meta (#12614) 2023-04-17 19:44:41 +01:00
rubenwardy
8c2c7fadbf Add lua_api.txt to point to new file 2023-04-16 20:23:53 +01:00
rubenwardy
b1786e88ac Use .md extension for markdown files
Linking to line numbers is brittle, linking to sections/headings is better.

If you still want to link to a line number, you can append ?plain=1 to GitHub's URL
2023-04-16 20:23:53 +01:00
rubenwardy
5cd6a22dd3 Update settingtypes (#13428)
* Move settings to correct sections
* Improve titles and descriptions
* Make defaults in settingtypes.txt and defaultsettings.cpp match

Fixes #9002
2023-04-14 22:32:25 +01:00
rubenwardy
b89077187b Fix ContentDB page not being reset when changing type
Fixes #13362
2023-04-14 20:34:03 +01:00
rubenwardy
c5fb50298a Prevent installing mods when there is no base game (#13429) 2023-04-14 20:23:25 +01:00
Desour
ccd696c49a Throw Hocroft-Karp onto shapeless recipes 2023-04-14 21:10:09 +02:00
Desour
50e91b882c Add some simple unittests for shapeless recipes
Note: devtest also has craft unittests (see devtest/mods/unittests/crafting.lua),
      but those aren't run at load-time.
2023-04-14 21:10:09 +02:00
DS
ae7271b725 Fix background[] pos-offset lower-right-corner being at least (1,1) (#13320)
IGUIElement has a MinSize for the RelativeRect, which is at least (1,1).
This means a pos offset of (0,0) will cause a seemingly off-by-1 error at the
lower right corner, and (0.1,0.1) for example will just not work on the lower
right corner.
Ergo, we can't use the AbsoluteRect for storing the pos offset.
2023-04-14 21:05:09 +02:00
DS
d49d80a4a0 Store whether window is maximized (#12861) 2023-04-14 21:04:03 +02:00
cat-master21
0b08e1b1d2 AppImageBuilder.yml: add script section and update to Jammy (#13078) 2023-04-14 13:00:20 +01:00
Lars
f9b1176fa9 Track server's max AsyncRunStep 2023-04-14 00:09:48 +01:00
Lars
3d232e2345 Add MAX profiler option 2023-04-14 00:09:48 +01:00
rubenwardy
9d1ae80e89 Add focused styling to buttons (#13414) 2023-04-14 00:09:29 +01:00
Gregor Parzefall
2a1bc82887 Fix black loading screen background if menu_clouds = false (#13322) 2023-04-13 18:12:48 +01:00
Wuzzy
d1e5dbefc7 Clarify documentation of punch key (#13238) 2023-04-13 18:12:26 +01:00
Desour
fc116ec950 Play object footstep sound at feet 2023-04-13 18:12:13 +01:00
Desour
7283d2495f Devtest: Add bigfoot for footstep sounds 2023-04-13 18:12:13 +01:00
Zardshard
e139749b5c Simulate all keys being released when when game loses focus (#13336) 2023-04-13 18:06:21 +02:00
sfan5
fe75ec8d0d Update dependency libraries in buildbot 2023-04-13 18:05:39 +02:00
AFCMS
68f81ace97 Add vector.in_area() utility function (#13390) 2023-04-12 10:46:26 +01:00
rubenwardy
2fc7eb3ea2 Remove formspec_default_bg_color/opacity settings (#13419)
These settings are unnecessary. They only apply when formspecs don't have a background/bgcolor set. In practice, most games do theme their GUIs. Removing low value settings simplifies code and improves UX by decluttering the settings menu

Split out from #12140
2023-04-11 19:57:36 +01:00
Desour
1dd13da37d Get rid of global dummySoundManager
There is no need for this to be globally unique.
2023-04-11 20:06:15 +02:00
Desour
b201c03625 Use smart-ptrs in GUIEngine 2023-04-11 20:06:15 +02:00
Desour
ceec560779 Add make_irr 2023-04-11 20:06:15 +02:00
Stvk imension
d39a07efea Android: Minor Code Improvements (#13342) 2023-04-10 23:05:01 +01:00
Riley Adams
73391013f7 Add node pos to node damage HP change reason (#13196) 2023-04-10 23:04:52 +01:00
David Leal
1d88d85f1c Add progress_bar.png and progress_bar_bg.png to LICENSE file 2023-04-10 19:57:41 +02:00
Lars
4a742be73e Do not call updateDrawList, updateDrawListShadow, and touchMapBlocks in the same frame 2023-04-09 07:10:17 -10:00
Lars
8982998681 Add a default direction light for shadows 2023-04-09 07:10:17 -10:00
sfan5
9d736e8b8b Drop ENABLE_GLES option
ENABLE_GLES predates forking Irrlicht. Its primary use was to distinguish Irrlicht-ogles from upstream version as Minetest could be compiled with either.
That's not necessary anymore and gets in the way sometimes.
2023-04-08 20:19:35 +02:00
sfan5
c26e122485 Move video_driver default selection to runtime 2023-04-08 20:19:35 +02:00
Desour
67068cfaf4 Get rid of wgettext 2023-04-08 20:17:50 +02:00
Vitaliy
35929d27e3 Remove fast faces (#13216)
Co-authored-by: Lars <larsh@apache.org>
2023-04-08 20:17:15 +02:00
sfan5
2e497cc471 Merge remote-tracking branch 'origin/stable-5' into HEAD 2023-04-08 19:32:11 +02:00
sfan5
c2a9ac24ac Continue with 5.8.0-dev 2023-04-08 18:05:03 +02:00
sfan5
587f6656a4 Bump version to 5.6.1 2022-09-19 21:05:10 +02:00
sfan5
4377c03168 Bump used IrrlichtMt version 2022-09-16 20:27:29 +02:00
savilli
1e0520074c Fix UAF in craft recipes (#12763)
If you call minetest.clear_craft after minetest.register_alias_force, the craft definition reference may not be removed from m_output_craft_definitions leading to UAF.
2022-09-16 19:18:51 +02:00
DS
b9f6832347 Fix tooltips for dropdown, scrollbar and more (#12747) 2022-09-14 13:48:06 +02:00
Jude Melton-Houghton
f8bb0cd3d1 Fix potential use-after-free with item metadata (#12729)
This fixes a use-after-free bug in the case where itemstack metadata is accessed after the itemstack has been garbage-collected.
2022-09-14 13:48:06 +02:00
Lars Mueller
129aef758e Serialize: Restore forward compatibility 2022-09-14 13:48:06 +02:00
Lars Mueller
94f55cf406 Serialize: Use numbers for refs to work around LuaJIT limits 2022-09-14 13:48:06 +02:00
sfan5
a20b758e19 Allow looped animation to be used safely with old clients
fixes #12657
2022-09-14 13:48:06 +02:00
pecksin
128842becf Chat weblink: remove comma as delimiter (#12730) 2022-09-14 13:48:06 +02:00
x2048
d51331f51f Convert entity glow value to color space before adding to the light 2022-09-14 13:48:06 +02:00
Niklp
4ef221a645 Fix incorrectly placed label in tab_online (#12732) 2022-09-14 13:48:06 +02:00
savilli
79010e972e Fix and enable x86 build for Android (#12700) 2022-09-14 13:48:06 +02:00
fluxionary
0ca530e251 Fix texture_min_size 2022-09-14 13:48:06 +02:00
Elliott Lester
57b4d46dbc Apply DPI Scaling to GUIModalMenu (#12693)
Co-authored-by: sfan5 <sfan5@live.de>
2022-09-14 13:48:06 +02:00
rubenwardy
50df5e2f59 Fix crash when trying to overwrite a package
Before #11646, core.copy_dir would overwrite the target if it exists. Adding core.delete_dir restores the exact same behaviour

Fixes #12303
2022-09-14 13:48:06 +02:00
Fábio Rodrigues Ribeiro
b6db2c7262 Remove resolution of appstream screenshots (#12652)
resolves Appdata not valid #12597
2022-09-14 13:48:06 +02:00
sfan5
9441b69ad2 Move some CI jobs to newer compiler versions 2022-09-14 13:48:06 +02:00
x2048
08e3d16a58 Limit force shadow update to urgent blocks (#12692) 2022-09-14 13:48:06 +02:00
Lars Müller
3f3049fdba Check hp_max > 0 for entities (#12667) 2022-09-14 13:39:30 +02:00
Zughy
41fb7a8a7e Reassure previous nil behaviour for tiles and special_tiles (#12678)
Co-authored-by: Zughy <4279489-marco_a@users.noreply.gitlab.com>
2022-09-14 13:39:20 +02:00
Zughy
5b9828e094 Fix crash when crafting callbacks return strings (#12685)
Co-authored-by: Zughy <4279489-marco_a@users.noreply.gitlab.com>
2022-09-14 13:37:54 +02:00
Zughy
96e35585b0 Fix crash when stars are reset 2022-09-14 13:37:44 +02:00
sfan5
f035fe9336 Merge remote-tracking branch 'origin/stable-5' into HEAD 2022-08-04 22:54:13 +02:00
sfan5
44c2e33c78 Bump version to 5.5.1 2022-05-15 21:53:21 +02:00
rubenwardy
2785dcbbbf Fix broken dependency enabling due to missing enabled field 2022-05-14 18:24:46 +01:00
sfan5
9b03bd3243 Fix Docker build
prometheus-cpp switched to C++14 in April (after we did) so this issue only affects older branches.
2022-05-14 18:51:48 +02:00
Jude Melton-Houghton
8f30456ee3 Fix cooking and fuel crafts with aliases 2022-05-14 18:33:42 +02:00
Octavian
38557ff635 Fix possible unreliable behavior due to uninitialized variables 2022-05-14 18:33:42 +02:00
Lars Müller
7bc2cde4dd HUD: Update selection mesh every frame (#12270)
Fixes outdated selection boxes after entity property changes.
2022-05-14 18:33:42 +02:00
Lars Müller
f065d3a06b Fix Minetest blaming the wrong mod for errors (#12241)
Covers the case where mods insert their callbacks manually into "minetest.registered_<callbacks>" (often to achieve a particular order of execution).
2022-05-14 18:33:42 +02:00
Jude Melton-Houghton
21f7e3a987 Enable dependencies when enabling modpacks (#12202) 2022-05-14 18:33:42 +02:00
Jude Melton-Houghton
9f688bc433 Fix enabling of dependencies with identical names (#12253) 2022-05-14 18:33:42 +02:00
rubenwardy
6e9d31d4fb Fix mods not being recursively enabled
Fixes #12290
2022-05-14 18:33:42 +02:00
sfan5
e81c48526b Declare all bundled libs as static
Otherwise it can happen that these are built as shared depending on the
options passed to CMake, which obviously isn't intended.
2022-05-14 18:33:42 +02:00
SmallJoker
b405985b80 guiScalingFilter: Fix most memory leaks (#12256)
Calls to the cache function ended up creating a new texture regardless whether
the texture is already cached.
2022-05-14 18:33:42 +02:00
rubenwardy
8b010c5a9f ContentDB: Fix ungraceful crash on aliases when list download fails
Fixes #12267 and fixes #12154
2022-05-14 18:33:42 +02:00
sfan5
1e7b5d6fdb Fix synchronization issue at thread start
If a newly started thread immediately exits then m_running would
immediately be set to false again and the caller would be stuck
waiting for m_running to become true forever.
Since a mutex for synchronizing startup already exists we can
simply move the while loop into it.

see also: #5134 which introduced m_start_finished_mutex
2022-05-14 18:33:42 +02:00
sfan5
a55982e7f0 Fix password changing getting stuck if wrong password is entered once 2022-05-14 18:33:42 +02:00
sfan5
1ac378063e Apply disallow_empty_password to password changes too 2022-05-14 18:33:42 +02:00
sfan5
d497c92684 Fix race condition in registration leading to duplicate create_auth calls 2022-05-14 18:33:42 +02:00
paradust7
677dc2c155 Remove HW_buffer_counter after IrrlichtMt fix to remove HWBufferMap (#12232)
Keep code and use version check instead, for backwards compatibility
2022-05-14 18:33:42 +02:00
Alex
beea8deeb5 Fix invalid queued package element and path (#12218) 2022-05-14 18:33:42 +02:00
Giuseppe Bilotta
0d0f1a2fb2 Fix some textures not being sent correctly to older clients
Since b2eb44afc5, a texture defined as
`[combine:16x512:0,0=some_file.png;etc`
will not be sent correctly from a 5.5 server to a 5.4 client due to the
overeager detection of unsupported base modifier `[` introducing a
spurious `blank.png^` before the modifier.

Fix this by whitelisting which base modifiers can be passed through
unchanged to the client, and prefix `blank.png` for the others
(which at the moment is just [png:, but the list may grow larger
as new base modifiers are added.)
2022-05-14 18:33:42 +02:00
paradust7
439701ed7a Fix '[combine' when EVDF_TEXTURE_NPOT is disabled. (#12187)
Stop scaling images to POT immediately when loaded. The 'combine'
modifier hardcodes X and Y coordinates, and so behaves incorrectly
if applied to a scaled image. Images emitted by generateImage()
are already scaled to POT before being used as a texture, so
nothing should break.
2022-05-14 18:33:42 +02:00
ShadowNinja
d945d0129c Fix OOB read in trim("") 2022-05-14 18:33:42 +02:00
Dmitry Kostenko
cc91477308 Avoid negation of comparison operator (luacheck warning) 2022-05-14 18:33:42 +02:00
Daroc Alden
ac139ec03d Fix memory leak in EmergeManager
EmergeManager keeps a copy of the BiomeGen that it creates, but
never deletes it.
2022-05-14 18:33:42 +02:00
Gregor Parzefall
b4f0e834bf Fix footsteps for players whose collision box min y != 0 (#12110) 2022-05-14 18:33:42 +02:00
Daroc Alden
6e6cdc834f Fix undefined behavior in TileLayer (#12125)
Initialize the values properly
2022-05-14 18:33:42 +02:00
Daroc Alden
4b81ae1b35 Fix memory leak from SpatialAreaStore (#12120) 2022-05-14 18:33:42 +02:00
sfan5
d569dc45a8 Fix segfault with autoscale_mode (again)
closes #12100
This time add some asserts so there is no misunderstanding about the NULL-ness of layer->texture.
2022-05-14 18:33:42 +02:00
sfan5
23d49fda29 Clean up ClientReady packet handling
fixes #12073
2022-05-14 18:33:42 +02:00
pecksin
62ad2c3bc1 Use absolute value for bouncy in collision (#11969)
[backport: removed devtest change and protocol_version comparison]
2022-05-14 18:33:42 +02:00
sfan5
25373ad294 Remove awful Mingw32 workarounds
Instead a warning is triggered if an affected compiler is detected.
closes #12022
2022-05-12 11:36:50 +02:00
sfan5
26d0c0fd8d Fix broken server startup if curl is disabled (#12046) 2022-05-12 11:36:39 +02:00
Lars Mueller
3afffcd36b Fix builtin statbar backgrounds
see #12000
2022-05-12 11:36:11 +02:00
sfan5
5440de1785 Merge remote-tracking branch 'origin/stable-5' into HEAD 2022-01-30 23:10:56 +01:00
rubenwardy
25a56f11c8 Bump version to 5.4.2 2021-10-22 23:06:51 +01:00
rubenwardy
8271c6481f Fix manifest and various things 2021-10-20 15:27:30 +01:00
sfan5
83e26f839d Reserve vectors before pushing and other code quality changes (#11161) 2021-10-20 14:25:39 +01:00
sfan5
c3f7905d82 Remove broken timeout behaviour
Code that relies on `resend_count` was added in 7ea4a03 and 247a1eb, but never worked.
This was fixed in #11607 which caused the problem to surface.
Hence undo the first commit entirely and change the logic of the second.
2021-10-19 19:23:00 +01:00
sfan5
05b54a8d18 Shave off buffer copies in networking code (#11607) 2021-10-19 19:22:46 +01:00
rubenwardy
e5cfdd369e Update deps ref 2021-10-18 18:33:25 +01:00
rubenwardy
c61d8cfb85 Use scoped app storage on Android (#11466)
From November 2021, the Play Store will no longer be accepting
apps which use the deprecated getExternalStorageDirectory() API.

Therefore, this commit replaces uses of deprecated API with the new
scoped API (`getExternalFilesDir()` and `getExternalCacheDir()`).
It also provides a temporary migration to move user data from the
shared external directory to new storage.

Fixes #2097,  #11417 and #11118
2021-10-18 18:12:03 +01:00
NeroBurner
27f4195471 Move build/android directory to root of project (#11283) 2021-10-18 18:11:33 +01:00
sfan5
b2596eda32 Bump version to 5.4.1 2021-04-10 18:41:12 +02:00
waxtatect
9379440fcb Translated using Weblate (French)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
Brian Gaucher
b7c502c8d1 Translated using Weblate (French)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
Markus Mikkonen
3c16d2d9b4 Translated using Weblate (Finnish)
Currently translated at 3.2% (44 of 1356 strings)
2021-04-10 17:51:40 +02:00
Tviljan
6cbc03a418 Translated using Weblate (Finnish)
Currently translated at 3.2% (44 of 1356 strings)
2021-04-10 17:51:40 +02:00
Edward
15ecc0fa65 Translated using Weblate (Russian)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
ssantos
7f2f8cdad1 Translated using Weblate (Portuguese)
Currently translated at 93.2% (1264 of 1356 strings)
2021-04-10 17:51:40 +02:00
waxtatect
a64646cb7b Translated using Weblate (French)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
David Leal
05f531c538 Translated using Weblate (Spanish)
Currently translated at 79.7% (1081 of 1356 strings)
2021-04-10 17:51:40 +02:00
François Delpierre
7ca335446b Translated using Weblate (French)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
waxtatect
99e96a6581 Translated using Weblate (French)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
BreadW
7200d8f90e Translated using Weblate (Japanese)
Currently translated at 99.8% (1354 of 1356 strings)
2021-04-10 17:51:40 +02:00
GnuPGを使うべきだ
7038837aca Translated using Weblate (Japanese)
Currently translated at 99.7% (1353 of 1356 strings)
2021-04-10 17:51:40 +02:00
ItsWidee
541dcc0e5a Translated using Weblate (French)
Currently translated at 98.0% (1330 of 1356 strings)
2021-04-10 17:51:40 +02:00
François Delpierre
1060b5aabf Translated using Weblate (French)
Currently translated at 96.6% (1311 of 1356 strings)
2021-04-10 17:51:40 +02:00
Dainis
6ea73c4982 Translated using Weblate (Latvian)
Currently translated at 28.6% (388 of 1356 strings)
2021-04-10 17:51:40 +02:00
Konstantin Yeliseyev
cff847273a Translated using Weblate (Russian)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
ResuUman
e669f8db9b Translated using Weblate (Polish)
Currently translated at 72.4% (982 of 1356 strings)
2021-04-10 17:51:40 +02:00
Mateusz Mendel
461cc30842 Translated using Weblate (Polish)
Currently translated at 72.4% (982 of 1356 strings)
2021-04-10 17:51:40 +02:00
gnu-ewm
13d7cb957c Translated using Weblate (Polish)
Currently translated at 71.6% (972 of 1356 strings)
2021-04-10 17:51:40 +02:00
Alessandro Mandelli
47a439a905 Translated using Weblate (Italian)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:40 +02:00
Hatlábú Farkas
053fb96694 Translated using Weblate (Hungarian)
Currently translated at 75.8% (1028 of 1356 strings)
2021-04-10 17:51:39 +02:00
ItsWidee
b72c1f7367 Translated using Weblate (French)
Currently translated at 96.5% (1309 of 1356 strings)
2021-04-10 17:51:39 +02:00
matiasC
e90738575f Translated using Weblate (Spanish)
Currently translated at 79.5% (1079 of 1356 strings)
2021-04-10 17:51:39 +02:00
Joaquín Villalba
35718eec9c Translated using Weblate (Spanish)
Currently translated at 79.5% (1079 of 1356 strings)
2021-04-10 17:51:39 +02:00
AnthonyDe
8285a53152 Translated using Weblate (Spanish)
Currently translated at 79.5% (1079 of 1356 strings)
2021-04-10 17:51:39 +02:00
Michalis
116fe7815b Translated using Weblate (Greek)
Currently translated at 8.8% (120 of 1356 strings)
2021-04-10 17:51:39 +02:00
Yangjun Wang
4c2efd7da3 Translated using Weblate (Chinese (Simplified))
Currently translated at 94.7% (1285 of 1356 strings)
2021-04-10 17:51:39 +02:00
Liu Tao
1a433e3185 Translated using Weblate (Chinese (Simplified))
Currently translated at 94.7% (1285 of 1356 strings)
2021-04-10 17:51:39 +02:00
Yangjun Wang
fa98a00916 Translated using Weblate (Chinese (Simplified))
Currently translated at 92.5% (1255 of 1356 strings)
2021-04-10 17:51:39 +02:00
David Leal
f4dd46ad60 Translated using Weblate (Spanish)
Currently translated at 79.0% (1072 of 1356 strings)
2021-04-10 17:51:39 +02:00
Joaquín Villalba
41825ccfbb Translated using Weblate (Spanish)
Currently translated at 78.0% (1059 of 1356 strings)
2021-04-10 17:51:39 +02:00
David Leal
4d1a5f12c0 Translated using Weblate (Spanish)
Currently translated at 78.0% (1059 of 1356 strings)
2021-04-10 17:51:39 +02:00
Agustin Calderon
cc58d56c6d Translated using Weblate (Spanish)
Currently translated at 78.0% (1059 of 1356 strings)
2021-04-10 17:51:39 +02:00
abidin toumi
683ef07312 Translated using Weblate (Arabic)
Currently translated at 25.7% (349 of 1356 strings)
2021-04-10 17:51:39 +02:00
Tirifto
c77c78cef5 Translated using Weblate (Esperanto)
Currently translated at 94.6% (1283 of 1356 strings)
2021-04-10 17:51:39 +02:00
Oğuz Ersen
88517030a4 Translated using Weblate (Turkish)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:39 +02:00
THANOS SIOURDAKIS
45471e8e63 Translated using Weblate (Greek)
Currently translated at 8.8% (120 of 1356 strings)
2021-04-10 17:51:39 +02:00
Yaya - Nurul Azeera Hidayah @ Muhammad Nur Hidayat Yasuyoshi
4e620beb75 Translated using Weblate (Malay)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:39 +02:00
winniepee
e7ab875b47 Translated using Weblate (Chinese (Simplified))
Currently translated at 92.4% (1254 of 1356 strings)
2021-04-10 17:51:39 +02:00
Ayes
be74ed9ab6 Translated using Weblate (Estonian)
Currently translated at 39.5% (536 of 1356 strings)
2021-04-10 17:51:39 +02:00
Wuzzy
52b2eacd37 Translated using Weblate (German)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:39 +02:00
Marian
6b4210a2ea Translated using Weblate (Slovak)
Currently translated at 100.0% (1356 of 1356 strings)
2021-04-10 17:51:39 +02:00
narrnika
740d0da5ee Translated using Weblate (Russian)
Currently translated at 99.3% (1347 of 1356 strings)
2021-04-10 17:51:07 +02:00
Mateusz Mendel
34883d356e Translated using Weblate (Polish)
Currently translated at 71.2% (966 of 1356 strings)
2021-04-10 17:51:07 +02:00
Giov4
aeafcce314 Translated using Weblate (Italian)
Currently translated at 99.7% (1352 of 1356 strings)
2021-04-10 17:51:07 +02:00
savilli
ae1d82c325 Fix hud_change and hud_remove after hud_add (#10997) 2021-04-09 22:05:22 +02:00
Vitaliy
1c89a07226 Restore minimal normal texture support (for minimap shading) 2021-04-09 22:04:51 +02:00
sfan5
43e262f13e Don't apply connection timeout limit to locally hosted servers
fixes #11085
2021-04-05 16:02:47 +02:00
sfan5
e5f802ab5c Fix server favorites not saving when client/serverlist/ doesn't exist already (#11152) 2021-04-05 16:02:32 +02:00
Lars Müller
847860fc5c Block & report player self-interaction (#11137) 2021-04-05 16:01:27 +02:00
SmallJoker
77e936445f Protect dropping from far node inventories
Also changes if/if to switch/case
2021-04-05 16:01:21 +02:00
SmallJoker
41beb74ef7 Protect per-player detached inventory actions 2021-04-05 16:01:15 +02:00
Elias Fleckenstein
67be50b706 Make pkgmgr handle modpacks containing modpacks properly
fixes #10550
2021-04-05 16:01:10 +02:00
rubenwardy
cd840b7c9d pkgmgr: Fix crash when .conf release field is invalid
Fixes #10942
2021-04-05 16:01:03 +02:00
sfan5
07903949ec Merge remote-tracking branch 'origin/stable-5' into HEAD 2021-02-23 20:18:23 +01:00
sfan5
d2156ddaad Merge remote-tracking branch 'origin/stable-5' into HEAD 2020-07-09 22:21:48 +02:00
sfan5
a84ff4b3ff Merge remote-tracking branch 'origin/stable-5' into HEAD 2020-04-05 18:44:51 +02:00
rubenwardy
c02f13d33f Release 5.1.1 2020-01-11 18:29:02 +00:00
rubenwardy
f6490859fd Translated using Weblate (Japanese (Kansai))
Currently translated at 0.2% (2 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
4b7816dbf4 Translated using Weblate (Burmese)
Currently translated at 0.2% (2 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
86ffbc3ec5 Translated using Weblate (Kazakh)
Currently translated at 0.2% (2 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
67257f44a5 Translated using Weblate (Arabic)
Currently translated at 6.1% (78 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
3086f5567a Translated using Weblate (Vietnamese)
Currently translated at 2.5% (32 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
bb8acb095d Translated using Weblate (Portuguese)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
24be3cbb5f Translated using Weblate (Basque)
Currently translated at 15.1% (193 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
9773191103 Translated using Weblate (Greek)
Currently translated at 1.4% (18 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
ddc703c3ec Translated using Weblate (Filipino)
Currently translated at 0.2% (2 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
09ec204e4b Translated using Weblate (Thai)
Currently translated at 66.9% (852 of 1274 strings)
2020-01-11 18:29:02 +00:00
rubenwardy
8b6cafa0e0 Translated using Weblate (Lao)
Currently translated at 0.2% (2 of 1274 strings)
2020-01-11 18:29:02 +00:00
Osoitz
1ee8be9d43 Translated using Weblate (Basque)
Currently translated at 15.1% (192 of 1274 strings)
2020-01-10 18:57:47 +00:00
Dhimas Wnz
91bc190d21 Translated using Weblate (Indonesian)
Currently translated at 96.9% (1234 of 1274 strings)
2020-01-10 18:57:47 +00:00
THANOS SIOURDAKIS
4dc833b642 Translated using Weblate (Greek)
Currently translated at 1.3% (17 of 1274 strings)
2020-01-10 18:57:47 +00:00
universales
895e9f8d5c Translated using Weblate (Spanish)
Currently translated at 61.9% (789 of 1274 strings)
2020-01-10 18:57:47 +00:00
Osoitz
12906ff631 Translated using Weblate (Basque)
Currently translated at 9.7% (123 of 1274 strings)
2020-01-10 18:57:47 +00:00
Osoitz
9c9bcff107 Added translation using Weblate (Basque) 2020-01-10 18:57:47 +00:00
Hotower
443ca5c63b Translated using Weblate (Chinese (Simplified))
Currently translated at 65.1% (830 of 1274 strings)
2020-01-10 18:57:47 +00:00
Stas Kies
1102b1fc4c Translated using Weblate (German)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:47 +00:00
abidin toumi
0d089eab21 Translated using Weblate (Arabic)
Currently translated at 6.0% (77 of 1274 strings)
2020-01-10 18:57:47 +00:00
zaoqi
b44fada29e Translated using Weblate (Chinese (Simplified))
Currently translated at 65.1% (830 of 1274 strings)
2020-01-10 18:57:47 +00:00
Yangjun Wang
859ea160e6 Translated using Weblate (Chinese (Simplified))
Currently translated at 63.2% (805 of 1274 strings)
2020-01-10 18:57:47 +00:00
Ács Zoltán
1c49e2ffc0 Translated using Weblate (Hungarian)
Currently translated at 61.9% (789 of 1274 strings)
2020-01-10 18:57:47 +00:00
Tirifto
140245c58d Translated using Weblate (Esperanto)
Currently translated at 97.2% (1238 of 1274 strings)
2020-01-10 18:57:47 +00:00
Petter Reinholdtsen
47adcced60 Translated using Weblate (Norwegian Bokmål)
Currently translated at 43.3% (552 of 1274 strings)
2020-01-10 18:57:47 +00:00
Luboš Nečas
a2054deb12 Translated using Weblate (Czech)
Currently translated at 48.8% (622 of 1274 strings)
2020-01-10 18:57:47 +00:00
Tirifto
30fdfd9ded Translated using Weblate (Esperanto)
Currently translated at 94.9% (1209 of 1274 strings)
2020-01-10 18:57:47 +00:00
ramon.venson
a87a86eb92 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.9% (1235 of 1274 strings)
2020-01-10 18:57:47 +00:00
Daniel Mancini
49dfbcfbc8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.9% (1235 of 1274 strings)
2020-01-10 18:57:47 +00:00
Andrei Stepanov
c558a4f4f6 Translated using Weblate (Russian)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:46 +00:00
Andrei Stepanov
4f49a2248f Translated using Weblate (Russian)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:46 +00:00
Andrei Stepanov
4e57da42c1 Translated using Weblate (Russian)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:46 +00:00
Andrei Stepanov
4f6c9e206c Translated using Weblate (Russian)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:46 +00:00
Andrei Stepanov
699e1d4b77 Translated using Weblate (Russian)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:46 +00:00
Matej Mlinar
fa2978b3b9 Translated using Weblate (Slovenian)
Currently translated at 43.9% (559 of 1274 strings)
2020-01-10 18:57:46 +00:00
abidin toumi
ffcdf741fc Translated using Weblate (Arabic)
Currently translated at 5.7% (73 of 1274 strings)
2020-01-10 18:57:46 +00:00
Fixer
429d7f33d4 Translated using Weblate (Ukrainian)
Currently translated at 42.1% (536 of 1274 strings)
2020-01-10 18:57:46 +00:00
Andrei Stepanov
b6a229775e Translated using Weblate (Russian)
Currently translated at 81.9% (1044 of 1274 strings)
2020-01-10 18:57:46 +00:00
abidin toumi
0a4580368a Translated using Weblate (Arabic)
Currently translated at 5.6% (71 of 1274 strings)
2020-01-10 18:57:46 +00:00
abidin toumi
e5b191e1f1 Translated using Weblate (Arabic)
Currently translated at 4.2% (53 of 1274 strings)
2020-01-10 18:57:46 +00:00
Andrei Stepanov
a07acc067b Translated using Weblate (Russian)
Currently translated at 81.7% (1041 of 1274 strings)
2020-01-10 18:57:46 +00:00
abidin toumi
01e763f879 Added translation using Weblate (Arabic) 2020-01-10 18:57:46 +00:00
Viktar Vauchkevich
a95e75261a Translated using Weblate (Belarusian)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:46 +00:00
Julien Maulny
dcaa7ac609 Translated using Weblate (French)
Currently translated at 97.0% (1236 of 1274 strings)
2020-01-10 18:57:46 +00:00
Jacques Lagrange
7d2ae10849 Translated using Weblate (Italian)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
642cac3759 Translated using Weblate (Japanese (Kansai))
Currently translated at 0.1% (1 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
662af2edba Translated using Weblate (Dhivehi)
Currently translated at 8.2% (105 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
6f97e15a8f Translated using Weblate (Chinese (Simplified))
Currently translated at 63.0% (803 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
ab2fa2ca9d Translated using Weblate (Burmese)
Currently translated at 0.1% (1 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
4666c99b27 Translated using Weblate (Kyrgyz)
Currently translated at 8.6% (110 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
e38415c56d Translated using Weblate (Slovenian)
Currently translated at 42.0% (535 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
3f3fce4664 Translated using Weblate (Kannada)
Currently translated at 3.0% (38 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
1407a7bc8a Translated using Weblate (Kazakh)
Currently translated at 0.1% (1 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
1d268f4b83 Translated using Weblate (Norwegian Nynorsk)
Currently translated at 31.2% (398 of 1274 strings)
2020-01-10 18:57:46 +00:00
Krock
92aab79d27 Translated using Weblate (Italian)
Currently translated at 96.9% (1234 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
0823bb1276 Translated using Weblate (Hebrew)
Currently translated at 4.3% (55 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
18e42efa01 Translated using Weblate (Hungarian)
Currently translated at 61.9% (788 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
0ea16328df Translated using Weblate (Estonian)
Currently translated at 14.4% (183 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
b037efc5c6 Translated using Weblate (Esperanto)
Currently translated at 79.6% (1014 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
839bb71389 Translated using Weblate (Greek)
Currently translated at 1.1% (14 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
2ef7df5cfe Translated using Weblate (Danish)
Currently translated at 49.5% (631 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
f5d2d79f75 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.4% (1228 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
8e5fa96ffc Translated using Weblate (Filipino)
Currently translated at 0.1% (1 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
6dbbe07d50 Translated using Weblate (Thai)
Currently translated at 66.8% (851 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
3c23410753 Translated using Weblate (Lithuanian)
Currently translated at 15.4% (196 of 1274 strings)
2020-01-10 18:57:45 +00:00
Krock
8e35ab78b4 Translated using Weblate (Lao)
Currently translated at 0.1% (1 of 1274 strings)
2020-01-10 18:57:45 +00:00
Allan Nordhøy
7f2911b7f0 Translated using Weblate (Italian)
Currently translated at 96.9% (1234 of 1274 strings)
2020-01-10 18:57:45 +00:00
Mateusz Mendel
d877e90301 Translated using Weblate (Polish)
Currently translated at 81.1% (1033 of 1274 strings)
2020-01-10 18:57:45 +00:00
Vicente Carrasco Alvarez
93db4be726 Translated using Weblate (Spanish)
Currently translated at 61.5% (783 of 1274 strings)
2020-01-10 18:57:45 +00:00
Mateusz Mendel
1f419ad19f Translated using Weblate (Polish)
Currently translated at 81.1% (1033 of 1274 strings)
2020-01-10 18:57:45 +00:00
Muhammad Nur Hidayat Yasuyoshi
3c7f6508ad Translated using Weblate (Malay)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:45 +00:00
Mattias Münster
39449d4b63 Translated using Weblate (Swedish)
Currently translated at 32.7% (417 of 1274 strings)
2020-01-10 18:57:45 +00:00
Jacques Lagrange
28e05295fa Translated using Weblate (Italian)
Currently translated at 96.9% (1234 of 1274 strings)
2020-01-10 18:57:45 +00:00
Ács Zoltán
60c18d3550 Translated using Weblate (Hungarian)
Currently translated at 61.9% (788 of 1274 strings)
2020-01-10 18:57:45 +00:00
ssantos
482ab186a2 Translated using Weblate (Portuguese)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:45 +00:00
BreadW
4814195dc4 Translated using Weblate (Japanese)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:45 +00:00
Wuzzy
d215b7a10e Translated using Weblate (German)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:45 +00:00
nautilusx
0e52b78590 Translated using Weblate (German)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:45 +00:00
monolifed
b3a9d607c4 Translated using Weblate (Turkish)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:45 +00:00
Oguz Ersen
c00081b62c Translated using Weblate (Turkish)
Currently translated at 100.0% (1274 of 1274 strings)
2020-01-10 18:57:44 +00:00
William Breathitt Gray
5e4739b460 Fix find_path for newer jsoncpp installations
The upstream JsonCpp project has renamed the `json/features.h` file to
`json/json_features.h`. This patch fixes the JsonCpp installation search
by looking for `json/allocator.h` which has not been renamed on newer
versions of JsonCpp.

Fixes: https://github.com/minetest/minetest/issues/9119
2019-12-31 21:39:16 +00:00
SmallJoker
0d8f598df2 Fix LocalPlayer-bound sound playback broken by 81c2370 2019-12-31 21:31:53 +00:00
Wuzzy
2ef04cc308 Fix item eat sound not played if last item (#9239) 2019-12-31 21:31:53 +00:00
rubenwardy
7a0884e2cd Fix spaces breaking formspec_version[] tag 2019-12-31 21:31:53 +00:00
ANAND
fa858530cc Use a safer implementation of gsub in core.chat_format_message (#9133)
This search-and-replace implementation does not use Lua pattern-matching
2019-12-31 21:31:53 +00:00
sfan5
1c61fe5ed9 Rework packet receiving in ServerThread
Notably it tries to receive all queued packets
between server steps, not just one.
2019-12-31 21:31:53 +00:00
Dmitry Marakasov
57409ef382 Fix build issue due to conflicting s64 type definitions (#9064)
See comment in irrlichttypes.h and https://sourceforge.net/p/irrlicht/bugs/433/
2019-12-31 21:31:52 +00:00
SmallJoker
06ba826803 Formspecs: Reset version number on rebuild 2019-12-26 17:24:27 +00:00
rubenwardy
6e6ef9489f Continue with 5.1.1-dev 2019-12-26 17:24:23 +00:00
Loic Blot
45bbe39d1f Add arm64-v8a but it's not sufficient for 64bit build 2019-11-09 12:50:53 +01:00
Loic Blot
6c9fc13083 Bump to version code 25 2019-11-09 11:37:46 +01:00
MoNTE48
4c8a642388 Android: build fixes & compat fixes 2019-11-09 11:23:31 +01:00
sfan5
6208c9d64f Merge remote-tracking branch 'origin/stable-5' into HEAD 2019-10-12 15:59:36 +02:00
sfan5
76325d0ba9 Bump version to 5.0.1 2019-03-31 22:57:45 +02:00
rubenwardy
cf1802a6de Prevent multi-line chat messages server-side (#8420) 2019-03-28 21:49:03 +00:00
sfan5
538a7b12bd Fix texture rotation for wallmounted nodeboxes
fixes #8358
2019-03-19 22:37:11 +01:00
sfan5
57e0f52aaa httpfetch: Disable IPv6 here too if requested by settings (#8399) 2019-03-19 02:18:34 +00:00
Paramat
1ae0335b62 num_emerge_threads: Initialise value to cope with setting syntax error (#8396) 2019-03-19 02:18:26 +00:00
paramat
ca1bff6b66 num_emerge_threads: Fix documentation of automatic selection 2019-03-19 02:18:17 +00:00
Paramat
10cc62d2ca num_emerge_threads: Warn of crashes when > 1 (#8357) 2019-03-14 17:58:19 +00:00
rubenwardy
dd451a8a00 Fix cast from const by accessing string data directly (#8354)
Fixes #8327
2019-03-12 20:25:55 +00:00
rubenwardy
444ec1e412 HPChange Reason: Fix push after free, and type being overwritten (#8359)
* HPChange Reason: Fix push after free, and type being overwritten

Fixes #8227 and #8344
2019-03-12 20:25:48 +00:00
Paramat
82739f4d7d Change 'num_emerge_threads' default to 1 (#8303) 2019-03-11 22:07:19 +00:00
sofar
19825d853e getS16NoEx() returns true unless syntactical error in conf. (#8304)
The getS16NoEx() handler will return true unless there is a
`[num_emerge_threads]` line in the `minetest.conf` at which
point the excption handler part is reached. Due to the fact that
`defaultsettings.cpp` has a default value set for this setting,
that never will happen.

Because of this, the code will never check the number of threads on
the system, and keep `nthreads = 0`. If that happens, the value is
changed to `1` and only 1 emerge thread will be used.

The default should be set to `1` instead, due to the potential unsafe
consequences for the standard sqlite map files, but that should be a
separate commit that also adds documentation for that setting. This
commit focuses on removing this `hiding` bug instead.
2019-03-11 22:07:19 +00:00
rubenwardy
d8ece2e3e9 Fix serialization of std::time_t by casting to u64 first (#8353)
Fixes #8332
2019-03-11 22:07:19 +00:00
Paramat
bf4deb0ce6 Confirm registration GUI: Remove positional strings to fix Windows bug (#8258)
Positional strings don't work on some Windows builds.
Remove server address string, leave player name string present.
2019-03-11 22:07:19 +00:00
rubenwardy
da4739a26c Fix detach inventory serialisation (#8331) 2019-03-11 22:07:19 +00:00
rubenwardy
fc24bf0915 Fix incorrect string length check after cast 2019-03-11 22:07:19 +00:00
rubenwardy
9329b99cba Continue with 5.0.1-dev 2019-03-11 22:07:12 +00:00
648 changed files with 136098 additions and 89012 deletions

View File

@@ -3,10 +3,10 @@ IndentWidth: 4
UseTab: Always
TabWidth: 4
BreakBeforeBraces: Custom
Standard: Cpp11
Standard: c++17
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: true
@@ -20,7 +20,7 @@ IndentCaseLabels: false
AccessModifierOffset: -4
ColumnLimit: 90
AllowShortFunctionsOnASingleLine: InlineOnly
SortIncludes: false
SortIncludes: Never
IncludeCategories:
- Regex: '^".*'
Priority: 2

View File

@@ -2,7 +2,7 @@
end_of_line = lf
[*.{cpp,h,lua,txt,glsl,md,c,cmake,java,gradle}]
charset = utf8
charset = utf-8
indent_size = 4
indent_style = tab
insert_final_newline = true

View File

@@ -19,7 +19,7 @@ Contributions are welcome! Here's how you can help:
developers.
Any Pull Request that isn't a bug fix and isn't covered by
[the roadmap](../doc/direction.md) will be closed within a week unless it
[the roadmap](../doc/direction.md) will be closed within a month unless it
receives a concept approval from a Core Developer. For this reason, it is
recommended that you open an issue for any such pull requests before doing
the work, to avoid disappointment.
@@ -30,7 +30,7 @@ Contributions are welcome! Here's how you can help:
3. Start coding!
- Refer to the
[Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt),
[Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.md),
[Developer Wiki](http://dev.minetest.net/Main_Page) and other
[documentation](https://github.com/minetest/minetest/tree/master/doc).
- Follow the [C/C++](http://dev.minetest.net/Code_style_guidelines) and

View File

@@ -1,32 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: Unconfirmed bug
assignees: ''
---
##### Minetest version
<!--
Paste Minetest version between quotes below.
If you are on a devel version, please add git commit hash.
You can use `minetest --version` to find it.
-->
```
```
##### OS / Hardware
<!-- General information about your hardware and operating system -->
Operating system:
CPU:
<!-- For graphical issues only -->
GPU model:
OpenGL version:
##### Summary
<!-- Describe your problem here -->
##### Steps to reproduce
<!-- Explain how the problem has happened, providing a minimal test (i.e. a code snippet reduced to the bone) where possible -->

91
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View File

@@ -0,0 +1,91 @@
name: Bug report
description: Create a report to help us improve
labels: ["Unconfirmed bug"]
body:
- type: markdown
attributes:
value: |
Please note the following:
1. **Please update your Minetest Engine 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.minetest.net/packages/?type=game) and submit a bug report in their issue trackers.
* For example, you can submit issues about the Minetest Game (the official game of Minetest) [in its own repository](https://github.com/minetest/minetest_game/issues).
3. Please provide as many details as possible for us to spot the problem quicker.
- type: textarea
attributes:
label: Minetest version
description: |
Paste the Minetest version below.
If you are on a devel version, please add a git commit hash.
You can use `minetest --version` to find it.
You can also refer to the "About" tab of the menu.
placeholder: |
Example:
Minetest 5.7.0-dev-ca13c51 (Linux)
Using Irrlicht 1.9.0mt9
Using LuaJIT 2.1.0-beta3
BUILD_TYPE=Release
RUN_IN_PLACE=1
USE_CURL=1
USE_GETTEXT=1
USE_SOUND=1
STATIC_SHAREDIR="."
STATIC_LOCALEDIR="locale"
render: "true"
validations:
required: true
- type: input
attributes:
label: Active renderer
description: For graphical and input-related issues. You can find these in the About tab in the mainmenu.
placeholder: "Example: OpenGL 4.6.0"
validations:
required: false
- type: input
attributes:
label: Irrlicht device
description:
placeholder: "Example: X11"
validations:
required: false
- type: input
attributes:
label: Operating system and version
description: It is recommended to upgrade your operating system to see if the problem still exists.
placeholder: "Example: Ubuntu 22.04"
validations:
required: true
- type: input
attributes:
label: CPU model
description: Usually found in system settings.
placeholder: "Example: Intel i5-2410M (4) @ 2.900GHz"
validations:
required: false
- type: markdown
attributes:
value: The GPU model and OpenGL version can be omitted if the bug is not a graphical issue.
- type: input
attributes:
label: GPU model
description: Usually found in system settings.
placeholder: "Example: NVIDA GeForce RTX 4090"
validations:
required: false
- type: input
attributes:
label: OpenGL version
placeholder: "Example: 4.6"
validations:
required: false
- type: textarea
attributes:
label: Summary
description: Describe your problem here.
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Explain how the problem has happened, providing a minimal test (i.e. a code snippet reduced to the bone) where possible.
validations:
required: true

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Submit issues about Minetest Game
url: https://github.com/minetest/minetest_game/issues/new/choose
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
url: https://content.minetest.net/packages/?type=game
about: For issues of third-party games, search for the game in the ContentDB and then submit an issue in their issue tracker.

View File

@@ -1,25 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: Feature request
assignees: ''
---
## Problem
A clear and concise description of what the problem is.
ie: Why is this needed?
Ex. I'm always frustrated when [...]
## Solutions
A clear and concise description of what you want to happen.
## Alternatives
A clear and concise description of any alternative solutions or features you've considered.
## Additional context
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,39 @@
name: Feature request
description: Suggest an idea for this project
labels: ["Feature request"]
body:
- type: markdown
attributes:
value: |
Please note the following:
1. Only submit a feature request if the feature does not exist on the latest dev version.
2. This page is for suggesting changes to **the engine itself**. To suggest changes to games, please [search for the game in the ContentDB](https://content.minetest.net/packages/?type=game) and submit a feature request in their issue trackers.
- type: textarea
attributes:
label: Problem
description: |
A clear and concise description of the problem, i.e. "Why is this needed?"
Example: I'm always frustrated when [...]
validations:
required: true
- type: textarea
attributes:
label: Solutions
description: |
A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Alternatives
description: |
A clear and concise description of any alternative solutions or features you've considered.
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: |
Add any other context or screenshots about the feature request here.
validations:
required: false

View File

@@ -3,7 +3,7 @@ Add compact, short information about your PR for easier understanding:
- Goal of the PR
- How does the PR work?
- Does it resolve any reported issue?
- Does this relate to a goal in [the roadmap](../doc/direction.md)?
- Does this relate to a goal in [the roadmap](https://github.com/minetest/minetest/blob/master/doc/direction.md)?
- If not a bug fix, why is this PR needed? What usecases does it solve?
## To do

View File

@@ -28,8 +28,17 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends gettext openjdk-11-jdk-headless
- name: Build with Gradle
- name: Build AAB with Gradle
# We build an AAB as well for uploading to the the Play Store.
run: cd android; ./gradlew bundlerelease
- name: Build APKs with Gradle
# "assemblerelease" is very fast after "bundlerelease".
run: cd android; ./gradlew assemblerelease
- name: Save AAB artifact
uses: actions/upload-artifact@v4
with:
name: Minetest-release.aab
path: android/app/build/outputs/bundle/release/app-release.aab
- name: Save armeabi artifact
uses: actions/upload-artifact@v3
with:

View File

@@ -34,22 +34,21 @@ env:
jobs:
# Older gcc version (should be close to our minimum supported version)
gcc_5:
runs-on: ubuntu-18.04
if: "false" # FIXME
gcc_7:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Install deps
run: |
source ./util/ci/common.sh
install_linux_deps g++-5
install_linux_deps g++-7
- name: Build
run: |
./util/ci/build.sh
env:
CC: gcc-5
CXX: g++-5
CC: gcc-7
CXX: g++-7
- name: Test
run: |
@@ -77,31 +76,27 @@ jobs:
./bin/minetest --run-unittests
# Older clang version (should be close to our minimum supported version)
clang_3_9:
runs-on: ubuntu-18.04
if: "false" # FIXME
clang_7:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Install deps
run: |
source ./util/ci/common.sh
install_linux_deps clang-3.9 valgrind
install_linux_deps clang-7 llvm
- name: Build
run: |
./util/ci/build.sh
env:
CC: clang-3.9
CXX: clang++-3.9
CC: clang-7
CXX: clang++-7
CMAKE_FLAGS: '-DCMAKE_C_FLAGS="-fsanitize=address" -DCMAKE_CXX_FLAGS="-fsanitize=address"'
- name: Unittest
run: |
./bin/minetest --run-unittests
- name: Valgrind
run: |
valgrind --leak-check=full --leak-check-heuristics=all --undef-value-errors=no --error-exitcode=9 ./bin/minetest --run-unittests
# Current clang version
clang_14:
runs-on: ubuntu-22.04
@@ -179,7 +174,6 @@ jobs:
run: |
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin32.sh winbuild
env:
NO_MINETEST_GAME: 1
NO_PACKAGE: 1
win64:
@@ -197,15 +191,14 @@ jobs:
run: |
EXISTING_MINETEST_DIR=$PWD ./util/buildbot/buildwin64.sh winbuild
env:
NO_MINETEST_GAME: 1
NO_PACKAGE: 1
msvc:
name: VS 2019 ${{ matrix.config.arch }}-${{ matrix.type }}
runs-on: windows-2019
env:
VCPKG_VERSION: 5cf60186a241e84e8232641ee973395d4fde90e1
# 2022.02
VCPKG_VERSION: 8eb57355a4ffb410a2e94c07b4dca2dffbee8e50
# 2023.10.19
vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry
strategy:
fail-fast: false
@@ -249,6 +242,8 @@ jobs:
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}\vcpkg\scripts\buildsystems\vcpkg.cmake" `
-DCMAKE_BUILD_TYPE=Release `
-DENABLE_POSTGRESQL=OFF `
-DENABLE_LUAJIT=TRUE `
-DREQUIRE_LUAJIT=TRUE `
-DRUN_IN_PLACE=${{ contains(matrix.type, 'portable') }} .
- name: Build Minetest

48
.github/workflows/lua_api_deploy.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: lua_api_deploy
permissions:
contents: read
pages: write
id-token: write
on:
push:
paths:
- '.github/workflows/lua_api_deploy.yml'
- 'doc/lua_api.md'
- 'doc/mkdocs/'
branches:
- master
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
- name: Install mkdocs
run: |
pip install -U -r doc/mkdocs/requirements.txt
- name: Build documentation
run: |
cd doc/mkdocs/
./build.sh
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: 'public/'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2

View File

@@ -21,14 +21,9 @@ on:
- 'cmake/Modules/**'
- '.github/workflows/macos.yml'
env:
MINETEST_GAME_REPO: https://github.com/minetest/minetest_game.git
MINETEST_GAME_BRANCH: master
MINETEST_GAME_NAME: minetest_game
jobs:
build:
runs-on: macos-11
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Install deps
@@ -38,7 +33,6 @@ jobs:
- name: Build
run: |
git clone -b $MINETEST_GAME_BRANCH $MINETEST_GAME_REPO games/$MINETEST_GAME_NAME
git clone https://github.com/minetest/irrlicht lib/irrlichtmt --depth 1 -b $(cat misc/irrlichtmt_tag.txt)
mkdir build
cd build
@@ -48,7 +42,7 @@ jobs:
-DCMAKE_INSTALL_PREFIX=../build/macos/ \
-DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE \
-DINSTALL_DEVTEST=TRUE
make -j2
cmake --build . -j$(sysctl -n hw.logicalcpu)
make install
- name: Test

7
.gitignore vendored
View File

@@ -28,10 +28,17 @@ gtags.files
# Visual Studio Code & plugins
.vscode/
build/.cmake/
# Fleet
.fleet
# Gradle
.gradle
# Clang
.cache
# AppImage
*.AppImage
*.zsync
appimage-build
AppDir
## Files related to Minetest development cycle
/*.patch

View File

@@ -9,7 +9,6 @@ stages:
- deploy
variables:
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
.build_template:
@@ -120,8 +119,6 @@ package:appimage-client:
- mkdir AppDir
- cp -a artifact/minetest/usr/ AppDir/usr/
- cp -a clientmods AppDir/usr/share/minetest
- git clone $MINETEST_GAME_REPO AppDir/usr/share/minetest/games/minetest_game
- rm -rf AppDir/usr/share/minetest/games/minetest_game/.git
# Remove PrefersNonDefaultGPU property due to validation errors
- sed -i '/PrefersNonDefaultGPU/d' AppDir/usr/share/applications/net.minetest.minetest.desktop
script:

View File

@@ -70,6 +70,7 @@ files["builtin/mainmenu"] = {
read_globals = {
"PLATFORM",
"TOUCHSCREEN_GUI",
},
}
@@ -80,3 +81,9 @@ files["builtin/common/tests"] = {
"assert",
},
}
files["builtin/fstk"] = {
read_globals = {
"TOUCHSCREEN_GUI",
},
}

View File

@@ -1,25 +1,18 @@
cmake_minimum_required(VERSION 3.5)
# Set policies up to 3.9 since we want to enable the IPO option
if(${CMAKE_VERSION} VERSION_LESS 3.9)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.9)
endif()
cmake_minimum_required(VERSION 3.12)
# This can be read from ${PROJECT_NAME} after project() is called
project(minetest)
set(PROJECT_NAME_CAPITALIZED "Minetest")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(GCC_MINIMUM_VERSION "5.1")
set(CLANG_MINIMUM_VERSION "3.5")
set(GCC_MINIMUM_VERSION "7.5")
set(CLANG_MINIMUM_VERSION "7.0.1")
# You should not need to edit these manually, use util/bump_version.sh
set(VERSION_MAJOR 5)
set(VERSION_MINOR 7)
set(VERSION_PATCH 0)
set(VERSION_MINOR 8)
set(VERSION_PATCH 1)
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
# Change to false for releases
@@ -37,10 +30,20 @@ if (CMAKE_BUILD_TYPE STREQUAL Debug)
set(VERSION_STRING "${VERSION_STRING}-debug")
endif()
message(STATUS "*** Will build version ${VERSION_STRING} ***")
# Configuration options
set(BUILD_CLIENT TRUE CACHE BOOL "Build client")
set(BUILD_SERVER FALSE CACHE BOOL "Build server")
set(BUILD_UNITTESTS TRUE CACHE BOOL "Build unittests")
set(BUILD_BENCHMARKS FALSE CACHE BOOL "Build benchmarks")
set(BUILD_DOCUMENTATION TRUE CACHE BOOL "Build documentation")
set(DEFAULT_ENABLE_LTO TRUE)
# by default don't enable on Debug builds to get faster builds
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(DEFAULT_ENABLE_LTO FALSE)
endif()
set(ENABLE_LTO ${DEFAULT_ENABLE_LTO} CACHE BOOL "Use Link Time Optimization")
set(DEFAULT_RUN_IN_PLACE FALSE)
if(WIN32)
set(DEFAULT_RUN_IN_PLACE TRUE)
@@ -48,11 +51,13 @@ endif()
set(RUN_IN_PLACE ${DEFAULT_RUN_IN_PLACE} CACHE BOOL
"Run directly in source directory structure")
set(BUILD_CLIENT TRUE CACHE BOOL "Build client")
set(BUILD_SERVER FALSE CACHE BOOL "Build server")
set(BUILD_UNITTESTS TRUE CACHE BOOL "Build unittests")
set(BUILD_BENCHMARKS FALSE CACHE BOOL "Build benchmarks")
message(STATUS "*** Will build version ${VERSION_STRING} ***")
message(STATUS "BUILD_CLIENT: " ${BUILD_CLIENT})
message(STATUS "BUILD_SERVER: " ${BUILD_SERVER})
message(STATUS "BUILD_UNITTESTS: " ${BUILD_UNITTESTS})
message(STATUS "BUILD_BENCHMARKS: " ${BUILD_BENCHMARKS})
message(STATUS "BUILD_DOCUMENTATION: " ${BUILD_DOCUMENTATION})
message(STATUS "RUN_IN_PLACE: " ${RUN_IN_PLACE})
set(WARN_ALL TRUE CACHE BOOL "Enable -Wall for Release build")
@@ -61,15 +66,37 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type: Debug or Release" FORCE)
endif()
# FIXME: Windows build fails in multiple places to link, needs to be investigated.
if (ENABLE_LTO AND NOT WIN32)
include(CheckIPOSupported)
check_ipo_supported(RESULT lto_supported OUTPUT lto_output)
if(lto_supported)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
message(STATUS "LTO/IPO is enabled")
else()
message(STATUS "LTO/IPO requested but it is not supported by the compiler: ${lto_output}")
endif()
else()
message(STATUS "LTO/IPO is not enabled")
endif()
set(ENABLE_UPDATE_CHECKER (NOT ${DEVELOPMENT_BUILD}) CACHE BOOL
"Whether to enable update checks by default")
# Included stuff
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
# Load default options for Android
if(ANDROID)
cmake_minimum_required(VERSION 3.20)
include(MinetestAndroidLibs)
endif()
set(IRRLICHTMT_BUILD_DIR "" CACHE PATH "Path to IrrlichtMt build directory.")
if(NOT "${IRRLICHTMT_BUILD_DIR}" STREQUAL "")
if(ANDROID)
# currently manually provided
elseif(NOT "${IRRLICHTMT_BUILD_DIR}" STREQUAL "")
find_package(IrrlichtMt QUIET
PATHS "${IRRLICHTMT_BUILD_DIR}"
NO_DEFAULT_PATH
@@ -120,14 +147,16 @@ else()
endif()
endif()
if(BUILD_CLIENT AND TARGET IrrlichtMt::IrrlichtMt)
if(ANDROID)
# skipped for now
elseif(BUILD_CLIENT AND TARGET IrrlichtMt::IrrlichtMt)
# retrieve version somehow
if(NOT IrrlichtMt_VERSION)
get_target_property(IrrlichtMt_VERSION IrrlichtMt VERSION)
endif()
message(STATUS "Found IrrlichtMt ${IrrlichtMt_VERSION}")
set(TARGET_VER_S 1.9.0mt10)
set(TARGET_VER_S 1.9.0mt13)
string(REPLACE "mt" "." TARGET_VER ${TARGET_VER_S})
if(IrrlichtMt_VERSION VERSION_LESS ${TARGET_VER})
message(FATAL_ERROR "At least IrrlichtMt ${TARGET_VER_S} is required to build")
@@ -247,9 +276,6 @@ if(RUN_IN_PLACE)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/texture_packs_here.txt" DESTINATION "${SHAREDIR}/textures")
endif()
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game" DESTINATION "${SHAREDIR}/games/"
COMPONENT "SUBGAME_MINETEST_GAME" OPTIONAL PATTERN ".git*" EXCLUDE )
set(INSTALL_DEVTEST FALSE CACHE BOOL "Install Development Test")
if(INSTALL_DEVTEST)
@@ -267,11 +293,11 @@ if(BUILD_CLIENT)
endif()
install(FILES "README.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/lua_api.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/client_lua_api.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/menu_lua_api.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/texture_packs.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/world_format.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/lua_api.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/client_lua_api.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/menu_lua_api.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/texture_packs.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "doc/world_format.md" DESTINATION "${DOCDIR}" COMPONENT "Docs")
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
if(UNIX AND NOT APPLE)
@@ -321,16 +347,6 @@ cpack_add_component(Docs
DESCRIPTION "Documentation about Minetest and Minetest modding"
)
cpack_add_component(SUBGAME_MINETEST_GAME
DISPLAY_NAME "Minetest Game"
DESCRIPTION "The default game bundled in the Minetest engine. Mainly used as a modding base."
GROUP "Games"
)
cpack_add_component_group(Subgames
DESCRIPTION "Games for the Minetest engine."
)
if(WIN32)
# Include all dynamically linked runtime libraries such as MSVCRxxx.dll
include(InstallRequiredSystemLibraries)
@@ -384,13 +400,15 @@ include(CPack)
# Add a target to generate API documentation with Doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc
COMMENT "Generating API documentation with Doxygen" VERBATIM
)
if(BUILD_DOCUMENTATION)
find_package(Doxygen)
if(DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc
COMMENT "Generating API documentation with Doxygen" VERBATIM
)
endif()
endif()

1
CNAME Normal file
View File

@@ -0,0 +1 @@
api.minetest.net

View File

@@ -1,7 +1,6 @@
ARG DOCKER_IMAGE=alpine:3.16
FROM $DOCKER_IMAGE AS builder
FROM $DOCKER_IMAGE AS dev
ENV MINETEST_GAME_VERSION master
ENV IRRLICHT_VERSION master
ENV SPATIALINDEX_VERSION 1.9.3
ENV LUAJIT_VERSION v2.1
@@ -35,6 +34,8 @@ RUN git clone --recursive https://github.com/jupp0r/prometheus-cpp/ && \
git clone --depth=1 https://github.com/minetest/irrlicht/ -b ${IRRLICHT_VERSION} && \
cp -r irrlicht/include /usr/include/irrlichtmt
FROM dev as builder
COPY .git /usr/src/minetest/.git
COPY CMakeLists.txt /usr/src/minetest/CMakeLists.txt
COPY README.md /usr/src/minetest/README.md
@@ -50,18 +51,16 @@ COPY src /usr/src/minetest/src
COPY textures /usr/src/minetest/textures
WORKDIR /usr/src/minetest
RUN git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \
rm -fr ./games/minetest_game/.git && \
cmake -B build \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SERVER=TRUE \
-DENABLE_PROMETHEUS=TRUE \
-DBUILD_UNITTESTS=FALSE \
-DBUILD_CLIENT=FALSE \
-GNinja && \
cmake --build build && \
cmake --install build
RUN cmake -B build \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SERVER=TRUE \
-DENABLE_PROMETHEUS=TRUE \
-DBUILD_UNITTESTS=FALSE \
-DBUILD_CLIENT=FALSE \
-GNinja && \
cmake --build build && \
cmake --install build
ARG DOCKER_IMAGE=alpine:3.16
FROM $DOCKER_IMAGE AS runtime

View File

@@ -61,7 +61,11 @@ Zughy:
textures/base/pack/cdb_downloading.png
textures/base/pack/cdb_queued.png
textures/base/pack/cdb_update.png
textures/base/pack/cdb_update_cropped.png
textures/base/pack/cdb_viewonline.png
textures/base/pack/settings_btn.png
textures/base/pack/settings_info.png
textures/base/pack/settings_reset.png
appgurueu:
textures/base/pack/server_incompatible.png
@@ -71,15 +75,23 @@ erlehmann, Warr1024, rollerozxa:
kilbith:
textures/base/pack/server_favorite.png
textures/base/pack/progress_bar.png
textures/base/pack/progress_bar_bg.png
SmallJoker:
textures/base/pack/cdb_clear.png
textures/base/pack/server_favorite_delete.png (based on server_favorite.png)
DS:
games/devtest/mods/soundstuff/textures/soundstuff_bigfoot.png
games/devtest/mods/soundstuff/textures/soundstuff_jukebox.png
games/devtest/mods/soundstuff/textures/soundstuff_racecar.png
games/devtest/mods/soundstuff/sounds/soundstuff_sinus.ogg
games/devtest/mods/testtools/textures/testtools_branding_iron.png
grorp:
textures/base/pack/exit_btn.png
License of Minetest source code
-------------------------------

334
README.md
View File

@@ -10,12 +10,6 @@ Minetest is a free open-source voxel game engine with easy modding and game crea
Copyright (C) 2010-2022 Perttu Ahola <celeron55@gmail.com>
and contributors (see source file comments and the version control log)
In case you downloaded the source code
--------------------------------------
If you downloaded the Minetest Engine source code in which this file is
contained, you probably want to download the [Minetest Game](https://github.com/minetest/minetest_game/)
project too. See its README.txt for more information.
Table of Contents
------------------
@@ -51,7 +45,7 @@ Some can be changed in the key config dialog in the settings tab.
| Shift | Sneak/move down |
| Q | Drop itemstack |
| Shift + Q | Drop single item |
| Left mouse button | Dig/punch/take item |
| Left mouse button | Dig/punch/use |
| Right mouse button | Place/use |
| Shift + right mouse button | Build (without using) |
| I | Inventory menu |
@@ -124,330 +118,16 @@ Command-line options
Compiling
---------
### Compiling on GNU/Linux
#### Dependencies
| Dependency | Version | Commentary |
|------------|---------|------------|
| GCC | 5.1+ | or Clang 3.5+ |
| CMake | 3.5+ | |
| IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
| Freetype | 2.0+ | |
| SQLite3 | 3+ | |
| Zstd | 1.0+ | |
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present |
For Debian/Ubuntu users:
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev
For Fedora users:
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel
For Arch users:
sudo pacman -S base-devel libcurl-gnutls cmake libxi libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd
For Alpine users:
sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev
#### Download
You can install Git for easily keeping your copy up to date.
If you dont want Git, read below on how to get the source without Git.
This is an example for installing Git on Debian/Ubuntu:
sudo apt install git
For Fedora users:
sudo dnf install git
For Arch users:
sudo pacman -S git
For Alpine users:
sudo apk add 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
cd minetest
Download Minetest Game (otherwise only the "Development Test" game is available) using Git:
git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
Download IrrlichtMt to `lib/irrlichtmt`, it will be used to satisfy the IrrlichtMt dependency that way:
git clone --depth 1 https://github.com/minetest/irrlicht.git lib/irrlichtmt
Download source, without using Git:
wget https://github.com/minetest/minetest/archive/master.tar.gz
tar xf master.tar.gz
cd minetest-master
Download Minetest Game, without using Git:
cd games/
wget https://github.com/minetest/minetest_game/archive/master.tar.gz
tar xf master.tar.gz
mv minetest_game-master minetest_game
cd ..
Download IrrlichtMt, without using Git:
cd lib/
wget https://github.com/minetest/irrlicht/archive/master.tar.gz
tar xf master.tar.gz
mv irrlicht-master irrlichtmt
cd ..
#### Build
Build a version that runs directly from the source directory:
cmake . -DRUN_IN_PLACE=TRUE
make -j$(nproc)
Run it:
./bin/minetest
- 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),
you will want to use `-DRUN_IN_PLACE=FALSE`.
- You can build a bare server by specifying `-DBUILD_SERVER=TRUE`.
- You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`.
- You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`.
- Debug build is slower, but gives much more useful output in a debugger.
- If you build a bare server you don't need to compile IrrlichtMt, just the headers suffice.
- In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlichtmt/include`.
- Minetest will use the IrrlichtMt package that is found first, given by the following order:
1. Specified `IRRLICHTMT_BUILD_DIR` CMake variable
2. `${PROJECT_SOURCE_DIR}/lib/irrlichtmt` (if existent)
3. Installation of IrrlichtMt in the system-specific library paths
4. For server builds with disabled `BUILD_CLIENT` variable, the headers from `IRRLICHT_INCLUDE_DIR` will be used.
- NOTE: Changing the IrrlichtMt build directory (includes system installs) requires regenerating the CMake cache (`rm CMakeCache.txt`)
### CMake options
General options and their default values:
BUILD_CLIENT=TRUE - Build Minetest client
BUILD_SERVER=FALSE - Build Minetest server
BUILD_UNITTESTS=TRUE - Build unittest sources
BUILD_BENCHMARKS=FALSE - Build benchmark sources
CMAKE_BUILD_TYPE=Release - Type of build (Release vs. Debug)
Release - Release build
Debug - Debug build
SemiDebug - Partially optimized debug build
RelWithDebInfo - Release build with debug information
MinSizeRel - Release build with -Os passed to compiler to make executable as small as possible
ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations
ENABLE_GLES=OFF - Enable extra support code for OpenGL ES (requires support by IrrlichtMt)
ENABLE_LEVELDB=ON - Build with LevelDB; Enables use of LevelDB map backend
ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended)
ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend
ENABLE_SPATIAL=ON - Build with LibSpatial; Speeds up AreaStores
ENABLE_SOUND=ON - Build with OpenAL, libogg & libvorbis; in-game sounds
ENABLE_LUAJIT=ON - Build with LuaJIT (much faster than non-JIT Lua)
ENABLE_PROMETHEUS=OFF - Build with Prometheus metrics exporter (listens on tcp/30000 by default)
ENABLE_SYSTEM_GMP=ON - Use GMP from system (much faster than bundled mini-gmp)
ENABLE_SYSTEM_JSONCPP=ON - Use JsonCPP from system
RUN_IN_PLACE=FALSE - Create a portable install (worlds, settings etc. in current directory)
ENABLE_UPDATE_CHECKER=TRUE - Whether to enable update checks by default
INSTALL_DEVTEST=FALSE - Whether the Development Test game should be installed alongside Minetest
USE_GPROF=FALSE - Enable profiling using GProf
VERSION_EXTRA= - Text to append to version (e.g. VERSION_EXTRA=foobar -> Minetest 0.4.9-foobar)
ENABLE_TOUCH=FALSE - Enable Touchscreen support (requires support by IrrlichtMt)
Library specific options:
CURL_DLL - Only if building with cURL on Windows; path to libcurl.dll
CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located
CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib
EGL_INCLUDE_DIR - Only if building with GLES; directory that contains egl.h
EGL_LIBRARY - Only if building with GLES; path to libEGL.a/libEGL.so
EXTRA_DLL - Only on Windows; optional paths to additional DLLs that should be packaged
FREETYPE_INCLUDE_DIR_freetype2 - Directory that contains files such as ftimage.h
FREETYPE_INCLUDE_DIR_ft2build - Directory that contains ft2build.h
FREETYPE_LIBRARY - Path to libfreetype.a/libfreetype.so/freetype.lib
FREETYPE_DLL - Only on Windows; path to libfreetype-6.dll
GETTEXT_DLL - Only when building with gettext on Windows; paths to libintl + libiconv DLLs
GETTEXT_INCLUDE_DIR - Only when building with gettext; directory that contains libintl.h
GETTEXT_LIBRARY - Optional/platform-dependent with gettext; path to libintl.so/libintl.dll.a
GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe
ICONV_LIBRARY - Optional/platform-dependent; path to libiconv.so/libiconv.dylib
IRRLICHT_DLL - Only on Windows; path to IrrlichtMt.dll
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h (usable for server build only)
LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h
LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll
PostgreSQL_INCLUDE_DIR - Only when building with PostgreSQL; directory that contains libpq-fe.h
PostgreSQL_LIBRARY - Only when building with PostgreSQL; path to libpq.a/libpq.so/libpq.lib
REDIS_INCLUDE_DIR - Only when building with Redis; directory that contains hiredis.h
REDIS_LIBRARY - Only when building with Redis; path to libhiredis.a/libhiredis.so
SPATIAL_INCLUDE_DIR - Only when building with LibSpatial; directory that contains spatialindex/SpatialIndex.h
SPATIAL_LIBRARY - Only when building with LibSpatial; path to libspatialindex.so/spatialindex-32.lib
LUA_INCLUDE_DIR - Only if you want to use LuaJIT; directory where luajit.h is located
LUA_LIBRARY - Only if you want to use LuaJIT; path to libluajit.a/libluajit.so
OGG_DLL - Only if building with sound on Windows; path to libogg.dll
OGG_INCLUDE_DIR - Only if building with sound; directory that contains an ogg directory which contains ogg.h
OGG_LIBRARY - Only if building with sound; path to libogg.a/libogg.so/libogg.dll.a
OPENAL_DLL - Only if building with sound on Windows; path to OpenAL32.dll
OPENAL_INCLUDE_DIR - Only if building with sound; directory where al.h is located
OPENAL_LIBRARY - Only if building with sound; path to libopenal.a/libopenal.so/OpenAL32.lib
SQLITE3_INCLUDE_DIR - Directory that contains sqlite3.h
SQLITE3_LIBRARY - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib
VORBISFILE_LIBRARY - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a
VORBIS_DLL - Only if building with sound on Windows; paths to vorbis DLLs
VORBIS_INCLUDE_DIR - Only if building with sound; directory that contains a directory vorbis with vorbisenc.h inside
VORBIS_LIBRARY - Only if building with sound; path to libvorbis.a/libvorbis.so/libvorbis.dll.a
ZLIB_DLL - Only on Windows; path to zlib1.dll
ZLIB_INCLUDE_DIR - Directory that contains zlib.h
ZLIB_LIBRARY - Path to libz.a/libz.so/zlib.lib
ZSTD_DLL - Only on Windows; path to libzstd.dll
ZSTD_INCLUDE_DIR - Directory that contains zstd.h
ZSTD_LIBRARY - Path to libzstd.a/libzstd.so/ztd.lib
### Compiling on Windows using MSVC
### Requirements
- [Visual Studio 2015 or newer](https://visualstudio.microsoft.com)
- [CMake](https://cmake.org/download/)
- [vcpkg](https://github.com/Microsoft/vcpkg)
- [Git](https://git-scm.com/downloads)
### Compiling and installing the dependencies
It is highly recommended to use vcpkg as package manager.
After you successfully built vcpkg you can easily install the required libraries:
```powershell
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry --triplet x64-windows
```
- **Don't forget about IrrlichtMt.** The easiest way is to clone it to `lib/irrlichtmt` as described in the Linux section.
- `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store.
- `openal-soft`, `libvorbis` and `libogg` are optional, but required to use sound.
- `luajit` is optional, it replaces the integrated Lua interpreter with a faster just-in-time interpreter.
- `gmp` and `jsoncpp` are optional, otherwise the bundled versions will be compiled
There are other optional libraries, but they are not tested if they can build and link correctly.
Use `--triplet` to specify the target triplet, e.g. `x64-windows` or `x86-windows`.
### Compile Minetest
#### a) Using the vcpkg toolchain and CMake GUI
1. Start up the CMake GUI
2. Select **Browse Source...** and select DIR/minetest
3. Select **Browse Build...** and select DIR/minetest-build
4. Select **Configure**
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**
7. Click **Next**
8. Select the vcpkg toolchain file e.g. `D:/vcpkg/scripts/buildsystems/vcpkg.cmake`
9. Click Finish
10. Wait until cmake have generated the cash file
11. If there are any errors, solve them and hit **Configure**
12. Click **Generate**
13. Click **Open Project**
14. Compile Minetest inside Visual studio.
#### b) Using the vcpkg toolchain and the commandline
Run the following script in PowerShell:
```powershell
cmake . -G"Visual Studio 15 2017 Win64" -DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_GETTEXT=OFF -DENABLE_CURSES=OFF
cmake --build . --config Release
```
Make sure that the right compiler is selected and the path to the vcpkg toolchain is correct.
### Windows Installer using WiX Toolset
Requirements:
* [Visual Studio 2017](https://visualstudio.microsoft.com/)
* [WiX Toolset](https://wixtoolset.org/)
In the Visual Studio 2017 Installer select **Optional Features -> WiX Toolset**.
Build the binaries as described above, but make sure you unselect `RUN_IN_PLACE`.
Open the generated project file with Visual Studio. Right-click **Package** and choose **Generate**.
It may take some minutes to generate the installer.
### Compiling on MacOS
#### Requirements
- [Homebrew](https://brew.sh/)
- [Git](https://git-scm.com/downloads)
Install dependencies with homebrew:
```
brew install cmake freetype gettext gmp hiredis jpeg jsoncpp leveldb libogg libpng libvorbis luajit zstd
```
#### Download
Download source (this is the URL to the latest of source repository, which might not work at all times) using Git:
```bash
git clone --depth 1 https://github.com/minetest/minetest.git
cd minetest
```
Download Minetest Game (otherwise only the "Development Test" game is available) using Git:
```
git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
```
Download Minetest's fork of Irrlicht:
```
git clone --depth 1 https://github.com/minetest/irrlicht.git lib/irrlichtmt
```
#### Build
```bash
mkdir build
cd build
cmake .. \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14 \
-DCMAKE_FIND_FRAMEWORK=LAST \
-DCMAKE_INSTALL_PREFIX=../build/macos/ \
-DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE
make -j$(sysctl -n hw.logicalcpu)
make install
```
#### Run
```
open ./build/macos/minetest.app
```
- [Compiling on GNU/Linux](doc/compiling/linux.md)
- [Compiling on Windows](doc/compiling/windows.md)
- [Compiling on MacOS](doc/compiling/macos.md)
Docker
------
- [Developing minetestserver with Docker](doc/developing/docker.md)
We provide Minetest server Docker images using the GitLab mirror registry.
Images are built on each commit and available using the following tag scheme:

View File

@@ -54,7 +54,9 @@ android {
task prepareAssets() {
def assetsFolder = "build/assets"
def projRoot = rootDir.parent
def gameToCopy = "minetest_game"
// See issue #4638
def unsupportedLanguages = new File("${projRoot}/src/unsupported_language_list.txt").text.readLines()
doFirst {
logger.lifecycle('Preparing assets at {}', assetsFolder)
@@ -79,14 +81,13 @@ task prepareAssets() {
from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts"
}
copy {
from "${projRoot}/games/${gameToCopy}" into "${assetsFolder}/games/${gameToCopy}"
}
copy {
from "${projRoot}/textures" into "${assetsFolder}/textures"
from "${projRoot}/textures/base/pack" into "${assetsFolder}/textures/base/pack"
}
// compile translations
fileTree("${projRoot}/po").include("**/*.po").forEach { poFile ->
fileTree("${projRoot}/po").include("**/*.po").grep {
it.parentFile.name !in unsupportedLanguages
}.forEach { poFile ->
def moPath = "${assetsFolder}/locale/${poFile.parentFile.name}/LC_MESSAGES/"
file(moPath).mkdirs()
exec {

View File

@@ -5,20 +5,13 @@
android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-feature android:glEsVersion="0x00020000" />
<!--
`android:requestLegacyExternalStorage="true"` is workaround for using `/sdcard`
instead of the `getFilesDir()` patch for assets. Check link below for more information:
https://developer.android.com/training/data-storage/compatibility
-->
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/label"
android:requestLegacyExternalStorage="true"
android:resizeableActivity="false"
tools:ignore="UnusedAttribute">
@@ -53,7 +46,7 @@
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="Minetest" />
android:value="minetest" />
</activity>
<service

View File

@@ -2,6 +2,8 @@
Minetest
Copyright (C) 2014-2020 MoNTE48, Maksim Gamarnik <MoNTE48@mail.ua>
Copyright (C) 2014-2020 ubulem, Bektur Mambetov <berkut87@gmail.com>
Copyright (C) 2023 srifqi, Muhammad Rifqi Priyo Susanto
<muhammadrifqipriyosusanto@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -29,17 +31,52 @@ import androidx.appcompat.widget.AppCompatEditText;
import java.util.Objects;
public class CustomEditText extends AppCompatEditText {
private int editType = 2; // single line text input as default
private boolean wantsToShowKeyboard = false;
public CustomEditText(Context context) {
super(context);
}
public CustomEditText(Context context, int _editType) {
super(context);
editType = _editType;
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// For multi-line, do not close the dialog after pressing back button
if (editType != 1 && keyCode == KeyEvent.KEYCODE_BACK) {
InputMethodManager mgr = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
Objects.requireNonNull(mgr).hideSoftInputFromWindow(this.getWindowToken(), 0);
}
return false;
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
tryShowKeyboard();
}
public void requestFocusTryShow() {
requestFocus();
wantsToShowKeyboard = true;
tryShowKeyboard();
}
private void tryShowKeyboard() {
if (hasWindowFocus() && wantsToShowKeyboard) {
if (isFocused()) {
CustomEditText that = this;
post(() -> {
final InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(that, 0);
});
}
wantsToShowKeyboard = false;
}
}
}

View File

@@ -23,7 +23,6 @@ package net.minetest.minetest;
import android.app.NativeActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
@@ -32,7 +31,6 @@ import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import androidx.annotation.Keep;
@@ -40,6 +38,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.Locale;
import java.util.Objects;
// Native code finds these methods by name (see porting_android.cpp).
@@ -49,14 +48,12 @@ import java.util.Objects;
public class GameActivity extends NativeActivity {
static {
System.loadLibrary("c++_shared");
System.loadLibrary("Minetest");
System.loadLibrary("minetest");
}
private int messageReturnCode = -1;
private String messageReturnValue = "";
public static native void putMessageBoxResult(String text);
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -64,11 +61,10 @@ public class GameActivity extends NativeActivity {
}
private void makeFullScreen() {
if (Build.VERSION.SDK_INT >= 19)
this.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
this.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
@Override
@@ -84,6 +80,17 @@ public class GameActivity extends NativeActivity {
makeFullScreen();
}
private native void saveSettings();
@Override
protected void onStop() {
super.onStop();
// Avoid losing setting changes in case the app is onDestroy()ed later.
// Saving stuff in onStop() is recommended in the Android activity
// lifecycle documentation.
saveSettings();
}
@Override
public void onBackPressed() {
// Ignore the back press so Minetest can handle it
@@ -99,21 +106,11 @@ public class GameActivity extends NativeActivity {
container.setOrientation(LinearLayout.VERTICAL);
builder.setView(container);
AlertDialog alertDialog = builder.create();
EditText editText;
// For multi-line, do not close the dialog after pressing back button
if (editType == 1) {
editText = new EditText(this);
} else {
editText = new CustomEditText(this);
}
CustomEditText editText = new CustomEditText(this, editType);
container.addView(editText);
editText.setMaxLines(8);
editText.requestFocus();
editText.setHint(hint);
editText.setText(current);
final InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
Objects.requireNonNull(imm).toggleSoftInput(InputMethodManager.SHOW_FORCED,
InputMethodManager.HIDE_IMPLICIT_ONLY);
if (editType == 1)
editText.setInputType(InputType.TYPE_CLASS_TEXT |
InputType.TYPE_TEXT_FLAG_MULTI_LINE);
@@ -122,7 +119,8 @@ public class GameActivity extends NativeActivity {
InputType.TYPE_TEXT_VARIATION_PASSWORD);
else
editText.setInputType(InputType.TYPE_CLASS_TEXT);
editText.setSelection(editText.getText().length());
editText.setSelection(Objects.requireNonNull(editText.getText()).length());
final InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
editText.setOnKeyListener((view, keyCode, event) -> {
// For multi-line, do not submit the text after pressing Enter key
if (keyCode == KeyEvent.KEYCODE_ENTER && editType != 1) {
@@ -146,12 +144,13 @@ public class GameActivity extends NativeActivity {
alertDialog.dismiss();
}));
}
alertDialog.show();
alertDialog.setOnCancelListener(dialog -> {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
messageReturnValue = current;
messageReturnCode = -1;
});
alertDialog.show();
editText.requestFocusTryShow();
}
public int getDialogState() {
@@ -205,4 +204,28 @@ public class GameActivity extends NativeActivity {
Intent shareIntent = Intent.createChooser(intent, null);
startActivity(shareIntent);
}
public String getLanguage() {
String langCode = Locale.getDefault().getLanguage();
// getLanguage() still uses old language codes to preserve compatibility.
// List of code changes in ISO 639-2:
// https://www.loc.gov/standards/iso639-2/php/code_changes.php
switch (langCode) {
case "in":
langCode = "id"; // Indonesian
break;
case "iw":
langCode = "he"; // Hebrew
break;
case "ji":
langCode = "yi"; // Yiddish
break;
case "jw":
langCode = "jv"; // Javanese
break;
}
return langCode;
}
}

View File

@@ -20,38 +20,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
package net.minetest.minetest;
import android.Manifest;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static net.minetest.minetest.UnzipService.*;
public class MainActivity extends AppCompatActivity {
public static final String NOTIFICATION_CHANNEL_ID = "Minetest channel";
private final static int versionCode = BuildConfig.VERSION_CODE;
private final static int PERMISSIONS = 1;
private static final String[] REQUIRED_SDK_PERMISSIONS =
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
private static final String SETTINGS = "MinetestSettings";
private static final String TAG_VERSION_CODE = "versionCode";
@@ -95,63 +87,21 @@ public class MainActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter(ACTION_UPDATE);
registerReceiver(myReceiver, filter);
mProgressBar = findViewById(R.id.progressBar);
mTextView = findViewById(R.id.textView);
sharedPreferences = getSharedPreferences(SETTINGS, Context.MODE_PRIVATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
checkPermission();
else
checkAppVersion();
}
checkAppVersion();
private void checkPermission() {
final List<String> missingPermissions = new ArrayList<>();
for (final String permission : REQUIRED_SDK_PERMISSIONS) {
final int result = ContextCompat.checkSelfPermission(this, permission);
if (result != PackageManager.PERMISSION_GRANTED)
missingPermissions.add(permission);
}
if (!missingPermissions.isEmpty()) {
final String[] permissions = missingPermissions
.toArray(new String[0]);
ActivityCompat.requestPermissions(this, permissions, PERMISSIONS);
} else {
final int[] grantResults = new int[REQUIRED_SDK_PERMISSIONS.length];
Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
onRequestPermissionsResult(PERMISSIONS, REQUIRED_SDK_PERMISSIONS, grantResults);
}
}
@Override
public void onRequestPermissionsResult(
int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSIONS) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, R.string.not_granted, Toast.LENGTH_LONG).show();
finish();
return;
}
}
checkAppVersion();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
createNotificationChannel();
}
private void checkAppVersion() {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(this, R.string.no_external_storage, Toast.LENGTH_LONG).show();
finish();
return;
}
if (UnzipService.getIsRunning()) {
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setIndeterminate(true);
@@ -176,6 +126,28 @@ public class MainActivity extends AppCompatActivity {
startActivity(intent);
}
@RequiresApi(Build.VERSION_CODES.O)
private void createNotificationChannel() {
NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notifyManager == null)
return;
NotificationChannel notifyChannel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID,
getString(R.string.notification_channel_name),
NotificationManager.IMPORTANCE_LOW
);
notifyChannel.setDescription(getString(R.string.notification_channel_description));
// Configure the notification channel without sound set
notifyChannel.setSound(null, null);
notifyChannel.enableLights(false);
notifyChannel.enableVibration(false);
// It is fine to always create the notification channel because creating a channel
// with the same ID is the same as overriding it (only its name and description).
notifyManager.createNotificationChannel(notifyChannel);
}
@Override
public void onBackPressed() {
// Prevent abrupt interruption when copy game files from assets

View File

@@ -22,13 +22,11 @@ package net.minetest.minetest;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -59,9 +57,11 @@ public class UnzipService extends IntentService {
private String failureMessage;
private static boolean isRunning = false;
public static synchronized boolean getIsRunning() {
return isRunning;
}
private static synchronized void setIsRunning(boolean v) {
isRunning = v;
}
@@ -88,7 +88,6 @@ public class UnzipService extends IntentService {
}
}
migrate(notificationBuilder, userDataDirectory);
unzip(notificationBuilder, zipFile, userDataDirectory);
} catch (IOException e) {
isSuccess = false;
@@ -101,28 +100,13 @@ public class UnzipService extends IntentService {
}
}
@NonNull
private Notification.Builder createNotification() {
String name = "net.minetest.minetest";
String channelId = "Minetest channel";
String description = "notifications from Minetest";
Notification.Builder builder;
if (mNotifyManager == null)
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = null;
if (mNotifyManager != null)
mChannel = mNotifyManager.getNotificationChannel(channelId);
if (mChannel == null) {
mChannel = new NotificationChannel(channelId, name, importance);
mChannel.setDescription(description);
// Configure the notification channel, NO SOUND
mChannel.setSound(null, null);
mChannel.enableLights(false);
mChannel.enableVibration(false);
mNotifyManager.createNotificationChannel(mChannel);
}
builder = new Notification.Builder(this, channelId);
builder = new Notification.Builder(this, MainActivity.NOTIFICATION_CHANNEL_ID);
} else {
builder = new Notification.Builder(this);
}
@@ -137,9 +121,9 @@ public class UnzipService extends IntentService {
PendingIntent intent = PendingIntent.getActivity(this, 0,
notificationIntent, pendingIntentFlag);
builder.setContentTitle(getString(R.string.notification_title))
builder.setContentTitle(getString(R.string.unzip_notification_title))
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(getString(R.string.notification_description))
.setContentText(getString(R.string.unzip_notification_description))
.setContentIntent(intent)
.setOngoing(true)
.setProgress(0, 0, true);
@@ -182,9 +166,9 @@ public class UnzipService extends IntentService {
try {
Process p = new ProcessBuilder("/system/bin/mv",
src.getAbsolutePath(), dst.getAbsolutePath()).start();
int exitcode = p.waitFor();
if (exitcode != 0)
throw new IOException("Move failed with exit code " + exitcode);
int exitCode = p.waitFor();
if (exitCode != 0)
throw new IOException("Move failed with exit code " + exitCode);
} catch (InterruptedException e) {
throw new IOException("Move operation interrupted");
}
@@ -200,45 +184,7 @@ public class UnzipService extends IntentService {
}
}
/**
* Migrates user data from deprecated external storage to app scoped storage
*/
private void migrate(Notification.Builder notificationBuilder, File newLocation) throws IOException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return;
}
File oldLocation = new File(Environment.getExternalStorageDirectory(), "Minetest");
if (!oldLocation.isDirectory())
return;
publishProgress(notificationBuilder, R.string.migrating, 0);
if (!newLocation.mkdir()) {
Log.e("UnzipService", "New installation folder cannot be made");
}
String[] dirs = new String[] { "worlds", "games", "mods", "textures", "client" };
for (int i = 0; i < dirs.length; i++) {
publishProgress(notificationBuilder, R.string.migrating, 100 * i / dirs.length);
File dir = new File(oldLocation, dirs[i]), dir2 = new File(newLocation, dirs[i]);
if (dir.isDirectory() && !dir2.isDirectory()) {
moveFileOrDir(dir, dir2);
}
}
for (String filename : new String[] { "minetest.conf" }) {
File file = new File(oldLocation, filename), file2 = new File(newLocation, filename);
if (file.isFile() && !file2.isFile()) {
moveFileOrDir(file, file2);
}
}
if (!recursivelyDeleteDirectory(oldLocation)) {
Log.w("UnzipService", "Old installation files cannot be deleted successfully");
}
}
private void publishProgress(@Nullable Notification.Builder notificationBuilder, @StringRes int message, int progress) {
private void publishProgress(@Nullable Notification.Builder notificationBuilder, @StringRes int message, int progress) {
Intent intentUpdate = new Intent(ACTION_UPDATE);
intentUpdate.putExtra(ACTION_PROGRESS, progress);
intentUpdate.putExtra(ACTION_PROGRESS_MESSAGE, message);

View File

@@ -38,7 +38,6 @@ public class Utils {
public static boolean isInstallValid(@NonNull Context context) {
File userDataDirectory = getUserDataDirectory(context);
return userDataDirectory.isDirectory() &&
new File(userDataDirectory, "games").isDirectory() &&
new File(userDataDirectory, "builtin").isDirectory() &&
new File(userDataDirectory, "client").isDirectory() &&
new File(userDataDirectory, "textures").isDirectory();

View File

@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="label">Minetest</string>
<string name="loading">Loading&#8230;</string>
<string name="migrating">Migrating save data from old install&#8230; (this may take a while)</string>
<string name="not_granted">Required permission wasn\'t granted, Minetest can\'t run without it</string>
<string name="notification_title">Loading Minetest</string>
<string name="notification_description">Less than 1 minute&#8230;</string>
<string name="notification_channel_name">General notification</string>
<string name="notification_channel_description">Notifications from Minetest</string>
<string name="unzip_notification_title">Loading Minetest</string>
<string name="unzip_notification_description">Less than 1 minute&#8230;</string>
<string name="ime_dialog_done">Done</string>
<string name="no_external_storage">External storage isn\'t available. If you use an SDCard, please reinsert it. Otherwise, try restarting your phone or contacting the Minetest developers</string>
</resources>

View File

@@ -1,11 +1,10 @@
// 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("versionMinor", 7) // Version Minor
project.ext.set("versionPatch", 0) // Version Patch
project.ext.set("versionExtra", "") // Version Extra
project.ext.set("versionCode", 44) // Android Version Code
project.ext.set("developmentBuild", 0) // Whether it is a development build, or a release
project.ext.set("versionMinor", 8) // Version Minor
project.ext.set("versionPatch", 1) // Version Patch
// ^ keep in sync with cmake
project.ext.set("versionCode", 48) // Android Version Code
// NOTE: +2 after each release!
// +1 for ARM and +1 for ARM64 APK's, because
// each APK must have a larger `versionCode` than the previous

View File

@@ -7,5 +7,5 @@ org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.parallel.threads=8
org.gradle.configureondemand=true
android.enableJetifier=true
android.enableJetifier=false
android.useAndroidX=true

111
android/icons/exit_btn.svg Normal file
View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 135.46666 135.46667"
version="1.1"
id="svg8"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
sodipodi:docname="exit_btn.svg"
inkscape:export-filename="../../textures/base/pack/exit_btn.png"
inkscape:export-xdpi="24.000002"
inkscape:export-ydpi="24.000002"
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="defs10" />
<sodipodi:namedview
id="base"
pagecolor="#404040"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.84958349"
inkscape:cx="-94.752312"
inkscape:cy="291.31922"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1001"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="false"
inkscape:snap-grids="true"
inkscape:snap-page="true"
showguides="false"
inkscape:showpageshadow="2"
inkscape:deskcolor="#404040">
<inkscape:grid
type="xygrid"
id="grid16"
spacingx="0.26458333"
spacingy="0.26458333"
empspacing="4"
color="#40ff40"
opacity="0.1254902"
empcolor="#40ff40"
empopacity="0.25098039" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2"
style="display:inline">
<path
id="rect5028"
style="display:inline;fill:none;stroke:#ffffff;stroke-width:5.99996;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
d="m 78.052082,90.48746 v 17.4625 l -50.535415,4e-5 V 27.516667 l 50.535415,3.7e-5 v 17.462423"
sodipodi:nodetypes="cccccc" />
<path
style="display:inline;fill:none;stroke:#ffffff;stroke-width:5.99996;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 101.49853,55.033202 12.69966,12.700052 -12.69966,12.699942"
id="path4737"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="display:inline;fill:none;stroke:#ffffff;stroke-width:6;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 113.36416,67.733332 H 59.484405"
id="path4729"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -9,20 +9,18 @@ android {
minSdkVersion 21
targetSdkVersion 33
externalNativeBuild {
ndkBuild {
arguments '-j' + Runtime.getRuntime().availableProcessors(),
"versionMajor=${versionMajor}",
"versionMinor=${versionMinor}",
"versionPatch=${versionPatch}",
"versionExtra=${versionExtra}",
"developmentBuild=${developmentBuild}"
cmake {
arguments "-DANDROID_STL=c++_shared",
"-DENABLE_CURL=1", "-DENABLE_SOUND=1",
"-DENABLE_TOUCH=1", "-DENABLE_GETTEXT=1",
"-DBUILD_UNITTESTS=0", "-DENABLE_UPDATE_CHECKER=0"
}
}
}
externalNativeBuild {
ndkBuild {
path file('jni/Android.mk')
cmake {
path file("../../CMakeLists.txt")
}
}
@@ -37,12 +35,6 @@ android {
buildTypes {
release {
externalNativeBuild {
ndkBuild {
arguments 'NDEBUG=1'
}
}
ndk {
debugSymbolLevel 'SYMBOL_TABLE'
}
@@ -51,19 +43,25 @@ android {
}
// get precompiled deps
task downloadDeps(type: Download) {
def depsDir = new File(buildDir.parent, 'deps')
def depsZip = new File(buildDir, 'deps.zip')
def depsDir = new File(buildDir.parent, 'deps')
if (new File(depsDir, 'armeabi-v7a').exists()) {
task getDeps {
doLast { logger.lifecycle('Using existing deps from {}', depsDir) }
}
} else {
task downloadDeps(type: Download) {
def depsZip = new File(buildDir, 'deps.zip')
src 'https://github.com/minetest/minetest_android_deps/releases/download/latest/deps.zip'
dest depsZip
overwrite false
src 'https://github.com/minetest/minetest_android_deps/releases/download/5.8.0/deps.zip'
dest depsZip
overwrite false
task getDeps(dependsOn: downloadDeps, type: Copy) {
depsDir.mkdir()
from zipTree(depsZip)
into depsDir
doFirst { logger.lifecycle('Extracting to {}', depsDir) }
task getDeps(dependsOn: downloadDeps, type: Copy) {
depsDir.mkdir()
from zipTree(depsZip)
into depsDir
doFirst { logger.lifecycle('Extracting to {}', depsDir) }
}
}
}

View File

@@ -1,302 +0,0 @@
LOCAL_PATH := $(call my-dir)/..
#LOCAL_ADDRESS_SANITIZER:=true
#USE_BUILTIN_LUA:=true
include $(CLEAR_VARS)
LOCAL_MODULE := Curl
LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libcurl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libmbedcrypto
LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libmbedcrypto.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libmbedtls
LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libmbedtls.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libmbedx509
LOCAL_SRC_FILES := deps/$(APP_ABI)/Curl/libmbedx509.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Freetype
LOCAL_SRC_FILES := deps/$(APP_ABI)/Freetype/libfreetype.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Iconv
LOCAL_SRC_FILES := deps/$(APP_ABI)/Iconv/libiconv.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcharset
LOCAL_SRC_FILES := deps/$(APP_ABI)/Iconv/libcharset.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Irrlicht
LOCAL_SRC_FILES := deps/$(APP_ABI)/Irrlicht/libIrrlichtMt.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Irrlicht-libpng
LOCAL_SRC_FILES := deps/$(APP_ABI)/Irrlicht/libpng.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Irrlicht-libjpeg
LOCAL_SRC_FILES := deps/$(APP_ABI)/Irrlicht/libjpeg.a
include $(PREBUILT_STATIC_LIBRARY)
ifndef USE_BUILTIN_LUA
include $(CLEAR_VARS)
LOCAL_MODULE := LuaJIT
LOCAL_SRC_FILES := deps/$(APP_ABI)/LuaJIT/libluajit.a
include $(PREBUILT_STATIC_LIBRARY)
endif
include $(CLEAR_VARS)
LOCAL_MODULE := OpenAL
LOCAL_SRC_FILES := deps/$(APP_ABI)/OpenAL-Soft/libopenal.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Gettext
LOCAL_SRC_FILES := deps/$(APP_ABI)/Gettext/libintl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := SQLite3
LOCAL_SRC_FILES := deps/$(APP_ABI)/SQLite/libsqlite3.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Vorbis
LOCAL_SRC_FILES := deps/$(APP_ABI)/Vorbis/libvorbis.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libvorbisfile
LOCAL_SRC_FILES := deps/$(APP_ABI)/Vorbis/libvorbisfile.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libogg
LOCAL_SRC_FILES := deps/$(APP_ABI)/Vorbis/libogg.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Zstd
LOCAL_SRC_FILES := deps/$(APP_ABI)/Zstd/libzstd.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := Minetest
LOCAL_CFLAGS += \
-DJSONCPP_NO_LOCALE_SUPPORT \
-DHAVE_TOUCHSCREENGUI \
-DENABLE_GLES=1 \
-DUSE_CURL=1 \
-DUSE_SOUND=1 \
-DUSE_LEVELDB=0 \
-DUSE_GETTEXT=1 \
-DVERSION_MAJOR=${versionMajor} \
-DVERSION_MINOR=${versionMinor} \
-DVERSION_PATCH=${versionPatch} \
-DVERSION_EXTRA=${versionExtra} \
-DDEVELOPMENT_BUILD=${developmentBuild} \
$(GPROF_DEF)
ifdef USE_BUILTIN_LUA
LOCAL_CFLAGS += -DUSE_LUAJIT=0
else
LOCAL_CFLAGS += -DUSE_LUAJIT=1
endif
ifdef NDEBUG
LOCAL_CFLAGS += -DNDEBUG=1
endif
ifdef GPROF
GPROF_DEF := -DGPROF
PROFILER_LIBS := android-ndk-profiler
LOCAL_CFLAGS += -pg
endif
LOCAL_C_INCLUDES := \
../../src \
../../src/script \
../../lib/gmp \
../../lib/jsoncpp \
deps/$(APP_ABI)/Curl/include \
deps/$(APP_ABI)/Freetype/include/freetype2 \
deps/$(APP_ABI)/Irrlicht/include \
deps/$(APP_ABI)/Gettext/include \
deps/$(APP_ABI)/Iconv/include \
deps/$(APP_ABI)/OpenAL-Soft/include \
deps/$(APP_ABI)/SQLite/include \
deps/$(APP_ABI)/Vorbis/include \
deps/$(APP_ABI)/Zstd/include
ifdef USE_BUILTIN_LUA
LOCAL_C_INCLUDES += \
../../lib/lua/src \
../../lib/bitop
else
LOCAL_C_INCLUDES += deps/$(APP_ABI)/LuaJIT/include
endif
LOCAL_SRC_FILES := \
$(wildcard ../../src/client/*.cpp) \
$(wildcard ../../src/client/*/*.cpp) \
$(wildcard ../../src/content/*.cpp) \
../../src/database/database.cpp \
../../src/database/database-dummy.cpp \
../../src/database/database-files.cpp \
../../src/database/database-sqlite3.cpp \
$(wildcard ../../src/gui/*.cpp) \
$(wildcard ../../src/irrlicht_changes/*.cpp) \
$(wildcard ../../src/mapgen/*.cpp) \
$(wildcard ../../src/network/*.cpp) \
$(wildcard ../../src/script/*.cpp) \
$(wildcard ../../src/script/*/*.cpp) \
$(wildcard ../../src/server/*.cpp) \
$(wildcard ../../src/threading/*.cpp) \
$(wildcard ../../src/util/*.c) \
$(wildcard ../../src/util/*.cpp) \
../../src/ban.cpp \
../../src/chat.cpp \
../../src/clientiface.cpp \
../../src/collision.cpp \
../../src/content_mapnode.cpp \
../../src/content_nodemeta.cpp \
../../src/convert_json.cpp \
../../src/craftdef.cpp \
../../src/debug.cpp \
../../src/defaultsettings.cpp \
../../src/emerge.cpp \
../../src/environment.cpp \
../../src/face_position_cache.cpp \
../../src/filesys.cpp \
../../src/gettext.cpp \
../../src/httpfetch.cpp \
../../src/hud.cpp \
../../src/inventory.cpp \
../../src/inventorymanager.cpp \
../../src/itemdef.cpp \
../../src/itemstackmetadata.cpp \
../../src/light.cpp \
../../src/lighting.cpp \
../../src/log.cpp \
../../src/main.cpp \
../../src/map.cpp \
../../src/map_settings_manager.cpp \
../../src/mapblock.cpp \
../../src/mapnode.cpp \
../../src/mapsector.cpp \
../../src/metadata.cpp \
../../src/modchannels.cpp \
../../src/nameidmapping.cpp \
../../src/nodedef.cpp \
../../src/nodemetadata.cpp \
../../src/nodetimer.cpp \
../../src/noise.cpp \
../../src/objdef.cpp \
../../src/object_properties.cpp \
../../src/particles.cpp \
../../src/pathfinder.cpp \
../../src/player.cpp \
../../src/porting.cpp \
../../src/porting_android.cpp \
../../src/profiler.cpp \
../../src/raycast.cpp \
../../src/reflowscan.cpp \
../../src/remoteplayer.cpp \
../../src/rollback.cpp \
../../src/rollback_interface.cpp \
../../src/serialization.cpp \
../../src/server.cpp \
../../src/serverenvironment.cpp \
../../src/serverlist.cpp \
../../src/settings.cpp \
../../src/staticobject.cpp \
../../src/texture_override.cpp \
../../src/tileanimation.cpp \
../../src/tool.cpp \
../../src/translation.cpp \
../../src/version.cpp \
../../src/voxel.cpp \
../../src/voxelalgorithms.cpp
# Built-in Lua
ifdef USE_BUILTIN_LUA
LOCAL_SRC_FILES += \
../../lib/lua/src/lapi.c \
../../lib/lua/src/lauxlib.c \
../../lib/lua/src/lbaselib.c \
../../lib/lua/src/lcode.c \
../../lib/lua/src/ldblib.c \
../../lib/lua/src/ldebug.c \
../../lib/lua/src/ldo.c \
../../lib/lua/src/ldump.c \
../../lib/lua/src/lfunc.c \
../../lib/lua/src/lgc.c \
../../lib/lua/src/linit.c \
../../lib/lua/src/liolib.c \
../../lib/lua/src/llex.c \
../../lib/lua/src/lmathlib.c \
../../lib/lua/src/lmem.c \
../../lib/lua/src/loadlib.c \
../../lib/lua/src/lobject.c \
../../lib/lua/src/lopcodes.c \
../../lib/lua/src/loslib.c \
../../lib/lua/src/lparser.c \
../../lib/lua/src/lstate.c \
../../lib/lua/src/lstring.c \
../../lib/lua/src/lstrlib.c \
../../lib/lua/src/ltable.c \
../../lib/lua/src/ltablib.c \
../../lib/lua/src/ltm.c \
../../lib/lua/src/lundump.c \
../../lib/lua/src/lvm.c \
../../lib/lua/src/lzio.c \
../../lib/bitop/bit.c
endif
# GMP
LOCAL_SRC_FILES += ../../lib/gmp/mini-gmp.c
# JSONCPP
LOCAL_SRC_FILES += ../../lib/jsoncpp/jsoncpp.cpp
LOCAL_STATIC_LIBRARIES += \
Curl libmbedcrypto libmbedtls libmbedx509 \
Freetype \
Iconv libcharset \
Irrlicht Irrlicht-libpng Irrlicht-libjpeg \
OpenAL \
Gettext \
SQLite3 \
Vorbis libvorbisfile libogg \
Zstd
ifndef USE_BUILTIN_LUA
LOCAL_STATIC_LIBRARIES += LuaJIT
endif
LOCAL_STATIC_LIBRARIES += android_native_app_glue $(PROFILER_LIBS)
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES -lz
include $(BUILD_SHARED_LIBRARY)
ifdef GPROF
$(call import-module,android-ndk-profiler)
endif
$(call import-module,android/native_app_glue)

View File

@@ -1,32 +0,0 @@
APP_PLATFORM := ${APP_PLATFORM}
APP_ABI := ${TARGET_ABI}
APP_STL := c++_shared
NDK_TOOLCHAIN_VERSION := clang
APP_SHORT_COMMANDS := true
APP_MODULES := Minetest
APP_CPPFLAGS := -O2 -fvisibility=hidden
ifeq ($(APP_ABI),armeabi-v7a)
APP_CPPFLAGS += -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb
endif
ifeq ($(APP_ABI),x86)
APP_CPPFLAGS += -mssse3 -mfpmath=sse -funroll-loops
endif
ifndef NDEBUG
APP_CPPFLAGS := -g -Og -fno-omit-frame-pointer
endif
APP_CFLAGS := $(APP_CPPFLAGS) -Wno-inconsistent-missing-override -Wno-parentheses-equality
APP_CXXFLAGS := $(APP_CPPFLAGS) -fexceptions -frtti -std=gnu++14
APP_LDFLAGS := -Wl,--no-warn-mismatch,--gc-sections,--icf=safe
ifeq ($(APP_ABI),arm64-v8a)
APP_LDFLAGS := -Wl,--no-warn-mismatch,--gc-sections
endif
ifndef NDEBUG
APP_LDFLAGS :=
endif

View File

@@ -36,11 +36,16 @@ do
setmetatable(v, {__newindex = {}})
-- Reassemble the other tables
if v.type == "node" then
getmetatable(v).__index = all.nodedef_default
all.registered_nodes[k] = v
elseif v.type == "craftitem" then
elseif v.type == "craft" then
getmetatable(v).__index = all.craftitemdef_default
all.registered_craftitems[k] = v
elseif v.type == "tool" then
getmetatable(v).__index = all.tooldef_default
all.registered_tools[k] = v
else
getmetatable(v).__index = all.noneitemdef_default
end
end

View File

@@ -5,3 +5,14 @@ function core.setting_get_pos(name)
end
return core.string_to_pos(value)
end
-- old non-method sound functions
function core.sound_stop(handle, ...)
return handle:stop(...)
end
function core.sound_fade(handle, ...)
return handle:fade(...)
end

View File

@@ -0,0 +1,74 @@
local builtin_shared = ...
do
local default = {mod = "??", name = "??"}
core.callback_origins = setmetatable({}, {
__index = function()
return default
end
})
end
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 = nil
for i = 1, cb_len do
local origin = core.callback_origins[callbacks[i]]
core.set_last_run_mod(origin.mod)
local cb_ret = callbacks[i](...)
if mode == 0 and i == 1 then
ret = cb_ret
elseif 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
function builtin_shared.make_registration()
local t = {}
local registerfunc = function(func)
t[#t + 1] = func
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
end
return t, registerfunc
end
function builtin_shared.make_registration_reverse()
local t = {}
local registerfunc = function(func)
table.insert(t, 1, func)
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.getinfo(1, "n").name or "??"
}
end
return t, registerfunc
end

View File

@@ -462,4 +462,11 @@ describe("vector", function()
end
end)
it("in_area()", function()
assert.True(vector.in_area(vector.zero(), vector.new(-10, -10, -10), vector.new(10, 10, 10)))
assert.True(vector.in_area(vector.new(-2, 5, -8), vector.new(-10, -10, -10), vector.new(10, 10, 10)))
assert.True(vector.in_area(vector.new(-10, -10, -10), vector.new(-10, -10, -10), vector.new(10, 10, 10)))
assert.False(vector.in_area(vector.new(-10, -10, -10), vector.new(10, 10, 10), vector.new(-11, -10, -10)))
end)
end)

View File

@@ -369,6 +369,12 @@ function vector.dir_to_rotation(forward, up)
return rot
end
function vector.in_area(pos, min, max)
return (pos.x >= min.x) and (pos.x <= max.x) and
(pos.y >= min.y) and (pos.y <= max.y) and
(pos.z >= min.z) and (pos.z <= max.z)
end
if rawget(_G, "core") and core.set_read_vector and core.set_push_vector then
local function read_vector(v)
return v.x, v.y, v.z

View File

@@ -1,5 +1,6 @@
--Minetest
--Copyright (C) 2014 sapier
--Copyright (C) 2023 Gregor Parzefall
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
@@ -16,115 +17,101 @@
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local function buttonbar_formspec(self)
local BASE_SPACING = 0.1
local SCROLL_BTN_WIDTH = TOUCHSCREEN_GUI and 0.8 or 0.5
local function buttonbar_formspec(self)
if self.hidden then
return ""
end
local formspec = string.format("box[%f,%f;%f,%f;%s]",
self.pos.x,self.pos.y ,self.size.x,self.size.y,self.bgcolor)
local formspec = {
"style_type[box;noclip=true]",
string.format("box[%f,%f;%f,%f;%s]", self.pos.x, self.pos.y, self.size.x,
self.size.y, self.bgcolor),
"style_type[box;noclip=false]",
}
for i=self.startbutton,#self.buttons,1 do
local btn_name = self.buttons[i].name
local btn_pos = {}
local btn_size = self.size.y - 2*BASE_SPACING
if self.orientation == "horizontal" then
btn_pos.x = self.pos.x + --base pos
(i - self.startbutton) * self.btn_size + --button offset
self.btn_initial_offset
else
btn_pos.x = self.pos.x + (self.btn_size * 0.05)
end
-- Spacing works like CSS Flexbox with `justify-content: space-evenly;`.
-- `BASE_SPACING` is used as the minimum spacing, like `gap` in CSS Flexbox.
if self.orientation == "vertical" then
btn_pos.y = self.pos.y + --base pos
(i - self.startbutton) * self.btn_size + --button offset
self.btn_initial_offset
else
btn_pos.y = self.pos.y + (self.btn_size * 0.05)
end
-- The number of buttons per page is always calculated as if the scroll
-- buttons were visible.
local avail_space = self.size.x - 2*BASE_SPACING - 2*SCROLL_BTN_WIDTH
local btns_per_page = math.floor((avail_space - BASE_SPACING) / (btn_size + BASE_SPACING))
if (self.orientation == "vertical" and
(btn_pos.y + self.btn_size <= self.pos.y + self.size.y)) or
(self.orientation == "horizontal" and
(btn_pos.x + self.btn_size <= self.pos.x + self.size.x)) then
self.num_pages = math.ceil(#self.buttons / btns_per_page)
self.cur_page = math.min(self.cur_page, self.num_pages)
local first_btn = (self.cur_page - 1) * btns_per_page + 1
local borders="true"
local show_scroll_btns = self.num_pages > 1
if self.buttons[i].image ~= nil then
borders="false"
end
-- In contrast, the button spacing calculation takes hidden scroll buttons
-- into account.
local real_avail_space = show_scroll_btns and avail_space or self.size.x
local btn_spacing = (real_avail_space - btns_per_page * btn_size) / (btns_per_page + 1)
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;%s]tooltip[%s;%s]",
btn_pos.x, btn_pos.y, self.btn_size, self.btn_size,
self.buttons[i].image, btn_name, self.buttons[i].caption,
borders, btn_name, self.buttons[i].tooltip)
else
--print("end of displayable buttons: orientation: " .. self.orientation)
--print( "button_end: " .. (btn_pos.y + self.btn_size - (self.btn_size * 0.05)))
--print( "bar_end: " .. (self.pos.x + self.size.x))
local btn_start_x = self.pos.x + btn_spacing
if show_scroll_btns then
btn_start_x = btn_start_x + BASE_SPACING + SCROLL_BTN_WIDTH
end
for i = first_btn, first_btn + btns_per_page - 1 do
local btn = self.buttons[i]
if btn == nil then
break
end
local btn_pos = {
x = btn_start_x + (i - first_btn) * (btn_size + btn_spacing),
y = self.pos.y + BASE_SPACING,
}
table.insert(formspec, string.format("image_button[%f,%f;%f,%f;%s;%s;%s;true;false]tooltip[%s;%s]",
btn_pos.x, btn_pos.y, btn_size, btn_size, btn.image, btn.name,
btn.caption, btn.name, btn.tooltip))
end
if (self.have_move_buttons) then
local btn_dec_pos = {}
btn_dec_pos.x = self.pos.x + (self.btn_size * 0.05)
btn_dec_pos.y = self.pos.y + (self.btn_size * 0.05)
local btn_inc_pos = {}
local btn_size = {}
if show_scroll_btns then
local btn_prev_pos = {
x = self.pos.x + BASE_SPACING,
y = self.pos.y + BASE_SPACING,
}
local btn_next_pos = {
x = self.pos.x + self.size.x - BASE_SPACING - SCROLL_BTN_WIDTH,
y = self.pos.y + BASE_SPACING,
}
if self.orientation == "horizontal" then
btn_size.x = 0.5
btn_size.y = self.btn_size
btn_inc_pos.x = self.pos.x + self.size.x - 0.5
btn_inc_pos.y = self.pos.y + (self.btn_size * 0.05)
else
btn_size.x = self.btn_size
btn_size.y = 0.5
btn_inc_pos.x = self.pos.x + (self.btn_size * 0.05)
btn_inc_pos.y = self.pos.y + self.size.y - 0.5
end
table.insert(formspec, string.format("style[%s,%s;noclip=true]",
self.btn_prev_name, self.btn_next_name))
local text_dec = "<"
local text_inc = ">"
if self.orientation == "vertical" then
text_dec = "^"
text_inc = "v"
end
table.insert(formspec, string.format("button[%f,%f;%f,%f;%s;<]",
btn_prev_pos.x, btn_prev_pos.y, SCROLL_BTN_WIDTH, btn_size,
self.btn_prev_name))
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_dec_%s;%s;true;true]",
btn_dec_pos.x, btn_dec_pos.y, btn_size.x, btn_size.y,
self.name, text_dec)
formspec = formspec ..
string.format("image_button[%f,%f;%f,%f;;btnbar_inc_%s;%s;true;true]",
btn_inc_pos.x, btn_inc_pos.y, btn_size.x, btn_size.y,
self.name, text_inc)
table.insert(formspec, string.format("button[%f,%f;%f,%f;%s;>]",
btn_next_pos.x, btn_next_pos.y, SCROLL_BTN_WIDTH, btn_size,
self.btn_next_name))
end
return formspec
return table.concat(formspec)
end
local function buttonbar_buttonhandler(self, fields)
if fields["btnbar_inc_" .. self.name] ~= nil and
self.startbutton < #self.buttons then
self.startbutton = self.startbutton + 1
if fields[self.btn_prev_name] and self.cur_page > 1 then
self.cur_page = self.cur_page - 1
return true
end
if fields["btnbar_dec_" .. self.name] ~= nil and self.startbutton > 1 then
self.startbutton = self.startbutton - 1
if fields[self.btn_next_name] and self.cur_page < self.num_pages then
self.cur_page = self.cur_page + 1
return true
end
for i=1,#self.buttons,1 do
if fields[self.buttons[i].name] ~= nil then
for _, btn in ipairs(self.buttons) do
if fields[btn.name] then
return self.userbuttonhandler(fields)
end
end
@@ -141,74 +128,45 @@ local buttonbar_metatable = {
delete = function(self) ui.delete(self) end,
add_button = function(self, name, caption, image, tooltip)
if caption == nil then caption = "" end
if image == nil then image = "" end
if tooltip == nil then tooltip = "" end
if caption == nil then caption = "" end
if image == nil then image = "" end
if tooltip == nil then tooltip = "" end
self.buttons[#self.buttons + 1] = {
name = name,
caption = caption,
image = image,
tooltip = tooltip
}
if self.orientation == "horizontal" then
if ( (self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.x ) then
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
else
if ((self.btn_size * #self.buttons) + (self.btn_size * 0.05 *2)
> self.size.y ) then
self.btn_initial_offset = self.btn_size * 0.05 + 0.5
self.have_move_buttons = true
end
end
end,
set_bgparams = function(self, bgcolor)
if (type(bgcolor) == "string") then
self.bgcolor = bgcolor
end
end,
table.insert(self.buttons, {
name = name,
caption = caption,
image = image,
tooltip = tooltip,
})
end,
}
buttonbar_metatable.__index = buttonbar_metatable
function buttonbar_create(name, cbf_buttonhandler, pos, orientation, size)
assert(name ~= nil)
assert(cbf_buttonhandler ~= nil)
assert(orientation == "vertical" or orientation == "horizontal")
assert(pos ~= nil and type(pos) == "table")
assert(size ~= nil and type(size) == "table")
function buttonbar_create(name, pos, size, bgcolor, cbf_buttonhandler)
assert(type(name) == "string" )
assert(type(pos) == "table" )
assert(type(size) == "table" )
assert(type(bgcolor) == "string" )
assert(type(cbf_buttonhandler) == "function")
local self = {}
self.name = name
self.type = "addon"
self.bgcolor = "#000000"
self.name = name
self.pos = pos
self.size = size
self.orientation = orientation
self.startbutton = 1
self.have_move_buttons = false
self.hidden = false
if self.orientation == "horizontal" then
self.btn_size = self.size.y
else
self.btn_size = self.size.x
end
if (self.btn_initial_offset == nil) then
self.btn_initial_offset = self.btn_size * 0.05
end
self.bgcolor = bgcolor
self.userbuttonhandler = cbf_buttonhandler
self.buttons = {}
setmetatable(self,buttonbar_metatable)
self.hidden = false
self.buttons = {}
self.num_pages = 1
self.cur_page = 1
self.btn_prev_name = "btnbar_prev_" .. self.name
self.btn_next_name = "btnbar_next_" .. self.name
setmetatable(self, buttonbar_metatable)
ui.add(self)
return self

View File

@@ -38,8 +38,18 @@ local dialog_metatable = {
handle_events = function(self,event)
if not self.hidden then return self.eventhandler(self,event) end
end,
hide = function(self) self.hidden = true end,
show = function(self) self.hidden = false end,
hide = function(self)
if not self.hidden then
self.hidden = true
self.eventhandler(self, "DialogHide")
end
end,
show = function(self)
if self.hidden then
self.hidden = false
self.eventhandler(self, "DialogShow")
end
end,
delete = function(self)
if self.parent ~= nil then
self.parent:show()

View File

@@ -42,6 +42,7 @@ local function add_tab(self,tab)
event_handler = tab.cbf_events,
get_formspec = tab.cbf_formspec,
tabsize = tab.tabsize,
formspec_version = tab.formspec_version or 6,
on_change = tab.on_change,
tabdata = {},
}
@@ -65,13 +66,38 @@ local function get_formspec(self)
local content, prepend = tab.get_formspec(self, tab.name, tab.tabdata, tab.tabsize)
local tsize = tab.tabsize or { width = self.width, height = self.height }
if self.parent == nil and not prepend then
local tsize = tab.tabsize or {width=self.width, height=self.height}
prepend = string.format("size[%f,%f,%s]", tsize.width, tsize.height,
dump(self.fixed_size))
if tab.formspec_version then
prepend = ("formspec_version[%d]"):format(tab.formspec_version) .. prepend
end
end
local end_button_size = 0.75
local tab_header_size = { width = tsize.width, height = 0.85 }
if self.end_button then
tab_header_size.width = tab_header_size.width - end_button_size - 0.1
end
local formspec = (prepend or "") .. self:tab_header(tab_header_size) .. content
if self.end_button then
formspec = formspec ..
("style[%s;noclip=true;border=false]"):format(self.end_button.name) ..
("tooltip[%s;%s]"):format(self.end_button.name, self.end_button.label) ..
("image_button[%f,%f;%f,%f;%s;%s;]"):format(
self.width - end_button_size,
(-tab_header_size.height - end_button_size) / 2,
end_button_size,
end_button_size,
core.formspec_escape(self.end_button.icon),
self.end_button.name)
end
local formspec = (prepend or "") .. self:tab_header() .. content
return formspec
end
@@ -86,8 +112,12 @@ local function handle_buttons(self,fields)
return true
end
if self.end_button and fields[self.end_button.name] then
return self.end_button.on_click(self)
end
if self.glb_btn_handler ~= nil and
self.glb_btn_handler(self,fields) then
self.glb_btn_handler(self, fields) then
return true
end
@@ -121,20 +151,23 @@ end
--------------------------------------------------------------------------------
local function tab_header(self)
local function tab_header(self, size)
local toadd = ""
for i=1,#self.tablist,1 do
for i = 1, #self.tablist do
if toadd ~= "" then
toadd = toadd .. ","
end
toadd = toadd .. self.tablist[i].caption
local caption = self.tablist[i].caption
if type(caption) == "function" then
caption = caption(self)
end
toadd = toadd .. caption
end
return string.format("tabheader[%f,%f;%s;%s;%i;true;false]",
self.header_x, self.header_y, self.name, toadd, self.last_tab_index);
return string.format("tabheader[%f,%f;%f,%f;%s;%s;%i;true;false]",
self.header_x, self.header_y, size.width, size.height, self.name, toadd, self.last_tab_index)
end
--------------------------------------------------------------------------------
@@ -225,6 +258,8 @@ local tabview_metatable = {
function(self,handler) self.glb_evt_handler = handler end,
set_fixed_size =
function(self,state) self.fixed_size = state end,
set_end_button =
function(self, v) self.end_button = v end,
tab_header = tab_header,
handle_tab_buttons = handle_tab_buttons
}

View File

@@ -62,8 +62,8 @@ function ui.update()
-- handle errors
if gamedata ~= nil and gamedata.reconnect_requested then
local error_message = core.formspec_escape(
gamedata.errormessage or fgettext("<none available>"))
local error_message = core.formspec_escape(gamedata.errormessage)
or fgettext("<none available>")
formspec = {
"size[14,8]",
"real_coordinates[true]",

View File

@@ -529,16 +529,16 @@ function core.check_single_for_falling(p)
if same and d_bottom.paramtype2 == "leveled" and
core.get_node_level(p_bottom) <
core.get_node_max_level(p_bottom) then
convert_to_falling_node(p, n)
return true
local success, _ = convert_to_falling_node(p, n)
return success
end
-- Otherwise only if the bottom node is considered "fall through"
if not same and
(not d_bottom.walkable or d_bottom.buildable_to) and
(core.get_item_group(n.name, "float") == 0 or
d_bottom.liquidtype == "none") then
convert_to_falling_node(p, n)
return true
local success, _ = convert_to_falling_node(p, n)
return success
end
end
end

View File

@@ -27,6 +27,8 @@ core.features = {
get_light_data_buffer = true,
mod_storage_on_disk = true,
compress_zstd = true,
sound_params_start_time = true,
physics_overrides_v2 = true,
}
function core.has_feature(arg)

View File

@@ -10,7 +10,8 @@ local builtin_shared = {}
dofile(gamepath .. "constants.lua")
assert(loadfile(commonpath .. "item_s.lua"))(builtin_shared)
assert(loadfile(gamepath .. "item.lua"))(builtin_shared)
dofile(gamepath .. "register.lua")
assert(loadfile(commonpath .. "register.lua"))(builtin_shared)
assert(loadfile(gamepath .. "register.lua"))(builtin_shared)
if core.settings:get_bool("profiler.load") then
profiler = dofile(scriptpath .. "profiler" .. DIR_DELIM .. "init.lua")

View File

@@ -69,6 +69,7 @@ core.register_entity(":__builtin:item", {
automatic_rotate = math.pi * 0.5 * 0.2 / size,
wield_item = self.itemstring,
glow = glow,
infotext = stack:get_description(),
})
-- cache for usage in on_step
@@ -178,6 +179,11 @@ core.register_entity(":__builtin:item", {
return
end
-- Prevent assert when item_entity is attached
if moveresult == nil and self.object:get_attach() then
return
end
if self.force_out then
-- This code runs after the entity got a push from the is_stuck code.
-- It makes sure the entity is entirely outside the solid node

View File

@@ -261,6 +261,11 @@ function core.get_globals_to_transfer()
local all = {
registered_items = copy_filtering(core.registered_items),
registered_aliases = core.registered_aliases,
nodedef_default = copy_filtering(core.nodedef_default),
craftitemdef_default = copy_filtering(core.craftitemdef_default),
tooldef_default = copy_filtering(core.tooldef_default),
noneitemdef_default = copy_filtering(core.noneitemdef_default),
}
return all
end

View File

@@ -1,5 +1,6 @@
-- Minetest: builtin/register.lua
local builtin_shared = ...
local S = core.get_translator("__builtin")
--
@@ -420,55 +421,6 @@ function core.override_item(name, redefinition)
register_item_raw(item)
end
do
local default = {mod = "??", name = "??"}
core.callback_origins = setmetatable({}, {
__index = function()
return default
end
})
end
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 = nil
for i = 1, cb_len do
local origin = core.callback_origins[callbacks[i]]
core.set_last_run_mod(origin.mod)
local cb_ret = callbacks[i](...)
if mode == 0 and i == 1 then
ret = cb_ret
elseif 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
function core.run_priv_callbacks(name, priv, caller, method)
local def = core.registered_privileges[priv]
if not def or not def["on_" .. method] or
@@ -485,34 +437,6 @@ 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 = debug.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
local function make_registration_reverse()
local t = {}
local registerfunc = function(func)
table.insert(t, 1, func)
core.callback_origins[func] = {
mod = core.get_current_modname() or "??",
name = debug.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
local function make_registration_wrap(reg_fn_name, clear_fn_name)
local list = {}
@@ -600,6 +524,9 @@ core.registered_decorations = make_registration_wrap("register_decoration", "cle
core.unregister_biome = make_wrap_deregistration(core.register_biome,
core.clear_registered_biomes, core.registered_biomes)
local make_registration = builtin_shared.make_registration
local make_registration_reverse = builtin_shared.make_registration_reverse
core.registered_on_chat_messages, core.register_on_chat_message = make_registration()
core.registered_on_chatcommands, core.register_on_chatcommand = make_registration()
core.registered_globalsteps, core.register_globalstep = make_registration()

View File

@@ -1,4 +1,22 @@
# textdomain: __builtin
Invalid parameters (see /help @1).=Ungültige Parameter (siehe „/help @1“).
Too many arguments, try using just /help <command>=Zu viele Argumente. Probieren Sie es mit „/help <Befehl>“
Available commands: @1=Verfügbare Befehle: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=„/help <Befehl>“ benutzen, um mehr Informationen zu erhalten, oder „/help all“, um alles aufzulisten.
Available commands:=Verfügbare Befehle:
Command not available: @1=Befehl nicht verfügbar: @1
[all | privs | <cmd>] [-t]=[all | privs | <Befehl>] [-t]
Get help for commands or list privileges (-t: output in chat)=Hilfe für Befehle erhalten oder Privilegien auflisten (-t: Ausgabe im Chat)
Available privileges:=Verfügbare Privilegien:
Command=Befehl
Parameters=Parameter
For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste.
Double-click to copy the entry to the chat history.=Doppelklicken, um den Eintrag in die Chathistorie einzufügen.
Command: @1 @2=Befehl: @1 @2
Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /help <Befehl>)
Close=Schließen
Privilege=Privileg
Description=Beschreibung
Empty command.=Leerer Befehl.
Invalid command: @1=Ungültiger Befehl: @1
Invalid command usage.=Ungültige Befehlsverwendung.
@@ -189,30 +207,6 @@ You are already dead.=Sie sind schon tot.
@1 is already dead.=@1 ist bereits tot.
@1 has been killed.=@1 wurde getötet.
Kill player or yourself=Einen Spieler oder Sie selbst töten
Invalid parameters (see /help @1).=Ungültige Parameter (siehe „/help @1“).
Too many arguments, try using just /help <command>=Zu viele Argumente. Probieren Sie es mit „/help <Befehl>“
Available commands: @1=Verfügbare Befehle: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=„/help <Befehl>“ benutzen, um mehr Informationen zu erhalten, oder „/help all“, um alles aufzulisten.
Available commands:=Verfügbare Befehle:
Command not available: @1=Befehl nicht verfügbar: @1
[all | privs | <cmd>] [-t]=[all | privs | <Befehl>] [-t]
Get help for commands or list privileges (-t: output in chat)=Hilfe für Befehle erhalten oder Privilegien auflisten (-t: Ausgabe im Chat)
Available privileges:=Verfügbare Privilegien:
Command=Befehl
Parameters=Parameter
For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste.
Double-click to copy the entry to the chat history.=Doppelklicken, um den Eintrag in die Chathistorie einzufügen.
Command: @1 @2=Befehl: @1 @2
Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /help <Befehl>)
Close=Schließen
Privilege=Privileg
Description=Beschreibung
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]]
Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten
Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben.
Statistics were reset.=Statistiken wurden zurückgesetzt.
Usage: @1=Verwendung: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format kann entweder „txt“, „csv“, „lua“, „json“ oder „json_pretty“ sein (die Struktur kann sich in Zukunft ändern).
@1 joined the game.=@1 ist dem Spiel beigetreten.
@1 left the game.=@1 hat das Spiel verlassen.
@1 left the game (timed out).=@1 hat das Spiel verlassen (Netzwerkzeitüberschreitung).
@@ -239,6 +233,12 @@ Unknown Item=Unbekannter Gegenstand
Air=Luft
Ignore=Ignorieren
You can't place 'ignore' nodes!=Sie können keine „ignore“-Blöcke platzieren!
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]] | reset
Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten
Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben.
Statistics were reset.=Statistiken wurden zurückgesetzt.
Usage: @1=Verwendung: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format kann entweder „txt“, „csv“, „lua“, „json“ oder „json_pretty“ sein (die Struktur kann sich in Zukunft ändern).
Values below show absolute/relative times spend per server step by the instrumented function.=Die unten angegebenen Werte zeigen absolute/relative Zeitspannen, die je Server-Step von der instrumentierten Funktion in Anspruch genommen wurden.
A total of @1 sample(s) were taken.=Es wurden insgesamt @1 Datenpunkt(e) aufgezeichnet.
The output is limited to '@1'.=Die Ausgabe ist beschränkt auf „@1“.

View File

@@ -1,9 +1,27 @@
# textdomain: __builtin
Invalid parameters (see /help @1).=Parameter tidak sah (lihat /help @1).
Too many arguments, try using just /help <command>=Terlalu banyak argumen. Coba hanya gunakan /help <perintah>
Available commands: @1=Perintah yang tersedia: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=Gunakan '/help <perintah>' untuk informasi lebih lanjut atau '/help all' untuk melihat daftar semuanya.
Available commands:=Perintah yang tersedia:
Command not available: @1=Perintah tidak tersedia: @1
[all | privs | <cmd>] [-t]=[all | privs | <perintah>] [-t]
Get help for commands or list privileges (-t: output in chat)=Ambil bantuan untuk perintah atau daftar hak (-t: keluaran di obrolan)
Available privileges:=Hak yang ada:
Command=Perintah
Parameters=Parameter
For more information, click on any entry in the list.=Untuk informasi lebih lanjut, klik pada entri apa pun dalam daftar.
Double-click to copy the entry to the chat history.=Klik ganda untuk menyalin entri ke riwayat obrolan.
Command: @1 @2=Perintah: @1 @2
Available commands: (see also: /help <cmd>)=Perintah yang tersedia: (lihat juga: /help <perintah>)
Close=Tutup
Privilege=Hak
Description=Deskripsi
Empty command.=Perintah kosong.
Invalid command: @1=Perintah tidak sah: @1
Invalid command usage.=Penggunaan perintah tidak sah.
(@1 s)= (@1 detik)
Command execution took @1 s=Pelaksanaan perintah memerlukan @1 detik
(@1 s)= (@1 detik)
Command execution took @1 s=Pelaksanaan perintah memerlukan @1 detik
You don't have permission to run this command (missing privileges: @1).=Anda tidak memiliki izin untuk menjalankan perintah ini (hak tidak ada: @1).
Unable to get position of player @1.=Tidak dapat mengambil letak pemain @1.
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Format daerah tidak sah. Diharapkan: (x1,y1,z1) (x2,y2,z2)
@@ -189,30 +207,6 @@ You are already dead.=Anda telah mati.
@1 is already dead.=@1 telah mati.
@1 has been killed.=@1 telah dibunuh.
Kill player or yourself=Bunuh pemain atau diri Anda
Invalid parameters (see /help @1).=Parameter tidak sah (lihat /help @1).
Too many arguments, try using just /help <command>=Terlalu banyak argumen. Coba hanya gunakan /help <perintah>
Available commands: @1=Perintah yang tersedia: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=Gunakan '/help <perintah>' untuk informasi lebih lanjut atau '/help all' untuk melihat daftar semuanya.
Available commands:=Perintah yang tersedia:
Command not available: @1=Perintah tidak tersedia: @1
[all | privs | <cmd>] [-t]=[all | privs | <perintah>] [-t]
Get help for commands or list privileges (-t: output in chat)=Ambil bantuan untuk perintah atau daftar hak (-t: keluaran di obrolan)
Available privileges:=Hak yang ada:
Command=Perintah
Parameters=Parameter
For more information, click on any entry in the list.=Untuk informasi lebih lanjut, klik pada entri apa pun dalam daftar.
Double-click to copy the entry to the chat history.=Klik ganda untuk menyalin entri ke riwayat obrolan.
Command: @1 @2=Perintah: @1 @2
Available commands: (see also: /help <cmd>)=Perintah yang tersedia: (lihat juga: /help <perintah>)
Close=Tutup
Privilege=Hak
Description=Deskripsi
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset
Handle the profiler and profiling data=Menangani profiler dan data profiling
Statistics written to action log.=Statistik ditulis ke log action.
Statistics were reset.=Statistik diatur ulang.
Usage: @1=Penggunaan: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format berupa salah satu dari txt, csv, lua, json, json_pretty (struktur mungkin berubah).
@1 joined the game.=@1 bergabung dalam permainan.
@1 left the game.=@1 keluar permainan.
@1 left the game (timed out).=@1 keluar permainan (kehabisan waktu).
@@ -239,6 +233,12 @@ Unknown Item=Barang Tak Diketahui
Air=Udara
Ignore=Ignore
You can't place 'ignore' nodes!=Anda tidak dapat menaruh nodus 'ignore'!
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset
Handle the profiler and profiling data=Menangani profiler dan data profiling
Statistics written to action log.=Statistik ditulis ke log action.
Statistics were reset.=Statistik diatur ulang.
Usage: @1=Penggunaan: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format berupa salah satu dari txt, csv, lua, json, json_pretty (struktur mungkin berubah).
Values below show absolute/relative times spend per server step by the instrumented function.=Nilai berikut menampilkan waktu mutlak/relatif yang dihabiskan tiap langkah server oleh fungsi instrumen.
A total of @1 sample(s) were taken.=Total @1 sampel yang diambil.
The output is limited to '@1'.=Keluaran dibatasi ke '@1'.

View File

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

View File

@@ -1,4 +1,22 @@
# textdomain: __builtin
Invalid parameters (see /help @1).=Parameter tidak sah (sila lihat /help @1).
Too many arguments, try using just /help <command>=Terlalu banyak argumen, cuba guna /help <perintah> sahaja
Available commands: @1=Perintah yang tersedia: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=Gunakan '/help <perintah>' untuk maklumat lanjut, atau '/help all' untuk senaraikan kesemuanya.
Available commands:=Perintah yang tersedia:
Command not available: @1=Perintah tidak tersedia: @1
[all | privs | <cmd>] [-t]=[all | privs | <perintah>] [-t]
Get help for commands or list privileges (-t: output in chat)=Dapatkan bantuan untuk perintah atau senaraikan keistimewaan (-t: output dalam sembang)
Available privileges:=Keistimewaan yang tersedia:
Command=Perintah
Parameters=Parameter
For more information, click on any entry in the list.=Untuk maklumat lanjut, klik pada mana-mana entri dalam senarai.
Double-click to copy the entry to the chat history.=Klik dua kali untuk salin entri ke sejarah sembang.
Command: @1 @2=Perintah: @1 @2
Available commands: (see also: /help <cmd>)=Perintah yang tersedua: (sila lihat juga: /help <perintah>)
Close=Tutup
Privilege=Keistimewaan
Description=Keterangan
Empty command.=Perintah kosong.
Invalid command: @1=Perintah tidak sah: @1
Invalid command usage.=Penggunaan perintah tidak sah.
@@ -189,30 +207,6 @@ You are already dead.=Anda sudah pun mati.
@1 is already dead.=@1 sudah pun mati.
@1 has been killed.=@1 telah berjaya dibunuh.
Kill player or yourself=Bunuh pemain atau diri sendiri
Invalid parameters (see /help @1).=Parameter tidak sah (sila lihat /help @1).
Too many arguments, try using just /help <command>=Terlalu banyak argumen, cuba guna /help <perintah> sahaja
Available commands: @1=Perintah yang tersedia: @1
Use '/help <cmd>' to get more information, or '/help all' to list everything.=Gunakan '/help <perintah>' untuk maklumat lanjut, atau '/help all' untuk senaraikan kesemuanya.
Available commands:=Perintah yang tersedia:
Command not available: @1=Perintah tidak tersedia: @1
[all | privs | <cmd>] [-t]=[all | privs | <perintah>] [-t]
Get help for commands or list privileges (-t: output in chat)=Dapatkan bantuan untuk perintah atau senaraikan keistimewaan (-t: output dalam sembang)
Available privileges:=Keistimewaan yang tersedia:
Command=Perintah
Parameters=Parameter
For more information, click on any entry in the list.=Untuk maklumat lanjut, klik pada mana-mana entri dalam senarai.
Double-click to copy the entry to the chat history.=Klik dua kali untuk salin entri ke sejarah sembang.
Command: @1 @2=Perintah: @1 @2
Available commands: (see also: /help <cmd>)=Perintah yang tersedua: (sila lihat juga: /help <perintah>)
Close=Tutup
Privilege=Keistimewaan
Description=Keterangan
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<tapisan>] | dump [<tapisan>] | save [<format> [<tapisan>]] | reset
Handle the profiler and profiling data=Uruskan pembukah dan data pembukahan
Statistics written to action log.=Statistik telah ditulis ke log perlakuan.
Statistics were reset.=Statistik telah ditetapkan semula.
Usage: @1=Kegunaan: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format boleh jadi salah satu daripada txt, csv, lua, json, json_pretty (struktur boleh berubah kemudian).
@1 joined the game.=@1 telah menyertai permainan.
@1 left the game.=@1 telah meninggalkan permainan.
@1 left the game (timed out).=@1 telah meninggalkan permainan (tamat tempoh masa).
@@ -239,6 +233,12 @@ Unknown Item=Item Tidak Diketahui
Air=Udara
Ignore=Abai
You can't place 'ignore' nodes!=Anda tidak boleh meletakkan nod 'abai'!
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<tapisan>] | dump [<tapisan>] | save [<format> [<tapisan>]] | reset
Handle the profiler and profiling data=Uruskan pembukah dan data pembukahan
Statistics written to action log.=Statistik telah ditulis ke log perlakuan.
Statistics were reset.=Statistik telah ditetapkan semula.
Usage: @1=Kegunaan: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format boleh jadi salah satu daripada txt, csv, lua, json, json_pretty (struktur boleh berubah kemudian).
Values below show absolute/relative times spend per server step by the instrumented function.=Nilai di bawah menunjukkan masa mutlak/relatif yang digunakan oleh fungsi yang dipasangkan pada setiap langkah pelayan
A total of @1 sample(s) were taken.=Sebanyak @1 sampel telah diambil secara keseluruhan.
The output is limited to '@1'.=Output dihadkan kepada '@1'.

View File

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

View File

@@ -1,4 +1,22 @@
# textdomain: __builtin
Invalid parameters (see /help @1).=
Too many arguments, try using just /help <command>=
Available commands: @1=
Use '/help <cmd>' to get more information, or '/help all' to list everything.=
Available commands:=
Command not available: @1=
[all | privs | <cmd>] [-t]=
Get help for commands or list privileges (-t: output in chat)=
Available privileges:=
Command=
Parameters=
For more information, click on any entry in the list.=
Double-click to copy the entry to the chat history.=
Command: @1 @2=
Available commands: (see also: /help <cmd>)=
Close=
Privilege=
Description=
Empty command.=
Invalid command: @1=
Invalid command usage.=
@@ -189,30 +207,6 @@ You are already dead.=
@1 is already dead.=
@1 has been killed.=
Kill player or yourself=
Invalid parameters (see /help @1).=
Too many arguments, try using just /help <command>=
Available commands: @1=
Use '/help <cmd>' to get more information, or '/help all' to list everything.=
Available commands:=
Command not available: @1=
[all | privs | <cmd>] [-t]=
Get help for commands or list privileges (-t: output in chat)=
Available privileges:=
Command=
Parameters=
For more information, click on any entry in the list.=
Double-click to copy the entry to the chat history.=
Command: @1 @2=
Available commands: (see also: /help <cmd>)=
Close=
Privilege=
Description=
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
Handle the profiler and profiling data=
Statistics written to action log.=
Statistics were reset.=
Usage: @1=
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=
@1 joined the game.=
@1 left the game.=
@1 left the game (timed out).=
@@ -239,6 +233,12 @@ Unknown Item=
Air=
Ignore=
You can't place 'ignore' nodes!=
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
Handle the profiler and profiling data=
Statistics written to action log.=
Statistics were reset.=
Usage: @1=
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=
Values below show absolute/relative times spend per server step by the instrumented function.=
A total of @1 sample(s) were taken.=
The output is limited to '@1'.=

View File

@@ -23,9 +23,18 @@ if not core.get_http_api then
return
end
-- Unordered preserves the original order of the ContentDB API,
-- before the package list is ordered based on installed state.
local store = { packages = {}, packages_full = {}, packages_full_unordered = {}, aliases = {} }
local store = {
loading = false,
load_ok = false,
load_error = false,
-- Unordered preserves the original order of the ContentDB API,
-- before the package list is ordered based on installed state.
packages = {},
packages_full = {},
packages_full_unordered = {},
aliases = {},
}
local http = core.get_http_api()
@@ -47,6 +56,9 @@ local filter_types_titles = {
fgettext("Texture packs"),
}
-- Automatic package installation
local auto_install_spec = nil
local number_downloading = 0
local download_queue = {}
@@ -62,15 +74,6 @@ local REASON_UPDATE = "update"
local REASON_DEPENDENCY = "dependency"
-- encodes for use as URL parameter or path component
local function urlencode(str)
return str:gsub("[^%a%d()._~-]", function(char)
return string.format("%%%02X", string.byte(char))
end)
end
assert(urlencode("sample text?") == "sample%20text%3F")
local function get_download_url(package, reason)
local base_url = core.settings:get("contentdb_url")
local ret = base_url .. ("/packages/%s/releases/%d/download/"):format(
@@ -89,7 +92,7 @@ local function download_and_extract(param)
if filename == "" or not core.download_file(param.url, filename) then
core.log("error", "Downloading " .. dump(param.url) .. " failed")
return {
msg = fgettext("Failed to download \"$1\"", package.title)
msg = fgettext_ne("Failed to download \"$1\"", package.title)
}
end
@@ -105,7 +108,7 @@ local function download_and_extract(param)
os.remove(filename)
if not tempfolder then
return {
msg = fgettext("Failed to extract \"$1\" (unsupported file type or broken archive)", package.title),
msg = fgettext_ne("Failed to extract \"$1\" (unsupported file type or broken archive)", package.title),
}
end
@@ -129,7 +132,7 @@ local function start_install(package, reason)
local path, msg = pkgmgr.install_dir(package.type, result.path, package.name, package.path)
core.delete_dir(result.path)
if not path then
gamedata.errormessage = fgettext("Error installing \"$1\": $2", package.title, msg)
gamedata.errormessage = fgettext_ne("Error installing \"$1\": $2", package.title, msg)
else
core.log("action", "Installed package to " .. path)
@@ -184,12 +187,16 @@ local function start_install(package, reason)
if not core.handle_async(download_and_extract, params, callback) then
core.log("error", "ERROR: async event failed")
gamedata.errormessage = fgettext("Failed to download $1", package.name)
gamedata.errormessage = fgettext_ne("Failed to download $1", package.name)
return
end
end
local function queue_download(package, reason)
if package.queued or package.downloading then
return
end
local max_concurrent_downloads = tonumber(core.settings:get("contentdb_max_concurrent_downloads"))
if number_downloading < math.max(max_concurrent_downloads, 1) then
start_install(package, reason)
@@ -200,6 +207,9 @@ local function queue_download(package, reason)
end
local function get_raw_dependencies(package)
if package.type ~= "mod" then
return {}
end
if package.raw_deps then
return package.raw_deps
end
@@ -207,7 +217,7 @@ local function get_raw_dependencies(package)
local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s"
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local url = base_url .. url_fmt:format(package.url_part, core.get_max_supp_proto(), urlencode(version.string))
local url = base_url .. url_fmt:format(package.url_part, core.get_max_supp_proto(), core.urlencode(version.string))
local response = http.fetch_sync({ url = url })
if not response.succeeded then
@@ -429,7 +439,7 @@ function install_dialog.get_formspec()
"container_end[]",
}
return table.concat(formspec, "")
return table.concat(formspec)
end
function install_dialog.handle_submit(this, fields)
@@ -520,6 +530,50 @@ function confirm_overwrite.create(package, callback)
nil)
end
local function install_or_update_package(this, package)
local install_parent
if package.type == "mod" then
install_parent = core.get_modpath()
elseif package.type == "game" then
install_parent = core.get_gamepath()
elseif package.type == "txp" then
install_parent = core.get_texturepath()
else
error("Unknown package type: " .. package.type)
end
if package.queued or package.downloading then
return
end
local function on_confirm()
local deps = get_raw_dependencies(package)
if deps and has_hard_deps(deps) then
local dlg = install_dialog.create(package, deps)
dlg:set_parent(this)
this:hide()
dlg:show()
else
queue_download(package, package.path and REASON_UPDATE or REASON_NEW)
end
end
if package.type == "mod" and #pkgmgr.games == 0 then
local dlg = messagebox("install_game",
fgettext("You need to install a game before you can install a mod"))
dlg:set_parent(this)
this:hide()
dlg:show()
elseif not package.path and core.is_dir(install_parent .. DIR_DELIM .. package.name) then
local dlg = confirm_overwrite.create(package, on_confirm)
dlg:set_parent(this)
this:hide()
dlg:show()
else
on_confirm()
end
end
local function get_file_extension(path)
local parts = path:split(".")
@@ -574,29 +628,33 @@ local function get_screenshot(package)
return defaulttexturedir .. "loading_screenshot.png"
end
function store.load()
local function fetch_pkgs()
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local url = base_url ..
"/api/packages/?type=mod&type=game&type=txp&protocol_version=" ..
core.get_max_supp_proto() .. "&engine_version=" .. urlencode(version.string)
core.get_max_supp_proto() .. "&engine_version=" .. core.urlencode(version.string)
for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do
item = item:trim()
if item ~= "" then
url = url .. "&hide=" .. urlencode(item)
url = url .. "&hide=" .. core.urlencode(item)
end
end
local http = core.get_http_api()
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
store.packages_full = core.parse_json(response.data) or {}
store.aliases = {}
local packages = core.parse_json(response.data)
if not packages or #packages == 0 then
return
end
local aliases = {}
for _, package in pairs(store.packages_full) do
for _, package in pairs(packages) do
local name_len = #package.name
-- This must match what store.update_paths() does!
package.id = package.author:lower() .. "/"
@@ -606,48 +664,137 @@ function store.load()
package.id = package.id .. package.name
end
package.url_part = urlencode(package.author) .. "/" .. urlencode(package.name)
package.url_part = core.urlencode(package.author) .. "/" .. core.urlencode(package.name)
if package.aliases then
for _, alias in ipairs(package.aliases) do
-- We currently don't support name changing
local suffix = "/" .. package.name
if alias:sub(-#suffix) == suffix then
store.aliases[alias:lower()] = package.id
aliases[alias:lower()] = package.id
end
end
end
end
store.packages_full_unordered = store.packages_full
store.packages = store.packages_full
store.loaded = true
return { packages = packages, aliases = aliases }
end
local function sort_and_filter_pkgs()
store.update_paths()
store.sort_packages()
store.filter_packages(search_string)
end
-- Resolves the package specification stored in auto_install_spec into an actual package.
-- May only be called after the package list has been loaded successfully.
local function resolve_auto_install_spec()
assert(store.load_ok)
if not auto_install_spec then
return nil
end
local spec = store.aliases[auto_install_spec] or auto_install_spec
local resolved = nil
for _, pkg in ipairs(store.packages_full_unordered) do
if pkg.id == spec then
resolved = pkg
break
end
end
if not resolved then
gamedata.errormessage = fgettext("The package $1 was not found.", auto_install_spec)
ui.update()
auto_install_spec = nil
end
return resolved
end
-- Installs the package specified by auto_install_spec.
-- Only does something if:
-- a. The package list has been loaded successfully.
-- b. The store dialog is currently visible.
local function do_auto_install()
if not store.load_ok then
return
end
local pkg = resolve_auto_install_spec()
if not pkg then
return
end
local store_dlg = ui.find_by_name("store")
if not store_dlg or store_dlg.hidden then
return
end
install_or_update_package(store_dlg, pkg)
auto_install_spec = nil
end
function store.load()
if store.load_ok then
sort_and_filter_pkgs()
return
end
if store.loading then
return
end
store.loading = true
core.handle_async(
fetch_pkgs,
nil,
function(result)
if result then
store.load_ok = true
store.load_error = false
store.packages = result.packages
store.packages_full = result.packages
store.packages_full_unordered = result.packages
store.aliases = result.aliases
sort_and_filter_pkgs()
do_auto_install()
else
store.load_error = true
end
store.loading = false
ui.update()
end
)
end
function store.update_paths()
local mod_hash = {}
pkgmgr.refresh_globals()
for _, mod in pairs(pkgmgr.global_mods:get_list()) do
if mod.author and mod.release > 0 then
local id = mod.author:lower() .. "/" .. mod.name
mod_hash[store.aliases[id] or id] = mod
local cdb_id = pkgmgr.get_contentdb_id(mod)
if cdb_id then
mod_hash[store.aliases[cdb_id] or cdb_id] = mod
end
end
local game_hash = {}
pkgmgr.update_gamelist()
for _, game in pairs(pkgmgr.games) do
if game.author ~= "" and game.release > 0 then
local id = game.author:lower() .. "/" .. game.id
game_hash[store.aliases[id] or id] = game
local cdb_id = pkgmgr.get_contentdb_id(game)
if cdb_id then
game_hash[store.aliases[cdb_id] or cdb_id] = game
end
end
local txp_hash = {}
for _, txp in pairs(pkgmgr.get_texture_packs()) do
if txp.author and txp.release > 0 then
local id = txp.author:lower() .. "/" .. txp.name
txp_hash[store.aliases[id] or id] = txp
local cdb_id = pkgmgr.get_contentdb_id(txp)
if cdb_id then
txp_hash[store.aliases[cdb_id] or cdb_id] = txp
end
end
@@ -666,6 +813,7 @@ function store.update_paths()
package.installed_release = content.release or 0
else
package.path = nil
package.installed_release = nil
end
end
end
@@ -673,27 +821,40 @@ end
function store.sort_packages()
local ret = {}
local auto_install_pkg = resolve_auto_install_spec() -- can be nil
-- Add installed content
for i=1, #store.packages_full_unordered do
local package = store.packages_full_unordered[i]
if package.path then
ret[#ret + 1] = package
for _, pkg in ipairs(store.packages_full_unordered) do
if pkg.path and pkg ~= auto_install_pkg then
ret[#ret + 1] = pkg
end
end
-- Sort installed content by title
-- Sort installed content first by "is there an update available?", then by title
table.sort(ret, function(a, b)
local a_updatable = a.installed_release < a.release
local b_updatable = b.installed_release < b.release
if a_updatable and not b_updatable then
return true
elseif b_updatable and not a_updatable then
return false
end
return a.title < b.title
end)
-- Add uninstalled content
for i=1, #store.packages_full_unordered do
local package = store.packages_full_unordered[i]
if not package.path then
ret[#ret + 1] = package
for _, pkg in ipairs(store.packages_full_unordered) do
if not pkg.path and pkg ~= auto_install_pkg then
ret[#ret + 1] = pkg
end
end
-- Put the package that will be auto-installed at the very top
if auto_install_pkg then
table.insert(ret, 1, auto_install_pkg)
end
store.packages_full = ret
end
@@ -732,7 +893,29 @@ function store.filter_packages(query)
end
end
local function get_info_formspec(text)
local H = 9.5
return table.concat({
"formspec_version[6]",
"size[15.75,9.5]",
TOUCHSCREEN_GUI and "padding[0.01,0.01]" or "position[0.5,0.55]",
"label[4,4.35;", text, "]",
"container[0,", H - 0.8 - 0.375, "]",
"button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]",
"container_end[]",
})
end
function store.get_formspec(dlgdata)
if store.loading then
return get_info_formspec(fgettext("Loading..."))
end
if store.load_error then
return get_info_formspec(fgettext("No packages could be retrieved"))
end
assert(store.load_ok)
store.update_paths()
dlgdata.pagemax = math.max(math.ceil(#store.packages / num_per_page), 1)
@@ -742,82 +925,70 @@ function store.get_formspec(dlgdata)
local W = 15.75
local H = 9.5
local formspec
if #store.packages_full > 0 then
formspec = {
"formspec_version[3]",
"size[15.75,9.5]",
"position[0.5,0.55]",
local formspec = {
"formspec_version[6]",
"size[15.75,9.5]",
TOUCHSCREEN_GUI and "padding[0.01,0.01]" or "position[0.5,0.55]",
"style[status,downloading,queued;border=false]",
"style[status,downloading,queued;border=false]",
"container[0.375,0.375]",
"field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]",
"field_close_on_enter[search_string;false]",
"image_button[7.3,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
"image_button[8.125,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]",
"dropdown[9.6,0;2.4,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]",
"container_end[]",
"container[0.375,0.375]",
"field[0,0;7.225,0.8;search_string;;", core.formspec_escape(search_string), "]",
"field_enter_after_edit[search_string;true]",
"image_button[7.3,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "search.png"), ";search;]",
"image_button[8.125,0;0.8,0.8;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";clear;]",
"dropdown[9.175,0;2.7875,0.8;type;", table.concat(filter_types_titles, ","), ";", filter_type, "]",
"container_end[]",
-- Page nav buttons
"container[0,", H - 0.8 - 0.375, "]",
"button[0.375,0;4,0.8;back;", fgettext("Back to Main Menu"), "]",
-- Page nav buttons
"container[0,", H - 0.8 - 0.375, "]",
"button[0.375,0;5,0.8;back;", fgettext("Back to Main Menu"), "]",
"container[", W - 0.375 - 0.8*4 - 2, ",0]",
"image_button[0,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "start_icon.png;pstart;]",
"image_button[0.8,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "prev_icon.png;pback;]",
"style[pagenum;border=false]",
"button[1.6,0;2,0.8;pagenum;", tonumber(cur_page), " / ", tonumber(dlgdata.pagemax), "]",
"image_button[3.6,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "next_icon.png;pnext;]",
"image_button[4.4,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "end_icon.png;pend;]",
"container_end[]",
"container[", W - 0.375 - 0.8*4 - 2, ",0]",
"image_button[0,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "start_icon.png;pstart;]",
"image_button[0.8,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "prev_icon.png;pback;]",
"style[pagenum;border=false]",
"button[1.6,0;2,0.8;pagenum;", tonumber(cur_page), " / ", tonumber(dlgdata.pagemax), "]",
"image_button[3.6,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "next_icon.png;pnext;]",
"image_button[4.4,0;0.8,0.8;", core.formspec_escape(defaulttexturedir), "end_icon.png;pend;]",
"container_end[]",
"container_end[]",
}
"container_end[]",
}
if number_downloading > 0 then
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;downloading;"
if #download_queue > 0 then
formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue)
else
formspec[#formspec + 1] = fgettext("$1 downloading...", number_downloading)
if number_downloading > 0 then
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;downloading;"
if #download_queue > 0 then
formspec[#formspec + 1] = fgettext("$1 downloading,\n$2 queued", number_downloading, #download_queue)
else
formspec[#formspec + 1] = fgettext("$1 downloading...", number_downloading)
end
formspec[#formspec + 1] = "]"
else
local num_avail_updates = 0
for i=1, #store.packages_full do
local package = store.packages_full[i]
if package.path and package.installed_release < package.release and
not (package.downloading or package.queued) then
num_avail_updates = num_avail_updates + 1
end
end
if num_avail_updates == 0 then
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;status;"
formspec[#formspec + 1] = fgettext("No updates")
formspec[#formspec + 1] = "]"
else
local num_avail_updates = 0
for i=1, #store.packages_full do
local package = store.packages_full[i]
if package.path and package.installed_release < package.release and
not (package.downloading or package.queued) then
num_avail_updates = num_avail_updates + 1
end
end
if num_avail_updates == 0 then
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;status;"
formspec[#formspec + 1] = fgettext("No updates")
formspec[#formspec + 1] = "]"
else
formspec[#formspec + 1] = "button[12.75,0.375;2.625,0.8;update_all;"
formspec[#formspec + 1] = fgettext("Update All [$1]", num_avail_updates)
formspec[#formspec + 1] = "]"
end
end
if #store.packages == 0 then
formspec[#formspec + 1] = "label[4,3;"
formspec[#formspec + 1] = fgettext("No results")
formspec[#formspec + 1] = "button[12.5875,0.375;2.7875,0.8;update_all;"
formspec[#formspec + 1] = fgettext("Update All [$1]", num_avail_updates)
formspec[#formspec + 1] = "]"
end
else
formspec = {
"size[12,7]",
"position[0.5,0.55]",
"label[4,3;", fgettext("No packages could be retrieved"), "]",
"container[0,", H - 0.8 - 0.375, "]",
"button[0,0;4,0.8;back;", fgettext("Back to Main Menu"), "]",
"container_end[]",
}
end
if #store.packages == 0 then
formspec[#formspec + 1] = "label[4,4.75;"
formspec[#formspec + 1] = fgettext("No results")
formspec[#formspec + 1] = "]"
end
-- download/queued tooltips always have the same message
@@ -846,7 +1017,10 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "]"
-- buttons
local left_base = "image_button[-1.55,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir)
local description_width = W - 2.625 - 2 * 0.7 - 2 * 0.15
local second_base = "image_button[-1.55,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir)
local third_base = "image_button[-2.4,0;0.7,0.7;" .. core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "container["
formspec[#formspec + 1] = W - 0.375*2
formspec[#formspec + 1] = ",0.1]"
@@ -856,28 +1030,28 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
elseif package.queued then
formspec[#formspec + 1] = left_base
formspec[#formspec + 1] = second_base
formspec[#formspec + 1] = "cdb_queued.png;queued;]"
elseif not package.path then
local elem_name = "install_" .. i .. ";"
formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]"
formspec[#formspec + 1] = left_base .. "cdb_add.png;" .. elem_name .. "]"
formspec[#formspec + 1] = second_base .. "cdb_add.png;" .. elem_name .. "]"
formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Install") .. tooltip_colors
else
if package.installed_release < package.release then
-- The install_ action also handles updating
local elem_name = "install_" .. i .. ";"
formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#28ccdf]"
formspec[#formspec + 1] = left_base .. "cdb_update.png;" .. elem_name .. "]"
formspec[#formspec + 1] = third_base .. "cdb_update.png;" .. elem_name .. "]"
formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Update") .. tooltip_colors
else
local elem_name = "uninstall_" .. i .. ";"
formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#a93b3b]"
formspec[#formspec + 1] = left_base .. "cdb_clear.png;" .. elem_name .. "]"
formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Uninstall") .. tooltip_colors
description_width = description_width - 0.7 - 0.15
end
local elem_name = "uninstall_" .. i .. ";"
formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#a93b3b]"
formspec[#formspec + 1] = second_base .. "cdb_clear.png;" .. elem_name .. "]"
formspec[#formspec + 1] = "tooltip[" .. elem_name .. fgettext("Uninstall") .. tooltip_colors
end
local web_elem_name = "view_" .. i .. ";"
@@ -888,7 +1062,6 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "container_end[]"
-- description
local description_width = W - 0.375*5 - 0.85 - 2*0.7
formspec[#formspec + 1] = "textarea[1.855,0.3;"
formspec[#formspec + 1] = tostring(description_width)
formspec[#formspec + 1] = ",0.8;;;"
@@ -898,7 +1071,7 @@ function store.get_formspec(dlgdata)
formspec[#formspec + 1] = "container_end[]"
end
return table.concat(formspec, "")
return table.concat(formspec)
end
function store.handle_submit(this, fields)
@@ -952,6 +1125,7 @@ function store.handle_submit(this, fields)
local new_type = table.indexof(filter_types_titles, fields.type)
if new_type ~= filter_type then
filter_type = new_type
cur_page = 1
store.filter_packages(search_string)
return true
end
@@ -975,39 +1149,7 @@ function store.handle_submit(this, fields)
assert(package)
if fields["install_" .. i] then
local install_parent
if package.type == "mod" then
install_parent = core.get_modpath()
elseif package.type == "game" then
install_parent = core.get_gamepath()
elseif package.type == "txp" then
install_parent = core.get_texturepath()
else
error("Unknown package type: " .. package.type)
end
local function on_confirm()
local deps = get_raw_dependencies(package)
if deps and has_hard_deps(deps) then
local dlg = install_dialog.create(package, deps)
dlg:set_parent(this)
this:hide()
dlg:show()
else
queue_download(package, package.path and REASON_UPDATE or REASON_NEW)
end
end
if not package.path and core.is_dir(install_parent .. DIR_DELIM .. package.name) then
local dlg = confirm_overwrite.create(package, on_confirm)
dlg:set_parent(this)
this:hide()
dlg:show()
else
on_confirm()
end
install_or_update_package(this, package)
return true
end
@@ -1031,17 +1173,30 @@ function store.handle_submit(this, fields)
return false
end
function create_store_dlg(type)
if not store.loaded or #store.packages_full == 0 then
store.load()
function store.handle_events(event)
if event == "DialogShow" then
-- On mobile, don't show the "MINETEST" header behind the dialog.
mm_game_theme.set_engine(TOUCHSCREEN_GUI)
-- If the store is already loaded, auto-install packages here.
do_auto_install()
return true
end
store.update_paths()
store.sort_packages()
return false
end
--- Creates a ContentDB dialog.
---
--- @param type string | nil
--- Sets initial package filter. "game", "mod", "txp" or nil (no filter).
--- @param install_spec table | nil
--- ContentDB ID of package as returned by pkgmgr.get_contentdb_id().
--- Sets package to install or update automatically.
function create_store_dlg(type, install_spec)
search_string = ""
cur_page = 1
if type then
-- table.indexof does not work on tables that contain `nil`
for i, v in pairs(filter_types_type) do
@@ -1050,12 +1205,19 @@ function create_store_dlg(type)
break
end
end
else
filter_type = 1
end
store.filter_packages(search_string)
-- Keep the old auto_install_spec if the caller doesn't specify one.
if install_spec then
auto_install_spec = install_spec
end
store.load()
return dialog_create("store",
store.get_formspec,
store.handle_submit,
nil)
store.handle_events)
end

View File

@@ -0,0 +1,22 @@
--Minetest
--Copyright (C) 2023 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local path = core.get_mainmenu_path() .. DIR_DELIM .. "content"
dofile(path .. DIR_DELIM .. "pkgmgr.lua")
dofile(path .. DIR_DELIM .. "update_detector.lua")
dofile(path .. DIR_DELIM .. "dlg_contentstore.lua")

View File

@@ -177,6 +177,7 @@ function pkgmgr.get_mods(path, virtual_path, listing, modpack)
end
end
--------------------------------------------------------------------------------
function pkgmgr.get_texture_packs()
local txtpath = core.get_texturepath()
local txtpath_system = core.get_texturepath_share()
@@ -195,6 +196,23 @@ function pkgmgr.get_texture_packs()
return retval
end
--------------------------------------------------------------------------------
function pkgmgr.get_all()
local result = {}
for _, mod in pairs(pkgmgr.global_mods:get_list()) do
result[#result + 1] = mod
end
for _, game in pairs(pkgmgr.games) do
result[#result + 1] = game
end
for _, txp in pairs(pkgmgr.get_texture_packs()) do
result[#result + 1] = txp
end
return result
end
--------------------------------------------------------------------------------
function pkgmgr.get_folder_type(path)
local testfile = io.open(path .. DIR_DELIM .. "init.lua","r")
@@ -260,7 +278,10 @@ function pkgmgr.is_valid_modname(modpath)
end
--------------------------------------------------------------------------------
function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
--- @param render_list filterlist
--- @param use_technical_names boolean to show technical names instead of human-readable titles
--- @param with_icon table or nil, from virtual path to icon object
function pkgmgr.render_packagelist(render_list, use_technical_names, with_icon)
if not render_list then
if not pkgmgr.global_mods then
pkgmgr.refresh_globals()
@@ -273,10 +294,10 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
for i, v in ipairs(list) do
local color = ""
local icon = 0
local error = with_error and with_error[v.virtual_path]
local function update_error(val)
if val and (not error or (error.type == "warning" and val.type == "error")) then
error = val
local icon_info = with_icon and with_icon[v.virtual_path or v.path]
local function update_icon_info(val)
if val and (not icon_info or (icon_info.type == "warning" and val.type == "error")) then
icon_info = val
end
end
@@ -286,8 +307,8 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
for j = 1, #rawlist do
if rawlist[j].modpack == list[i].name then
if with_error then
update_error(with_error[rawlist[j].virtual_path])
if with_icon then
update_icon_info(with_icon[rawlist[j].virtual_path or rawlist[j].path])
end
if rawlist[j].enabled then
@@ -303,10 +324,10 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
color = mt_color_blue
local rawlist = render_list:get_raw_list()
if v.type == "game" and with_error then
if v.type == "game" and with_icon then
for j = 1, #rawlist do
if rawlist[j].is_game_content then
update_error(with_error[rawlist[j].virtual_path])
update_icon_info(with_icon[rawlist[j].virtual_path or rawlist[j].path])
end
end
end
@@ -315,13 +336,17 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
color = mt_color_green
end
if error then
if error.type == "warning" then
if icon_info then
if icon_info.type == "warning" then
color = mt_color_orange
icon = 2
else
elseif icon_info.type == "error" then
color = mt_color_red
icon = 3
elseif icon_info.type == "update" then
icon = 4
else
error("Unknown icon type " .. icon_info.type)
end
end
@@ -332,7 +357,7 @@ function pkgmgr.render_packagelist(render_list, use_technical_names, with_error)
retval[#retval + 1] = "0"
end
if with_error then
if with_icon then
retval[#retval + 1] = icon
end
@@ -534,7 +559,7 @@ function pkgmgr.install_dir(expected_type, path, basename, targetpath)
-- There's no good way to detect a texture pack, so let's just assume
-- it's correct for now.
if basefolder and basefolder.type ~= "invalid" and basefolder.type ~= "txp" then
return nil, fgettext("Unable to install a $1 as a texture pack", basefolder.type)
return nil, fgettext_ne("Unable to install a $1 as a texture pack", basefolder.type)
end
local from = basefolder and basefolder.path or path
@@ -544,17 +569,17 @@ function pkgmgr.install_dir(expected_type, path, basename, targetpath)
core.delete_dir(targetpath)
if not core.copy_dir(from, targetpath, false) then
return nil,
fgettext("Failed to install $1 to $2", basename, targetpath)
fgettext_ne("Failed to install $1 to $2", basename, targetpath)
end
return targetpath, nil
elseif not basefolder then
return nil, fgettext("Unable to find a valid mod, modpack, or game")
return nil, fgettext_ne("Unable to find a valid mod, modpack, or game")
end
-- Check type
if basefolder.type ~= expected_type and (basefolder.type ~= "modpack" or expected_type ~= "mod") then
return nil, fgettext("Unable to install a $1 as a $2", basefolder.type, expected_type)
return nil, fgettext_ne("Unable to install a $1 as a $2", basefolder.type, expected_type)
end
-- Set targetpath if not predetermined
@@ -575,7 +600,7 @@ function pkgmgr.install_dir(expected_type, path, basename, targetpath)
targetpath = content_path .. DIR_DELIM .. basename
else
return nil,
fgettext("Install: Unable to find suitable folder name for $1", path)
fgettext_ne("Install: Unable to find suitable folder name for $1", path)
end
end
@@ -583,7 +608,7 @@ function pkgmgr.install_dir(expected_type, path, basename, targetpath)
core.delete_dir(targetpath)
if not core.copy_dir(basefolder.path, targetpath, false) then
return nil,
fgettext("Failed to install $1 to $2", basename, targetpath)
fgettext_ne("Failed to install $1 to $2", basename, targetpath)
end
if basefolder.type == "game" then
@@ -752,6 +777,30 @@ function pkgmgr.update_gamelist()
end)
end
--------------------------------------------------------------------------------
-- Returns the ContentDB ID for an installed piece of content.
function pkgmgr.get_contentdb_id(content)
-- core.get_games() will return "" instead of nil if there is no "author" field.
if content.author and content.author ~= "" and content.release > 0 then
if content.type == "game" then
return content.author:lower() .. "/" .. content.id
end
return content.author:lower() .. "/" .. content.name
end
-- Until Minetest 5.8.0, Minetest Game was bundled with Minetest.
-- Unfortunately, the bundled MTG was not versioned (missing "release"
-- field in game.conf).
-- Therefore, we consider any installation of MTG that is not versioned,
-- has not been cloned from Git, and is not system-wide to be updatable.
if content.type == "game" and content.id == "minetest" and content.release == 0 and
not core.is_dir(content.path .. "/.git") and core.may_modify_path(content.path) then
return "minetest/minetest"
end
return nil
end
--------------------------------------------------------------------------------
-- read initial data
--------------------------------------------------------------------------------

View File

@@ -52,12 +52,12 @@ local function reset()
function core.get_gamepath()
return games_dir
end
function env.fgettext(fmt, ...)
function env.fgettext_ne(fmt, ...)
return fmt
end
setfenv(loadfile("builtin/common/misc_helpers.lua"), env)()
setfenv(loadfile("builtin/mainmenu/pkgmgr.lua"), env)()
setfenv(loadfile("builtin/mainmenu/content/pkgmgr.lua"), env)()
function env.pkgmgr.update_gamelist()
table.insert(calls, { "update_gamelist" })

View File

@@ -0,0 +1,139 @@
--Minetest
--Copyright (C) 2023 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
update_detector = {}
if not core.get_http_api then
update_detector.get_all = function() return {} end
update_detector.get_count = function() return 0 end
return
end
local has_fetched = false
local latest_releases
local function fetch_latest_releases()
local version = core.get_version()
local base_url = core.settings:get("contentdb_url")
local url = base_url ..
"/api/updates/?type=mod&type=game&type=txp&protocol_version=" ..
core.get_max_supp_proto() .. "&engine_version=" .. core.urlencode(version.string)
local http = core.get_http_api()
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
return core.parse_json(response.data)
end
--- Get a table from package key (author/name) to latest release id
---
--- @param callback function that takes a single argument, table or nil
local function get_latest_releases(callback)
core.handle_async(fetch_latest_releases, nil, callback)
end
local function has_packages_from_cdb()
pkgmgr.refresh_globals()
pkgmgr.update_gamelist()
for _, content in pairs(pkgmgr.get_all()) do
if pkgmgr.get_contentdb_id(content) then
return true
end
end
return false
end
--- @returns a new table with all keys lowercase
local function lowercase_keys(tab)
local ret = {}
for key, value in pairs(tab) do
ret[key:lower()] = value
end
return ret
end
local function fetch()
if has_fetched or not has_packages_from_cdb() then
return
end
has_fetched = true
get_latest_releases(function(releases)
if not releases then
has_fetched = false
return
end
latest_releases = lowercase_keys(releases)
if update_detector.get_count() > 0 then
local maintab = ui.find_by_name("maintab")
if not maintab.hidden then
ui.update()
end
end
end)
end
--- @returns a list of content with an update available
function update_detector.get_all()
if latest_releases == nil then
fetch()
return {}
end
pkgmgr.refresh_globals()
pkgmgr.update_gamelist()
local ret = {}
local all_content = pkgmgr.get_all()
for _, content in ipairs(all_content) do
local cdb_id = pkgmgr.get_contentdb_id(content)
if cdb_id then
-- The backend will account for aliases in `latest_releases`
local latest_release = latest_releases[cdb_id]
if not latest_release and content.type == "game" then
latest_release = latest_releases[cdb_id .. "_game"]
end
if latest_release and latest_release > content.release then
ret[#ret + 1] = content
end
end
end
return ret
end
--- @return number of packages with updates available
function update_detector.get_count()
return #update_detector.get_all()
end

View File

@@ -245,7 +245,7 @@ local function get_formspec(data)
return retval ..
"tablecolumns[color;tree;image,align=inline,width=1.5,0=" .. core.formspec_escape(defaulttexturedir .. "blank.png") ..
",1=" .. core.formspec_escape(defaulttexturedir .. "checkbox_16_white.png") ..
",1=" .. core.formspec_escape(defaulttexturedir .. "checkbox_16.png") ..
",2=" .. core.formspec_escape(defaulttexturedir .. "error_icon_orange.png") ..
",3=" .. core.formspec_escape(defaulttexturedir .. "error_icon_red.png") .. ";text]" ..
"table[5.5,0.75;5.75,6;world_config_modlist;" ..

View File

@@ -91,16 +91,6 @@ local mgv6_biomes = {
local function create_world_formspec(dialogdata)
-- Point the player to ContentDB when no games are found
if #pkgmgr.games == 0 then
return "size[8,2.5,true]" ..
"style[label_button;border=false]" ..
"button[0.5,0.5;7,0.5;label_button;" ..
fgettext("You have no games installed.") .. "]" ..
"button[0.5,1.5;2.5,0.5;world_create_open_cdb;" .. fgettext("Install a game") .. "]" ..
"button[5.0,1.5;2.5,0.5;world_create_cancel;" .. fgettext("Cancel") .. "]"
end
local current_mg = dialogdata.mg
local mapgens = core.get_mapgen_names()
@@ -310,8 +300,8 @@ local function create_world_formspec(dialogdata)
"label[0,2;" .. fgettext("Mapgen") .. "]"..
"dropdown[0,2.5;6.3;dd_mapgen;" .. mglist .. ";" .. selindex .. "]"
-- Warning if only devtest is installed
if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
-- Warning when making a devtest world
if game.id == "devtest" then
retval = retval ..
"container[0,3.5]" ..
"box[0,0;5.8,1.7;#ff8800]" ..
@@ -363,7 +353,7 @@ local function create_world_buttonhandler(this, fields)
local message
if game == nil then
message = fgettext("No game selected")
message = fgettext_ne("No game selected")
end
if message == nil then
@@ -382,7 +372,7 @@ local function create_world_buttonhandler(this, fields)
end
if menudata.worldlist:uid_exists_raw(worldname) then
message = fgettext("A world named \"$1\" already exists", worldname)
message = fgettext_ne("A world named \"$1\" already exists", worldname)
end
end

View File

@@ -34,7 +34,7 @@ local function delete_content_buttonhandler(this, fields)
this.data.content.path ~= core.get_gamepath() and
this.data.content.path ~= core.get_texturepath() then
if not core.delete_dir(this.data.content.path) then
gamedata.errormessage = fgettext("pkgmgr: failed to delete \"$1\"", this.data.content.path)
gamedata.errormessage = fgettext_ne("pkgmgr: failed to delete \"$1\"", this.data.content.path)
end
if this.data.content.type == "game" then
@@ -43,7 +43,7 @@ local function delete_content_buttonhandler(this, fields)
pkgmgr.refresh_globals()
end
else
gamedata.errormessage = fgettext("pkgmgr: invalid path \"$1\"", this.data.content.path)
gamedata.errormessage = fgettext_ne("pkgmgr: invalid path \"$1\"", this.data.content.path)
end
this:delete()
return true

View File

@@ -0,0 +1,115 @@
--Minetest
--Copyright (C) 2023 Gregor Parzefall
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
function check_reinstall_mtg()
if core.settings:get_bool("no_mtg_notification") then
return
end
local games = core.get_games()
for _, game in ipairs(games) do
if game.id == "minetest" then
core.settings:set_bool("no_mtg_notification", true)
return
end
end
local mtg_world_found = false
local worlds = core.get_worlds()
for _, world in ipairs(worlds) do
if world.gameid == "minetest" then
mtg_world_found = true
break
end
end
if not mtg_world_found then
core.settings:set_bool("no_mtg_notification", true)
return
end
local maintab = ui.find_by_name("maintab")
local dlg = create_reinstall_mtg_dlg()
dlg:set_parent(maintab)
maintab:hide()
dlg:show()
ui.update()
end
local function get_formspec(dialogdata)
local markup = table.concat({
"<big>", fgettext("Minetest Game is no longer installed by default"), "</big>\n",
fgettext("For a long time, the Minetest engine shipped with a default game called \"Minetest Game\". " ..
"Since Minetest 5.8.0, Minetest ships without a default game."), "\n",
fgettext("If you want to continue playing in your Minetest Game worlds, you need to reinstall Minetest Game."),
})
return table.concat({
"formspec_version[6]",
"size[12.8,7]",
"hypertext[0.375,0.375;12.05,5.2;text;", minetest.formspec_escape(markup), "]",
"container[0.375,5.825]",
"style[dismiss;bgcolor=red]",
"button[0,0;4,0.8;dismiss;", fgettext("Dismiss"), "]",
"button[4.25,0;8,0.8;reinstall;", fgettext("Reinstall Minetest Game"), "]",
"container_end[]",
})
end
local function buttonhandler(this, fields)
if fields.reinstall then
-- Don't set "no_mtg_notification" here so that the dialog will be shown
-- again if downloading MTG fails for whatever reason.
this:delete()
local maintab = ui.find_by_name("maintab")
local dlg = create_store_dlg(nil, "minetest/minetest")
dlg:set_parent(maintab)
maintab:hide()
dlg:show()
return true
end
if fields.dismiss then
core.settings:set_bool("no_mtg_notification", true)
this:delete()
return true
end
end
local function eventhandler(event)
if event == "DialogShow" then
mm_game_theme.set_engine()
return true
elseif event == "MenuQuit" then
-- Don't allow closing the dialog with ESC, but still allow exiting
-- Minetest.
core.close()
return true
end
return false
end
function create_reinstall_mtg_dlg()
local dlg = dialog_create("dlg_reinstall_mtg", get_formspec,
buttonhandler, eventhandler)
return dlg
end

File diff suppressed because it is too large Load Diff

View File

@@ -71,6 +71,15 @@ local function version_info_buttonhandler(this, fields)
return false
end
local function version_info_eventhandler(event)
if event == "DialogShow" then
mm_game_theme.set_engine()
return true
end
return false
end
local function create_version_info_dlg(new_version, url)
assert(type(new_version) == "string")
assert(type(url) == "string")
@@ -78,7 +87,7 @@ local function create_version_info_dlg(new_version, url)
local retval = dialog_create("version_info",
version_info_formspec,
version_info_buttonhandler,
nil)
version_info_eventhandler)
retval.data.new_version = new_version
retval.data.url = url

View File

@@ -20,10 +20,6 @@ mm_game_theme = {}
--------------------------------------------------------------------------------
function mm_game_theme.init()
mm_game_theme.defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
DIR_DELIM .. "pack" .. DIR_DELIM
mm_game_theme.basetexturedir = mm_game_theme.defaulttexturedir
mm_game_theme.texturepack = core.settings:get("texture_path")
mm_game_theme.gameid = nil
@@ -32,35 +28,27 @@ function mm_game_theme.init()
end
--------------------------------------------------------------------------------
function mm_game_theme.update(tab,gamedetails)
if tab ~= "singleplayer" then
mm_game_theme.reset()
return
end
if gamedetails == nil then
return
end
mm_game_theme.update_game(gamedetails)
end
--------------------------------------------------------------------------------
function mm_game_theme.reset()
function mm_game_theme.set_engine(hide_decorations)
mm_game_theme.gameid = nil
mm_game_theme.stop_music()
core.set_topleft_text("")
local have_bg = false
local have_overlay = mm_game_theme.set_generic("overlay")
local have_overlay = mm_game_theme.set_engine_single("overlay")
if not have_overlay then
have_bg = mm_game_theme.set_generic("background")
have_bg = mm_game_theme.set_engine_single("background")
end
mm_game_theme.clear("header")
mm_game_theme.clear("footer")
mm_game_theme.clear_single("header")
mm_game_theme.clear_single("footer")
core.set_clouds(false)
mm_game_theme.set_generic("footer")
mm_game_theme.set_generic("header")
if not hide_decorations then
mm_game_theme.set_engine_single("header")
mm_game_theme.set_engine_single("footer")
end
if not have_bg then
if core.settings:get_bool("menu_clouds") then
@@ -69,51 +57,50 @@ function mm_game_theme.reset()
mm_game_theme.set_dirt_bg()
end
end
if mm_game_theme.music_handle ~= nil then
core.sound_stop(mm_game_theme.music_handle)
end
end
--------------------------------------------------------------------------------
function mm_game_theme.update_game(gamedetails)
function mm_game_theme.set_game(gamedetails)
assert(gamedetails ~= nil)
if mm_game_theme.gameid == gamedetails.id then
return
end
mm_game_theme.gameid = gamedetails.id
mm_game_theme.set_music(gamedetails)
core.set_topleft_text(gamedetails.name)
local have_bg = false
local have_overlay = mm_game_theme.set_game("overlay",gamedetails)
local have_overlay = mm_game_theme.set_game_single("overlay", gamedetails)
if not have_overlay then
have_bg = mm_game_theme.set_game("background",gamedetails)
have_bg = mm_game_theme.set_game_single("background", gamedetails)
end
mm_game_theme.clear("header")
mm_game_theme.clear("footer")
mm_game_theme.clear_single("header")
mm_game_theme.clear_single("footer")
core.set_clouds(false)
if not have_bg then
mm_game_theme.set_game_single("header", gamedetails)
mm_game_theme.set_game_single("footer", gamedetails)
if not have_bg then
if core.settings:get_bool("menu_clouds") then
core.set_clouds(true)
else
mm_game_theme.set_dirt_bg()
end
end
mm_game_theme.set_game("footer",gamedetails)
mm_game_theme.set_game("header",gamedetails)
mm_game_theme.gameid = gamedetails.id
end
--------------------------------------------------------------------------------
function mm_game_theme.clear(identifier)
function mm_game_theme.clear_single(identifier)
core.set_background(identifier,"")
end
--------------------------------------------------------------------------------
function mm_game_theme.set_generic(identifier)
function mm_game_theme.set_engine_single(identifier)
--try texture pack first
if mm_game_theme.texturepack ~= nil then
local path = mm_game_theme.texturepack .. DIR_DELIM .."menu_" ..
@@ -123,25 +110,17 @@ function mm_game_theme.set_generic(identifier)
end
end
if mm_game_theme.defaulttexturedir ~= nil then
local path = mm_game_theme.defaulttexturedir .. DIR_DELIM .."menu_" ..
identifier .. ".png"
if core.set_background(identifier,path) then
return true
end
local path = defaulttexturedir .. DIR_DELIM .. "menu_" .. identifier .. ".png"
if core.set_background(identifier, path) then
return true
end
return false
end
--------------------------------------------------------------------------------
function mm_game_theme.set_game(identifier, gamedetails)
if gamedetails == nil then
return false
end
mm_game_theme.set_music(gamedetails)
function mm_game_theme.set_game_single(identifier, gamedetails)
assert(gamedetails ~= nil)
if mm_game_theme.texturepack ~= nil then
local path = mm_game_theme.texturepack .. DIR_DELIM ..
@@ -194,10 +173,18 @@ function mm_game_theme.set_dirt_bg()
end
--------------------------------------------------------------------------------
function mm_game_theme.set_music(gamedetails)
function mm_game_theme.stop_music()
if mm_game_theme.music_handle ~= nil then
core.sound_stop(mm_game_theme.music_handle)
end
end
--------------------------------------------------------------------------------
function mm_game_theme.set_music(gamedetails)
mm_game_theme.stop_music()
assert(gamedetails ~= nil)
local music_path = gamedetails.path .. DIR_DELIM .. "menu" .. DIR_DELIM .. "theme"
mm_game_theme.music_handle = core.sound_play(music_path, true)
end

View File

@@ -28,6 +28,8 @@ local basepath = core.get_builtin_path()
defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
DIR_DELIM .. "pack" .. DIR_DELIM
dofile(menupath .. DIR_DELIM .. "misc.lua")
dofile(basepath .. "common" .. DIR_DELIM .. "filterlist.lua")
dofile(basepath .. "fstk" .. DIR_DELIM .. "buttonbar.lua")
dofile(basepath .. "fstk" .. DIR_DELIM .. "dialog.lua")
@@ -35,27 +37,26 @@ dofile(basepath .. "fstk" .. DIR_DELIM .. "tabview.lua")
dofile(basepath .. "fstk" .. DIR_DELIM .. "ui.lua")
dofile(menupath .. DIR_DELIM .. "async_event.lua")
dofile(menupath .. DIR_DELIM .. "common.lua")
dofile(menupath .. DIR_DELIM .. "pkgmgr.lua")
dofile(menupath .. DIR_DELIM .. "serverlistmgr.lua")
dofile(menupath .. DIR_DELIM .. "game_theme.lua")
dofile(menupath .. DIR_DELIM .. "content" .. DIR_DELIM .. "init.lua")
dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua")
dofile(menupath .. DIR_DELIM .. "dlg_contentstore.lua")
dofile(menupath .. DIR_DELIM .. "settings" .. DIR_DELIM .. "init.lua")
dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_content.lua")
dofile(menupath .. DIR_DELIM .. "dlg_delete_world.lua")
dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua")
local tabs = {}
tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
tabs.content = dofile(menupath .. DIR_DELIM .. "tab_content.lua")
tabs.about = dofile(menupath .. DIR_DELIM .. "tab_about.lua")
tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua")
tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua")
local tabs = {
content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"),
about = dofile(menupath .. DIR_DELIM .. "tab_about.lua"),
local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua"),
play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua")
}
--------------------------------------------------------------------------------
local function main_event_handler(tabview, event)
@@ -86,26 +87,16 @@ local function init_globals()
menudata.worldlist:add_sort_mechanism("alphabetic", sort_worlds_alphabetic)
menudata.worldlist:set_sortmode("alphabetic")
local gameid = core.settings:get("menu_last_game")
local game = gameid and pkgmgr.find_by_gameid(gameid)
if not game then
gameid = core.settings:get("default_game") or "minetest"
game = pkgmgr.find_by_gameid(gameid)
core.settings:set("menu_last_game", gameid)
end
mm_game_theme.init()
mm_game_theme.set_engine() -- This is just a fallback.
-- Create main tabview
local tv_main = tabview_create("maintab", {x = 12, y = 5.4}, {x = 0, y = 0})
-- note: size would be 15.5,7.1 in real coordinates mode
local tv_main = tabview_create("maintab", {x = 15.5, y = 7.1}, {x = 0, y = 0})
tv_main:set_autosave_tab(true)
tv_main:add(tabs.local_game)
tv_main:add(tabs.play_online)
tv_main:add(tabs.content)
tv_main:add(tabs.settings)
tv_main:add(tabs.about)
tv_main:set_global_event_handler(main_event_handler)
@@ -116,16 +107,25 @@ local function init_globals()
tv_main:set_tab(last_tab)
end
-- In case the folder of the last selected game has been deleted,
-- display "Minetest" as a header
if tv_main.current_tab == "local" and not game then
mm_game_theme.reset()
end
tv_main:set_end_button({
icon = defaulttexturedir .. "settings_btn.png",
label = fgettext("Settings"),
name = "open_settings",
on_click = function(tabview)
local dlg = create_settings_dlg()
dlg:set_parent(tabview)
tabview:hide()
dlg:show()
return true
end,
})
ui.set_default("maintab")
check_new_version()
tv_main:show()
ui.update()
check_reinstall_mtg()
check_new_version()
end
init_globals()

View File

@@ -0,0 +1,6 @@
-- old non-method sound function
function core.sound_stop(handle, ...)
return handle:stop(...)
end

View File

@@ -0,0 +1,407 @@
--Minetest
--Copyright (C) 2022 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local make = {}
-- This file defines various component constructors, of the form:
--
-- make.component(setting)
--
-- `setting` is a table representing the settingtype.
--
-- A component is a table with the following:
--
-- * `full_width`: (Optional) true if the component shouldn't reserve space for info / reset.
-- * `info_text`: (Optional) string, informational text shown in an info icon.
-- * `setting`: (Optional) the setting.
-- * `max_w`: (Optional) maximum width, `avail_w` will never exceed this.
-- * `resettable`: (Optional) if this is true, a reset button is shown.
-- * `get_formspec = function(self, avail_w)`:
-- * `avail_w` is the available width for the component.
-- * Returns `fs, used_height`.
-- * `fs` is a string for the formspec.
-- Components should be relative to `0,0`, and not exceed `avail_w` or the returned `used_height`.
-- * `used_height` is the space used by components in `fs`.
-- * `on_submit = function(self, fields, parent)`:
-- * `fields`: submitted formspec fields
-- * `parent`: the fstk element for the settings UI, use to show dialogs
-- * Return true if the event was handled, to prevent future components receiving it.
local function get_label(setting)
local show_technical_names = core.settings:get_bool("show_technical_names")
if not show_technical_names and setting.readable_name then
return fgettext(setting.readable_name)
end
return setting.name
end
local function is_valid_number(value)
return type(value) == "number" and not (value ~= value or value >= math.huge or value <= -math.huge)
end
function make.heading(text)
return {
full_width = true,
get_formspec = function(self, avail_w)
return ("label[0,0.6;%s]box[0,0.9;%f,0.05;#ccc6]"):format(core.formspec_escape(text), avail_w), 1.2
end,
}
end
--- Used for string and numeric style fields
---
--- @param converter Function to coerce values from strings.
--- @param validator Validator function, optional. Returns true when valid.
--- @param stringifier Function to convert values to strings, optional.
local function make_field(converter, validator, stringifier)
return function(setting)
return {
info_text = setting.comment,
setting = setting,
get_formspec = function(self, avail_w)
local value = core.settings:get(setting.name) or setting.default
self.resettable = core.settings:has(setting.name)
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))
fs = fs .. ("field_enter_after_edit[%s;true]"):format(setting.name)
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
end,
on_submit = function(self, fields)
if fields["set_" .. setting.name] or fields.key_enter_field == setting.name then
local value = converter(fields[setting.name])
if value == nil or (validator and not validator(value)) then
return true
end
if setting.min then
value = math.max(value, setting.min)
end
if setting.max then
value = math.min(value, setting.max)
end
core.settings:set(setting.name, (stringifier or tostring)(value))
return true
end
end,
}
end
end
make.float = make_field(tonumber, is_valid_number, function(x)
local str = tostring(x)
if str:match("^[+-]?%d+$") then
str = str .. ".0"
end
return str
end)
make.int = make_field(function(x)
local value = tonumber(x)
return value and math.floor(value)
end, is_valid_number)
make.string = make_field(tostring, nil)
function make.bool(setting)
return {
info_text = setting.comment,
setting = setting,
get_formspec = function(self, avail_w)
local value = core.settings:get_bool(setting.name, core.is_yes(setting.default))
self.resettable = core.settings:has(setting.name)
local fs = ("checkbox[0,0.25;%s;%s;%s]"):format(
setting.name, get_label(setting), tostring(value))
return fs, 0.5
end,
on_submit = function(self, fields)
if fields[setting.name] == nil then
return false
end
core.settings:set_bool(setting.name, core.is_yes(fields[setting.name]))
return true
end,
}
end
function make.enum(setting)
return {
info_text = setting.comment,
setting = setting,
max_w = 4.5,
get_formspec = function(self, avail_w)
local value = core.settings:get(setting.name) or setting.default
self.resettable = core.settings:has(setting.name)
local labels = setting.option_labels or {}
local items = {}
for i, option in ipairs(setting.values) do
items[i] = core.formspec_escape(labels[option] or option)
end
local selected_idx = table.indexof(setting.values, value)
local fs = "label[0,0.1;" .. get_label(setting) .. "]"
fs = fs .. ("dropdown[0,0.3;%f,0.8;%s;%s;%d;true]"):format(
avail_w, setting.name, table.concat(items, ","), selected_idx, value)
return fs, 1.1
end,
on_submit = function(self, fields)
local old_value = core.settings:get(setting.name) or setting.default
local idx = tonumber(fields[setting.name]) or 0
local value = setting.values[idx]
if value == nil or value == old_value then
return false
end
core.settings:set(setting.name, value)
return true
end,
}
end
local function make_path(setting)
return {
info_text = setting.comment,
setting = setting,
get_formspec = function(self, avail_w)
local value = core.settings:get(setting.name) or setting.default
self.resettable = core.settings:has(setting.name)
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))
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"))
return fs, 1.1
end,
on_submit = function(self, fields)
local dialog_name = "dlg_path_" .. setting.name
if fields["pick_" .. setting.name] then
local is_file = setting.type ~= "path"
core.show_path_select_dialog(dialog_name,
is_file and fgettext_ne("Select file") or fgettext_ne("Select directory"), is_file)
return true
end
if fields[dialog_name .. "_accepted"] then
local value = fields[dialog_name .. "_accepted"]
if value ~= nil then
core.settings:set(setting.name, value)
end
return true
end
if fields["set_" .. setting.name] or fields.key_enter_field == setting.name then
local value = fields[setting.name]
if value ~= nil then
core.settings:set(setting.name, value)
end
return true
end
end,
}
end
if PLATFORM == "Android" then
-- The Irrlicht file picker doesn't work on Android.
make.path = make.string
make.filepath = make.string
else
make.path = make_path
make.filepath = make_path
end
function make.v3f(setting)
return {
info_text = setting.comment,
setting = setting,
get_formspec = function(self, avail_w)
local value = vector.from_string(core.settings:get(setting.name) or setting.default)
self.resettable = core.settings:has(setting.name)
-- Allocate space for "Set" button
avail_w = avail_w - 1
local fs = "label[0,0.1;" .. get_label(setting) .. "]"
local field_width = (avail_w - 3*0.25) / 3
fs = fs .. ("field[%f,0.6;%f,0.8;%s;%s;%s]"):format(
0, field_width, setting.name .. "_x", "X", value.x)
fs = fs .. ("field[%f,0.6;%f,0.8;%s;%s;%s]"):format(
field_width + 0.25, field_width, setting.name .. "_y", "Y", value.y)
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)
fs = fs .. ("button[%f,0.6;1,0.8;%s;%s]"):format(avail_w, "set_" .. setting.name, fgettext("Set"))
return fs, 1.4
end,
on_submit = function(self, fields)
if fields["set_" .. setting.name] or
fields.key_enter_field == setting.name .. "_x" or
fields.key_enter_field == setting.name .. "_y" or
fields.key_enter_field == setting.name .. "_z" then
local x = tonumber(fields[setting.name .. "_x"])
local y = tonumber(fields[setting.name .. "_y"])
local z = tonumber(fields[setting.name .. "_z"])
if is_valid_number(x) and is_valid_number(y) and is_valid_number(z) then
core.settings:set(setting.name, vector.new(x, y, z):to_string())
else
core.log("error", "Invalid vector: " .. dump({x, y, z}))
end
return true
end
end,
}
end
function make.flags(setting)
local checkboxes = {}
return {
info_text = setting.comment,
setting = setting,
get_formspec = function(self, avail_w)
local fs = {
"label[0,0.1;" .. get_label(setting) .. "]",
}
local value = core.settings:get(setting.name) or setting.default
self.resettable = core.settings:has(setting.name)
checkboxes = {}
for _, name in ipairs(value:split(",")) do
name = name:trim()
if name:sub(1, 2) == "no" then
checkboxes[name:sub(3)] = false
elseif name ~= "" then
checkboxes[name] = true
end
end
local columns = math.max(math.floor(avail_w / 2.5), 1)
local column_width = avail_w / columns
local x = 0
local y = 0.55
for _, possible in ipairs(setting.possible) do
if possible:sub(1, 2) ~= "no" then
if x >= avail_w then
x = 0
y = y + 0.5
end
local is_checked = checkboxes[possible]
fs[#fs + 1] = ("checkbox[%f,%f;%s;%s;%s]"):format(
x, y, setting.name .. "_" .. possible,
core.formspec_escape(possible), tostring(is_checked))
x = x + column_width
end
end
return table.concat(fs, ""), y + 0.25
end,
on_submit = function(self, fields)
local changed = false
for name, _ in pairs(checkboxes) do
local value = fields[setting.name .. "_" .. name]
if value ~= nil then
checkboxes[name] = core.is_yes(value)
changed = true
end
end
if changed then
local values = {}
for _, name in ipairs(setting.possible) do
if name:sub(1, 2) ~= "no" then
if checkboxes[name] then
table.insert(values, name)
else
table.insert(values, "no" .. name)
end
end
end
core.settings:set(setting.name, table.concat(values, ","))
end
return changed
end
}
end
local function make_noise_params(setting)
return {
info_text = setting.comment,
setting = setting,
get_formspec = function(self, avail_w)
-- The "defaults" noise parameter flag doesn't reset a noise
-- setting to its default value, so we offer a regular reset button.
self.resettable = core.settings:has(setting.name)
local fs = "label[0,0.4;" .. get_label(setting) .. "]" ..
("button[%f,0;2.5,0.8;%s;%s]"):format(avail_w - 2.5, "edit_" .. setting.name, fgettext("Edit"))
return fs, 0.8
end,
on_submit = function(self, fields, tabview)
if fields["edit_" .. setting.name] then
local dlg = create_change_mapgen_flags_dlg(setting)
dlg:set_parent(tabview)
tabview:hide()
dlg:show()
return true
end
end,
}
end
make.noise_params_2d = make_noise_params
make.noise_params_3d = make_noise_params
return make

View File

@@ -0,0 +1,252 @@
--Minetest
--Copyright (C) 2015 PilzAdam
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local checkboxes = {}
local function flags_to_table(flags)
return flags:gsub("%s+", ""):split(",", true) -- Remove all spaces and split
end
local function get_current_np_group(setting)
local value = core.settings:get_np_group(setting.name)
if value == nil then
return setting.values
end
local p = "%g"
return {
p:format(value.offset),
p:format(value.scale),
p:format(value.spread.x),
p:format(value.spread.y),
p:format(value.spread.z),
p:format(value.seed),
p:format(value.octaves),
p:format(value.persistence),
p:format(value.lacunarity),
value.flags
}
end
local function get_formspec(dialogdata)
local setting = dialogdata.setting
-- Final formspec will be created at the end of this function
-- Default values below, may be changed depending on setting type
local width = 10
local height = 2
local description_height = 1.5
local t = get_current_np_group(setting)
local dimension = 3
if setting.type == "noise_params_2d" then
dimension = 2
end
local fields = {}
local function add_field(x, name, label, value)
fields[#fields + 1] = ("field[%f,%f;3.3,1;%s;%s;%s]"):format(
x, height, name, label, core.formspec_escape(value or "")
)
end
-- First row
height = height + 0.3
add_field(0.3, "te_offset", fgettext("Offset"), t[1])
add_field(3.6, "te_scale", fgettext("Scale"), t[2])
add_field(6.9, "te_seed", fgettext("Seed"), t[6])
height = height + 1.1
-- Second row
add_field(0.3, "te_spreadx", fgettext("X spread"), t[3])
if dimension == 3 then
add_field(3.6, "te_spready", fgettext("Y spread"), t[4])
else
fields[#fields + 1] = "label[4," .. height - 0.2 .. ";" ..
fgettext("2D Noise") .. "]"
end
add_field(6.9, "te_spreadz", fgettext("Z spread"), t[5])
height = height + 1.1
-- Third row
add_field(0.3, "te_octaves", fgettext("Octaves"), t[7])
add_field(3.6, "te_persist", fgettext("Persistence"), t[8])
add_field(6.9, "te_lacun", fgettext("Lacunarity"), t[9])
height = height + 1.1
local enabled_flags = flags_to_table(t[10])
local flags = {}
for _, name in ipairs(enabled_flags) do
-- Index by name, to avoid iterating over all enabled_flags for every possible flag.
flags[name] = true
end
for _, name in ipairs(setting.flags) do
local checkbox_name = "cb_" .. name
local is_enabled = flags[name] == true -- to get false if nil
checkboxes[checkbox_name] = is_enabled
end
local formspec = table.concat(fields)
.. "checkbox[0.5," .. height - 0.6 .. ";cb_defaults;"
--[[~ "defaults" is a noise parameter flag.
It describes the default processing options
for noise settings in the settings menu. ]]
.. fgettext("defaults") .. ";" -- defaults
.. tostring(flags["defaults"] == true) .. "]" -- to get false if nil
.. "checkbox[5," .. height - 0.6 .. ";cb_eased;"
--[[~ "eased" is a noise parameter flag.
It is used to make the map smoother and
can be enabled in noise settings in
the settings menu. ]]
.. fgettext("eased") .. ";" -- eased
.. tostring(flags["eased"] == true) .. "]"
.. "checkbox[5," .. height - 0.15 .. ";cb_absvalue;"
--[[~ "absvalue" is a noise parameter flag.
It is short for "absolute value".
It can be enabled in noise settings in
the settings menu. ]]
.. fgettext("absvalue") .. ";" -- absvalue
.. tostring(flags["absvalue"] == true) .. "]"
height = height + 1
-- Box good, textarea bad. Calculate textarea size from box.
local function create_textfield(size, label, text, bg_color)
local textarea = {
x = size.x + 0.3,
y = size.y,
w = size.w + 0.25,
h = size.h * 1.16 + 0.12
}
return ("box[%f,%f;%f,%f;%s]textarea[%f,%f;%f,%f;;%s;%s]"):format(
size.x, size.y, size.w, size.h, bg_color or "#000",
textarea.x, textarea.y, textarea.w, textarea.h,
core.formspec_escape(label), core.formspec_escape(text)
)
end
-- When there's an error: Shrink description textarea and add error below
if dialogdata.error_message then
local error_box = {
x = 0,
y = description_height - 0.4,
w = width - 0.25,
h = 0.5
}
formspec = formspec ..
create_textfield(error_box, "", dialogdata.error_message, "#600")
description_height = description_height - 0.75
end
-- Get description field
local description_box = {
x = 0,
y = 0.2,
w = width - 0.25,
h = description_height
}
local setting_name = setting.name
if setting.readable_name then
setting_name = fgettext_ne(setting.readable_name) ..
" (" .. setting.name .. ")"
end
local comment_text
if setting.comment == "" then
comment_text = fgettext_ne("(No description of setting given)")
else
comment_text = fgettext_ne(setting.comment)
end
return (
"size[" .. width .. "," .. height + 0.25 .. ",true]" ..
create_textfield(description_box, setting_name, comment_text) ..
formspec ..
"button[" .. width / 2 - 2.5 .. "," .. height - 0.4 .. ";2.5,1;btn_done;" ..
fgettext("Save") .. "]" ..
"button[" .. width / 2 .. "," .. height - 0.4 .. ";2.5,1;btn_cancel;" ..
fgettext("Cancel") .. "]"
)
end
local function buttonhandler(this, fields)
local setting = this.data.setting
if fields["btn_done"] or fields["key_enter"] then
local np_flags = {}
for _, name in ipairs(setting.flags) do
if checkboxes["cb_" .. name] then
table.insert(np_flags, name)
end
end
checkboxes = {}
if setting.type == "noise_params_2d" then
fields["te_spready"] = fields["te_spreadz"]
end
local new_value = {
offset = fields["te_offset"],
scale = fields["te_scale"],
spread = {
x = fields["te_spreadx"],
y = fields["te_spready"],
z = fields["te_spreadz"]
},
seed = fields["te_seed"],
octaves = fields["te_octaves"],
persistence = fields["te_persist"],
lacunarity = fields["te_lacun"],
flags = table.concat(np_flags, ", ")
}
core.settings:set_np_group(setting.name, new_value)
core.settings:write()
this:delete()
return true
end
if fields["btn_cancel"] then
this:delete()
return true
end
for name, value in pairs(fields) do
if name:sub(1, 3) == "cb_" then
checkboxes[name] = core.is_yes(value)
return false -- Don't update the formspec!
end
end
return false
end
function create_change_mapgen_flags_dlg(setting)
assert(type(setting) == "table")
local retval = dialog_create("dlg_change_mapgen_flags",
get_formspec,
buttonhandler,
nil)
retval.data.setting = setting
return retval
end

View File

@@ -0,0 +1,725 @@
--Minetest
--Copyright (C) 2022 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local component_funcs = dofile(core.get_mainmenu_path() .. DIR_DELIM ..
"settings" .. DIR_DELIM .. "components.lua")
local shadows_component = dofile(core.get_mainmenu_path() .. DIR_DELIM ..
"settings" .. DIR_DELIM .. "shadows_component.lua")
local full_settings = settingtypes.parse_config_file(false, true)
local info_icon_path = core.formspec_escape(defaulttexturedir .. "settings_info.png")
local reset_icon_path = core.formspec_escape(defaulttexturedir .. "settings_reset.png")
local all_pages = {}
local page_by_id = {}
local filtered_pages = all_pages
local filtered_page_by_id = page_by_id
local function add_page(page)
assert(type(page.id) == "string")
assert(type(page.title) == "string")
assert(page.section == nil or type(page.section) == "string")
assert(type(page.content) == "table")
assert(not page_by_id[page.id], "Page " .. page.id .. " already registered")
all_pages[#all_pages + 1] = page
page_by_id[page.id] = page
return page
end
local change_keys = {
query_text = "Change Keys",
requires = {
keyboard_mouse = true,
},
get_formspec = function(self, avail_w)
local btn_w = math.min(avail_w, 3)
return ("button[0,0;%f,0.8;btn_change_keys;%s]"):format(btn_w, fgettext("Change Keys")), 0.8
end,
on_submit = function(self, fields)
if fields.btn_change_keys then
core.show_keys_menu()
end
end,
}
add_page({
id = "accessibility",
title = fgettext_ne("Accessibility"),
content = {
"language",
{ heading = fgettext_ne("General") },
"font_size",
"chat_font_size",
"gui_scaling",
"hud_scaling",
"show_nametag_backgrounds",
{ heading = fgettext_ne("Chat") },
"console_height",
"console_alpha",
"console_color",
{ heading = fgettext_ne("Controls") },
"autojump",
"safe_dig_and_place",
{ heading = fgettext_ne("Movement") },
"arm_inertia",
"view_bobbing_amount",
"fall_bobbing_amount",
},
})
local function load_settingtypes()
local page = nil
local section = nil
local function ensure_page_started()
if not page then
page = add_page({
id = (section or "general"):lower():gsub(" ", "_"),
title = section or fgettext_ne("General"),
section = section,
content = {},
})
end
end
for _, entry in ipairs(full_settings) do
if entry.type == "category" then
if entry.level == 0 then
section = entry.name
page = nil
elseif entry.level == 1 then
page = {
id = ((section and section .. "_" or "") .. entry.name):lower():gsub(" ", "_"),
title = entry.readable_name or entry.name,
section = section,
content = {},
}
page = add_page(page)
elseif entry.level == 2 then
ensure_page_started()
page.content[#page.content + 1] = {
heading = fgettext_ne(entry.readable_name or entry.name),
}
end
else
ensure_page_started()
page.content[#page.content + 1] = entry.name
end
end
end
load_settingtypes()
table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys)
do
local content = page_by_id.graphics_and_audio_shaders.content
local idx = table.indexof(content, "enable_dynamic_shadows")
table.insert(content, idx, shadows_component)
end
local function get_setting_info(name)
for _, entry in ipairs(full_settings) do
if entry.type ~= "category" and entry.name == name then
return entry
end
end
return nil
end
-- These must not be translated, as they need to show in the local
-- language no matter the user's current language.
-- This list must be kept in sync with src/unsupported_language_list.txt.
get_setting_info("language").option_labels = {
[""] = fgettext_ne("(Use system language)"),
--ar = " [ar]", blacklisted
be = "Беларуская [be]",
bg = "Български [bg]",
ca = "Català [ca]",
cs = "Česky [cs]",
cy = "Cymraeg [cy]",
da = "Dansk [da]",
de = "Deutsch [de]",
--dv = " [dv]", blacklisted
el = "Ελληνικά [el]",
en = "English [en]",
eo = "Esperanto [eo]",
es = "Español [es]",
et = "Eesti [et]",
eu = "Euskara [eu]",
fi = "Suomi [fi]",
fil = "Wikang Filipino [fil]",
fr = "Français [fr]",
gd = "Gàidhlig [gd]",
gl = "Galego [gl]",
--he = " [he]", blacklisted
--hi = " [hi]", blacklisted
hu = "Magyar [hu]",
id = "Bahasa Indonesia [id]",
it = "Italiano [it]",
ja = "日本語 [ja]",
jbo = "Lojban [jbo]",
kk = "Қазақша [kk]",
--kn = " [kn]", blacklisted
ko = "한국어 [ko]",
ky = "Kırgızca / Кыргызча [ky]",
lt = "Lietuvių [lt]",
lv = "Latviešu [lv]",
mn = "Монгол [mn]",
mr = "मराठी [mr]",
ms = "Bahasa Melayu [ms]",
--ms_Arab = " [ms_Arab]", blacklisted
nb = "Norsk Bokmål [nb]",
nl = "Nederlands [nl]",
nn = "Norsk Nynorsk [nn]",
oc = "Occitan [oc]",
pl = "Polski [pl]",
pt = "Português [pt]",
pt_BR = "Português do Brasil [pt_BR]",
ro = "Română [ro]",
ru = "Русский [ru]",
sk = "Slovenčina [sk]",
sl = "Slovenščina [sl]",
sr_Cyrl = "Српски [sr_Cyrl]",
sr_Latn = "Srpski (Latinica) [sr_Latn]",
sv = "Svenska [sv]",
sw = "Kiswahili [sw]",
--th = " [th]", blacklisted
tr = "Türkçe [tr]",
tt = "Tatarça [tt]",
uk = "Українська [uk]",
vi = "Tiếng Việt [vi]",
zh_CN = "中文 (简体) [zh_CN]",
zh_TW = "正體中文 (繁體) [zh_TW]",
}
-- See if setting matches keywords
local function get_setting_match_weight(entry, query_keywords)
local setting_score = 0
for _, keyword in ipairs(query_keywords) do
if string.find(entry.name:lower(), keyword, 1, true) then
setting_score = setting_score + 1
end
if entry.readable_name and
string.find(fgettext(entry.readable_name):lower(), keyword, 1, true) then
setting_score = setting_score + 1
end
if entry.comment and
string.find(fgettext_ne(entry.comment):lower(), keyword, 1, true) then
setting_score = setting_score + 1
end
end
return setting_score
end
local function filter_page_content(page, query_keywords)
if #query_keywords == 0 then
return page.content, 0
end
local retval = {}
local i = 1
local max_weight = 0
for _, content in ipairs(page.content) do
if type(content) == "string" then
local setting = get_setting_info(content)
assert(setting, "Unknown setting: " .. content)
local weight = get_setting_match_weight(setting, query_keywords)
if weight > 0 then
max_weight = math.max(max_weight, weight)
retval[i] = content
i = i + 1
end
elseif type(content) == "table" and content.query_text then
for _, keyword in ipairs(query_keywords) do
if string.find(fgettext(content.query_text), keyword, 1, true) then
max_weight = math.max(max_weight, 1)
retval[i] = content
i = i + 1
break
end
end
end
end
return retval, max_weight
end
local function update_filtered_pages(query)
filtered_pages = {}
filtered_page_by_id = {}
local query_keywords = {}
for word in query:lower():gmatch("%S+") do
table.insert(query_keywords, word)
end
local best_page = nil
local best_page_weight = -1
for _, page in ipairs(all_pages) do
local content, page_weight = filter_page_content(page, query_keywords)
if page_has_contents(page, content) then
local new_page = table.copy(page)
new_page.content = content
filtered_pages[#filtered_pages + 1] = new_page
filtered_page_by_id[new_page.id] = new_page
if page_weight > best_page_weight then
best_page = new_page
best_page_weight = page_weight
end
end
end
return best_page and best_page.id or nil
end
local function check_requirements(name, requires)
if requires == nil then
return true
end
local video_driver = core.get_active_driver()
local shaders_support = video_driver == "opengl" or video_driver == "ogles2"
local special = {
android = PLATFORM == "Android",
desktop = PLATFORM ~= "Android",
touchscreen_gui = TOUCHSCREEN_GUI,
keyboard_mouse = not TOUCHSCREEN_GUI,
shaders_support = shaders_support,
shaders = core.settings:get_bool("enable_shaders") and shaders_support,
opengl = video_driver == "opengl",
gles = video_driver:sub(1, 5) == "ogles",
}
for req_key, req_value in pairs(requires) do
if special[req_key] == nil then
local required_setting = get_setting_info(req_key)
if required_setting == nil then
core.log("warning", "Unknown setting " .. req_key .. " required by " .. name)
end
local actual_value = core.settings:get_bool(req_key,
required_setting and core.is_yes(required_setting.default))
if actual_value ~= req_value then
return false
end
elseif special[req_key] ~= req_value then
return false
end
end
return true
end
function page_has_contents(page, actual_content)
local is_advanced =
page.id:sub(1, #"client_and_server") == "client_and_server" or
page.id:sub(1, #"mapgen") == "mapgen" or
page.id:sub(1, #"advanced") == "advanced"
local show_advanced = core.settings:get_bool("show_advanced")
if is_advanced and not show_advanced then
return false
end
for _, item in ipairs(actual_content) do
if item == false or item.heading then --luacheck: ignore
-- skip
elseif type(item) == "string" then
local setting = get_setting_info(item)
assert(setting, "Unknown setting: " .. item)
if check_requirements(setting.name, setting.requires) then
return true
end
elseif item.get_formspec then
if check_requirements(item.id, item.requires) then
return true
end
else
error("Unknown content in page: " .. dump(item))
end
end
return false
end
local function build_page_components(page)
-- Filter settings based on requirements
local content = {}
local last_heading
for _, item in ipairs(page.content) do
if item == false then --luacheck: ignore
-- skip
elseif item.heading then
last_heading = item
else
local name, requires
if type(item) == "string" then
local setting = get_setting_info(item)
assert(setting, "Unknown setting: " .. item)
name = setting.name
requires = setting.requires
elseif item.get_formspec then
name = item.id
requires = item.requires
else
error("Unknown content in page: " .. dump(item))
end
if check_requirements(name, requires) then
if last_heading then
content[#content + 1] = last_heading
last_heading = nil
end
content[#content + 1] = item
end
end
end
-- Create components
local retval = {}
for i, item in ipairs(content) do
if type(item) == "string" then
local setting = get_setting_info(item)
local component_func = component_funcs[setting.type]
assert(component_func, "Unknown setting type: " .. setting.type)
retval[i] = component_func(setting)
elseif item.get_formspec then
retval[i] = item
elseif item.heading then
retval[i] = component_funcs.heading(item.heading)
end
end
return retval
end
--- Creates a scrollbaroptions for a scroll_container
--
-- @param visible_l the length of the scroll_container and scrollbar
-- @param total_l length of the scrollable area
-- @param scroll_factor as passed to scroll_container
local function make_scrollbaroptions_for_scroll_container(visible_l, total_l, scroll_factor)
assert(total_l >= visible_l)
local max = total_l - visible_l
local thumb_size = (visible_l / total_l) * max
return ("scrollbaroptions[min=0;max=%f;thumbsize=%f]"):format(max / scroll_factor, thumb_size / scroll_factor)
end
local formspec_show_hack = false
local function get_formspec(dialogdata)
local page_id = dialogdata.page_id or "accessibility"
local page = filtered_page_by_id[page_id]
local extra_h = 1 -- not included in tabsize.height
local tabsize = {
width = TOUCHSCREEN_GUI and 16.5 or 15.5,
height = TOUCHSCREEN_GUI and (10 - extra_h) or 12,
}
local scrollbar_w = TOUCHSCREEN_GUI and 0.6 or 0.4
local left_pane_width = TOUCHSCREEN_GUI and 4.5 or 4.25
local search_width = left_pane_width + scrollbar_w - (0.75 * 2)
local back_w = 3
local checkbox_w = (tabsize.width - back_w - 2*0.2) / 2
local show_technical_names = core.settings:get_bool("show_technical_names")
local show_advanced = core.settings:get_bool("show_advanced")
formspec_show_hack = not formspec_show_hack
local fs = {
"formspec_version[6]",
"size[", tostring(tabsize.width), ",", tostring(tabsize.height + extra_h), "]",
TOUCHSCREEN_GUI and "padding[0.01,0.01]" or "",
"bgcolor[#0000]",
-- HACK: this is needed to allow resubmitting the same formspec
formspec_show_hack and " " or "",
"box[0,0;", tostring(tabsize.width), ",", tostring(tabsize.height), ";#0000008C]",
("button[0,%f;%f,0.8;back;%s]"):format(
tabsize.height + 0.2, back_w, fgettext("Back")),
("box[%f,%f;%f,0.8;#0000008C]"):format(
back_w + 0.2, tabsize.height + 0.2, checkbox_w),
("checkbox[%f,%f;show_technical_names;%s;%s]"):format(
back_w + 2*0.2, tabsize.height + 0.6,
fgettext("Show technical names"), tostring(show_technical_names)),
("box[%f,%f;%f,0.8;#0000008C]"):format(
back_w + 2*0.2 + checkbox_w, tabsize.height + 0.2, checkbox_w),
("checkbox[%f,%f;show_advanced;%s;%s]"):format(
back_w + 3*0.2 + checkbox_w, tabsize.height + 0.6,
fgettext("Show advanced settings"), tostring(show_advanced)),
"field[0.25,0.25;", tostring(search_width), ",0.75;search_query;;",
core.formspec_escape(dialogdata.query or ""), "]",
"field_enter_after_edit[search_query;true]",
"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.75,0;0.75,0.75;", core.formspec_escape(defaulttexturedir .. "clear.png"), ";search_clear;]",
"tooltip[search;", fgettext("Search"), "]",
"tooltip[search_clear;", fgettext("Clear"), "]",
"container_end[]",
"scroll_container[0.25,1.25;", tostring(left_pane_width), ",",
tostring(tabsize.height - 1.5), ";leftscroll;vertical;0.1]",
"style_type[button;border=false;bgcolor=#3333]",
"style_type[button:hover;border=false;bgcolor=#6663]",
}
local y = 0
local last_section = nil
for _, other_page in ipairs(filtered_pages) do
if other_page.section ~= last_section then
fs[#fs + 1] = ("label[0.1,%f;%s]"):format(
y + 0.41, core.colorize("#ff0", fgettext(other_page.section)))
last_section = other_page.section
y = y + 0.82
end
fs[#fs + 1] = ("box[0,%f;%f,0.8;%s]"):format(
y, left_pane_width, other_page.id == page_id and "#467832FF" or "#3339")
fs[#fs + 1] = ("button[0,%f;%f,0.8;page_%s;%s]")
:format(y, left_pane_width, other_page.id, fgettext(other_page.title))
y = y + 0.82
end
if #filtered_pages == 0 then
fs[#fs + 1] = "label[0.1,0.41;"
fs[#fs + 1] = fgettext("No results")
fs[#fs + 1] = "]"
end
fs[#fs + 1] = "scroll_container_end[]"
if y >= tabsize.height - 1.25 then
fs[#fs + 1] = make_scrollbaroptions_for_scroll_container(tabsize.height - 1.5, y, 0.1)
fs[#fs + 1] = ("scrollbar[%f,1.25;%f,%f;vertical;leftscroll;%f]"):format(
left_pane_width + 0.25, scrollbar_w, tabsize.height - 1.5, dialogdata.leftscroll or 0)
end
fs[#fs + 1] = "style_type[button;border=;bgcolor=]"
if not dialogdata.components then
dialogdata.components = page and build_page_components(page) or {}
end
local right_pane_width = tabsize.width - left_pane_width - 0.375 - 2*scrollbar_w - 0.25
fs[#fs + 1] = ("scroll_container[%f,0;%f,%f;rightscroll;vertical;0.1]"):format(
tabsize.width - right_pane_width - scrollbar_w, right_pane_width, tabsize.height)
y = 0.25
for i, comp in ipairs(dialogdata.components) do
fs[#fs + 1] = ("container[0,%f]"):format(y)
local avail_w = right_pane_width - 0.25
if not comp.full_width then
avail_w = avail_w - 1.4
end
if comp.max_w then
avail_w = math.min(avail_w, comp.max_w)
end
local comp_fs, used_h = comp:get_formspec(avail_w)
fs[#fs + 1] = comp_fs
fs[#fs + 1] = "style_type[image_button;border=false;padding=]"
local show_reset = comp.resettable and comp.setting
local show_info = comp.info_text and comp.info_text ~= ""
if show_reset or show_info then
-- ensure there's enough space for reset/info
used_h = math.max(used_h, 0.5)
end
local info_reset_y = used_h / 2 - 0.25
if show_reset then
local default = comp.setting.default
local reset_tooltip = default and
fgettext("Reset setting to default ($1)", tostring(default)) or
fgettext("Reset setting to default")
fs[#fs + 1] = ("image_button[%f,%f;0.5,0.5;%s;%s;]"):format(
right_pane_width - 1.4, info_reset_y, reset_icon_path, "reset_" .. i)
fs[#fs + 1] = ("tooltip[%s;%s]"):format("reset_" .. i, reset_tooltip)
end
if show_info then
local info_x = right_pane_width - 0.75
fs[#fs + 1] = ("image[%f,%f;0.5,0.5;%s]"):format(info_x, info_reset_y, info_icon_path)
fs[#fs + 1] = ("tooltip[%f,%f;0.5,0.5;%s]"):format(info_x, info_reset_y, fgettext(comp.info_text))
end
fs[#fs + 1] = "style_type[image_button;border=;padding=]"
fs[#fs + 1] = "container_end[]"
if used_h > 0 then
y = y + used_h + 0.25
end
end
fs[#fs + 1] = "scroll_container_end[]"
if y >= tabsize.height then
fs[#fs + 1] = make_scrollbaroptions_for_scroll_container(tabsize.height, y + 0.375, 0.1)
fs[#fs + 1] = ("scrollbar[%f,0;%f,%f;vertical;rightscroll;%f]"):format(
tabsize.width - scrollbar_w, scrollbar_w, tabsize.height, dialogdata.rightscroll or 0)
end
return table.concat(fs, "")
end
-- On Android, closing the app via the "Recents screen" won't result in a clean
-- exit, discarding any setting changes made by the user.
-- To avoid that, we write the settings file in more cases on Android.
function write_settings_early()
if PLATFORM == "Android" then
core.settings:write()
end
end
local function buttonhandler(this, fields)
local dialogdata = this.data
dialogdata.leftscroll = core.explode_scrollbar_event(fields.leftscroll).value or dialogdata.leftscroll
dialogdata.rightscroll = core.explode_scrollbar_event(fields.rightscroll).value or dialogdata.rightscroll
dialogdata.query = fields.search_query
if fields.back then
this:delete()
return true
end
if fields.show_technical_names ~= nil then
local value = core.is_yes(fields.show_technical_names)
core.settings:set_bool("show_technical_names", value)
write_settings_early()
return true
end
if fields.show_advanced ~= nil then
local value = core.is_yes(fields.show_advanced)
core.settings:set_bool("show_advanced", value)
write_settings_early()
local suggested_page_id = update_filtered_pages(dialogdata.query)
if not filtered_page_by_id[dialogdata.page_id] then
dialogdata.components = nil
dialogdata.leftscroll = 0
dialogdata.rightscroll = 0
dialogdata.page_id = suggested_page_id
end
return true
end
if fields.search or fields.key_enter_field == "search_query" then
dialogdata.components = nil
dialogdata.leftscroll = 0
dialogdata.rightscroll = 0
dialogdata.page_id = update_filtered_pages(dialogdata.query)
return true
end
if fields.search_clear then
dialogdata.query = ""
dialogdata.components = nil
dialogdata.leftscroll = 0
dialogdata.rightscroll = 0
dialogdata.page_id = update_filtered_pages("")
return true
end
for _, page in ipairs(all_pages) do
if fields["page_" .. page.id] then
dialogdata.page_id = page.id
dialogdata.components = nil
dialogdata.rightscroll = 0
return true
end
end
for i, comp in ipairs(dialogdata.components) do
if comp.on_submit and comp:on_submit(fields, this) then
write_settings_early()
-- Clear components so they regenerate
dialogdata.components = nil
return true
end
if comp.setting and fields["reset_" .. i] then
core.settings:remove(comp.setting.name)
write_settings_early()
-- Clear components so they regenerate
dialogdata.components = nil
return true
end
end
return false
end
local function eventhandler(event)
if event == "DialogShow" then
-- Don't show the "MINETEST" header behind the dialog.
mm_game_theme.set_engine(true)
return true
end
return false
end
function create_settings_dlg()
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
dlg.data.page_id = update_filtered_pages("")
return dlg
end

View File

@@ -1,5 +1,3 @@
local settings = ...
local concat = table.concat
local insert = table.insert
local sprintf = string.format
@@ -36,7 +34,7 @@ local group_format_template = [[
]]
local function create_minetest_conf_example()
local function create_minetest_conf_example(settings)
local result = { minetest_example_header }
for _, entry in ipairs(settings) do
if entry.type == "category" then
@@ -108,14 +106,11 @@ local translation_file_header = [[
fake_function() {]]
local function create_translation_file()
local function create_translation_file(settings)
local result = { translation_file_header }
for _, entry in ipairs(settings) do
if entry.type == "category" then
insert(result, sprintf("\tgettext(%q);", entry.name))
elseif entry.type == "key" then --luacheck: ignore
-- Neither names nor descriptions of keys are used since we have a
-- dedicated menu for them.
else
if entry.readable_name then
insert(result, sprintf("\tgettext(%q);", entry.readable_name))
@@ -132,12 +127,13 @@ local function create_translation_file()
end
local file = assert(io.open("minetest.conf.example", "w"))
file:write(create_minetest_conf_example())
file:write(create_minetest_conf_example(settingtypes.parse_config_file(true, false)))
file:close()
file = assert(io.open("src/settings_translation_file.cpp", "w"))
-- If 'minetest.conf.example' appears in the 'bin' folder, the line below may have to be
-- used instead. The file will also appear in the 'bin' folder.
--file = assert(io.open("settings_translation_file.cpp", "w"))
file:write(create_translation_file())
-- We don't want hidden settings to be translated, so we set read_all to false.
file:write(create_translation_file(settingtypes.parse_config_file(false, false)))
file:close()

View File

@@ -0,0 +1,28 @@
--Minetest
--Copyright (C) 2022 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local path = core.get_mainmenu_path() .. DIR_DELIM .. "settings"
dofile(path .. DIR_DELIM .. "settingtypes.lua")
dofile(path .. DIR_DELIM .. "dlg_change_mapgen_flags.lua")
dofile(path .. DIR_DELIM .. "dlg_settings.lua")
-- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
-- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
-- See comment and alternative line at the end of 'generate_from_settingtypes.lua'.
-- dofile(path .. DIR_DELIM .. "generate_from_settingtypes.lua")

View File

@@ -0,0 +1,507 @@
--Minetest
--Copyright (C) 2015 PilzAdam
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
settingtypes = {}
-- A Setting type is a table with the following keys:
--
-- name: Identifier
-- readable_name: Readable title
-- type: Category
--
-- name = mod.name,
-- readable_name = mod.title,
-- level = 1,
-- type = "category", "int", "string", ""
-- }
local FILENAME = "settingtypes.txt"
local CHAR_CLASSES = {
SPACE = "[%s]",
VARIABLE = "[%w_%-%.]",
INTEGER = "[+-]?[%d]",
FLOAT = "[+-]?[%d%.]",
FLAGS = "[%w_%-%.,]",
}
local function flags_to_table(flags)
return flags:gsub("%s+", ""):split(",", true) -- Remove all spaces and split
end
-- returns error message, or nil
local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
-- strip carriage returns (CR, /r)
line = line:gsub("\r", "")
-- comment
local comment_match = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$")
if comment_match then
settings.current_comment[#settings.current_comment + 1] = comment_match
return
end
-- clear current_comment so only comments directly above a setting are bound to it
-- but keep a local reference to it for variables in the current line
local current_comment = settings.current_comment
settings.current_comment = {}
-- empty lines
if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then
return
end
-- category
local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
if category then
local category_level = stars:len() + base_level
if settings.current_hide_level then
if settings.current_hide_level < category_level then
-- Skip this category, it's inside a hidden category.
return
else
-- The start of this category marks the end of a hidden category.
settings.current_hide_level = nil
end
end
if not read_all and category:sub(1, 5) == "Hide:" then
-- This category is hidden.
settings.current_hide_level = category_level
return
end
table.insert(settings, {
name = category,
level = category_level,
type = "category",
})
return
end
if settings.current_hide_level then
-- Ignore this line, we're inside a hidden category.
return
end
-- settings
local first_part, name, readable_name, setting_type = line:match("^"
-- this first capture group matches the whole first part,
-- so we can later strip it from the rest of the line
.. "("
.. "([" .. CHAR_CLASSES.VARIABLE .. "+)" -- variable name
.. CHAR_CLASSES.SPACE .. "*"
.. "%(([^%)]*)%)" -- readable name
.. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type
.. CHAR_CLASSES.SPACE .. "*"
.. ")")
if not first_part then
return "Invalid line"
end
if name:match("secure%.[.]*") and not allow_secure then
return "Tried to add \"secure.\" setting"
end
local requires = {}
local last_line = #current_comment > 0 and current_comment[#current_comment]:trim()
if last_line and last_line:lower():sub(1, 9) == "requires:" then
local parts = last_line:sub(10):split(",")
current_comment[#current_comment] = nil
for _, part in ipairs(parts) do
part = part:trim()
local value = true
if part:sub(1, 1) == "!" then
value = false
part = part:sub(2):trim()
end
requires[part] = value
end
end
if readable_name == "" then
readable_name = nil
end
local remaining_line = line:sub(first_part:len() + 1)
local comment = table.concat(current_comment, "\n"):trim()
if setting_type == "int" then
local default, min, max = remaining_line:match("^"
-- first int is required, the last 2 are optional
.. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.INTEGER .. "*)"
.. "$")
if not default or not tonumber(default) then
return "Invalid integer setting"
end
min = tonumber(min)
max = tonumber(max)
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "int",
default = default,
min = min,
max = max,
requires = requires,
comment = comment,
})
return
end
if setting_type == "string"
or setting_type == "key" or setting_type == "v3f" then
local default = remaining_line:match("^(.*)$")
if not default then
return "Invalid string setting"
end
if setting_type == "key" and not read_all then
-- ignore key type if read_all is false
return
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = setting_type,
default = default,
requires = requires,
comment = comment,
})
return
end
if setting_type == "noise_params_2d"
or setting_type == "noise_params_3d" then
local default = remaining_line:match("^(.*)$")
if not default then
return "Invalid string setting"
end
local values = {}
local ti = 1
local index = 1
for match in default:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
index = default:find("[+-]?[%d.-e]+", index) + match:len()
table.insert(values, match)
ti = ti + 1
if ti > 9 then
break
end
end
index = default:find("[^, ]", index)
local flags = ""
if index then
flags = default:sub(index)
end
table.insert(values, flags)
table.insert(settings, {
name = name,
readable_name = readable_name,
type = setting_type,
default = default,
default_table = {
offset = values[1],
scale = values[2],
spread = {
x = values[3],
y = values[4],
z = values[5]
},
seed = values[6],
octaves = values[7],
persistence = values[8],
lacunarity = values[9],
flags = values[10]
},
values = values,
requires = requires,
comment = comment,
noise_params = true,
flags = flags_to_table("defaults,eased,absvalue")
})
return
end
if setting_type == "bool" then
if remaining_line ~= "false" and remaining_line ~= "true" then
return "Invalid boolean setting"
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "bool",
default = remaining_line,
requires = requires,
comment = comment,
})
return
end
if setting_type == "float" then
local default, min, max = remaining_line:match("^"
-- first float is required, the last 2 are optional
.. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.FLOAT .. "*)"
.."$")
if not default or not tonumber(default) then
return "Invalid float setting"
end
min = tonumber(min)
max = tonumber(max)
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "float",
default = default,
min = min,
max = max,
requires = requires,
comment = comment,
})
return
end
if setting_type == "enum" then
local default, values = remaining_line:match("^"
-- first value (default) may be empty (i.e. is optional)
.. "(" .. CHAR_CLASSES.VARIABLE .. "*)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.FLAGS .. "+)"
.. "$")
if not default or values == "" then
return "Invalid enum setting"
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "enum",
default = default,
values = values:split(",", true),
requires = requires,
comment = comment,
})
return
end
if setting_type == "path" or setting_type == "filepath" then
local default = remaining_line:match("^(.*)$")
if not default then
return "Invalid path setting"
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = setting_type,
default = default,
requires = requires,
comment = comment,
})
return
end
if setting_type == "flags" then
local default, possible = remaining_line:match("^"
-- first value (default) may be empty (i.e. is optional)
-- this is implemented by making the last value optional, and
-- swapping them around if it turns out empty.
.. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. "*"
.. "(" .. CHAR_CLASSES.FLAGS .. "*)"
.. "$")
if not default or not possible then
return "Invalid flags setting"
end
if possible == "" then
possible = default
default = ""
end
table.insert(settings, {
name = name,
readable_name = readable_name,
type = "flags",
default = default,
possible = flags_to_table(possible),
requires = requires,
comment = comment,
})
return
end
return "Invalid setting type \"" .. setting_type .. "\""
end
local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
-- store this helper variable in the table so it's easier to pass to parse_setting_line()
result.current_comment = {}
result.current_hide_level = nil
local line = file:read("*line")
while line do
local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure)
if error_msg then
core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
end
line = file:read("*line")
end
result.current_comment = nil
result.current_hide_level = nil
end
--- Returns table of setting types
--
-- @param read_all Whether to ignore certain setting types for GUI or not
-- @parse_mods Whether to parse settingtypes.txt in mods and games
function settingtypes.parse_config_file(read_all, parse_mods)
local settings = {}
do
local builtin_path = core.get_builtin_path() .. FILENAME
local file = io.open(builtin_path, "r")
if not file then
core.log("error", "Can't load " .. FILENAME)
return settings
end
parse_single_file(file, builtin_path, read_all, settings, 0, true)
file:close()
end
if parse_mods then
-- Parse games
local games_category_initialized = false
for _, game in ipairs(pkgmgr.games) do
local path = game.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
if file then
if not games_category_initialized then
fgettext_ne("Content: Games") -- not used, but needed for xgettext
table.insert(settings, {
name = "Content: Games",
level = 0,
type = "category",
})
games_category_initialized = true
end
table.insert(settings, {
name = game.path,
readable_name = game.title,
level = 1,
type = "category",
})
parse_single_file(file, path, read_all, settings, 2, false)
file:close()
end
end
-- Parse mods
local mods_category_initialized = false
local mods = {}
pkgmgr.get_mods(core.get_modpath(), "mods", mods)
table.sort(mods, function(a, b) return a.name < b.name end)
for _, mod in ipairs(mods) do
local path = mod.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
if file then
if not mods_category_initialized then
fgettext_ne("Content: Mods") -- not used, but needed for xgettext
table.insert(settings, {
name = "Content: Mods",
level = 0,
type = "category",
})
mods_category_initialized = true
end
table.insert(settings, {
name = mod.path,
readable_name = mod.title or mod.name,
level = 1,
type = "category",
})
parse_single_file(file, path, read_all, settings, 2, false)
file:close()
end
end
-- Parse client mods
local clientmods_category_initialized = false
local clientmods = {}
pkgmgr.get_mods(core.get_clientmodpath(), "clientmods", clientmods)
for _, mod in ipairs(clientmods) do
local path = mod.path .. DIR_DELIM .. FILENAME
local file = io.open(path, "r")
if file then
if not clientmods_category_initialized then
fgettext_ne("Client Mods") -- not used, but needed for xgettext
table.insert(settings, {
name = "Client Mods",
level = 0,
type = "category",
})
clientmods_category_initialized = true
end
table.insert(settings, {
name = mod.path,
readable_name = mod.title or mod.name,
level = 1,
type = "category",
})
parse_single_file(file, path, read_all, settings, 2, false)
file:close()
end
end
end
return settings
end

View File

@@ -0,0 +1,121 @@
--Minetest
--Copyright (C) 2021-2 x2048
--Copyright (C) 2022-3 rubenwardy
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local shadow_levels_labels = {
fgettext("Disabled"),
fgettext("Very Low"),
fgettext("Low"),
fgettext("Medium"),
fgettext("High"),
fgettext("Very High"),
fgettext("Custom"),
}
local PRESET_DISABLED = 1
local PRESET_CUSTOM = #shadow_levels_labels
-- max distance, texture size, texture_32bit, filters, map color
local shadow_presets = {
[2] = { 62, 512, true, 0, false },
[3] = { 93, 1024, true, 0, false },
[4] = { 140, 2048, true, 1, false },
[5] = { 210, 4096, true, 2, true },
[6] = { 300, 8192, true, 2, true },
}
local function detect_mapping_idx()
if not core.settings:get_bool("enable_dynamic_shadows", false) then
return PRESET_DISABLED
end
local shadow_map_max_distance = tonumber(core.settings:get("shadow_map_max_distance"))
local shadow_map_texture_size = tonumber(core.settings:get("shadow_map_texture_size"))
local shadow_map_texture_32bit = core.settings:get_bool("shadow_map_texture_32bit", false)
local shadow_filters = tonumber(core.settings:get("shadow_filters"))
local shadow_map_color = core.settings:get_bool("shadow_map_color", false)
for i = 2, 6 do
local preset = shadow_presets[i]
if preset[1] == shadow_map_max_distance and
preset[2] == shadow_map_texture_size and
preset[3] == shadow_map_texture_32bit and
preset[4] == shadow_filters and
preset[5] == shadow_map_color then
return i
end
end
return PRESET_CUSTOM
end
local function apply_preset(preset)
if preset then
core.settings:set_bool("enable_dynamic_shadows", true)
core.settings:set("shadow_map_max_distance", preset[1])
core.settings:set("shadow_map_texture_size", preset[2])
core.settings:set_bool("shadow_map_texture_32bit", preset[3])
core.settings:set("shadow_filters", preset[4])
core.settings:set_bool("shadow_map_color", preset[5])
else
core.settings:set_bool("enable_dynamic_shadows", false)
end
end
return {
query_text = "Shadows",
requires = {
shaders = true,
opengl = true,
},
get_formspec = function(self, avail_w)
local labels = table.copy(shadow_levels_labels)
local idx = detect_mapping_idx()
-- Remove "custom" if not already selected
if idx ~= PRESET_CUSTOM then
table.remove(labels, PRESET_CUSTOM)
end
local fs =
"label[0,0.2;" .. fgettext("Dynamic shadows") .. "]" ..
"dropdown[0,0.4;3,0.8;dd_shadows;" .. table.concat(labels, ",") .. ";" .. idx .. ";true]" ..
"label[0,1.5;" .. core.colorize("#bbb", fgettext("(The game will need to enable shadows as well)")) .. "]"
return fs, 1.8
end,
on_submit = function(self, fields)
if fields.dd_shadows then
local old_shadow_level_idx = detect_mapping_idx()
local shadow_level_idx = tonumber(fields.dd_shadows)
if shadow_level_idx == nil or shadow_level_idx == old_shadow_level_idx then
return false
end
if shadow_level_idx == PRESET_CUSTOM then
core.settings:set_bool("enable_dynamic_shadows", true)
return true
end
local preset = shadow_presets[shadow_level_idx]
apply_preset(preset)
return true
end
end,
}

View File

@@ -27,9 +27,9 @@ local core_developers = {
"Krock/SmallJoker <mk939@ymail.com>",
"Lars Hofhansl <larsh@apache.org>",
"v-rob <robinsonvincent89@gmail.com>",
"Hugues Ross <hugues.ross@gmail.com>",
"Dmitry Kostenko (x2048) <codeforsmile@gmail.com>",
"Desour",
"Desour/DS",
"srifqi",
"Gregor Parzefall (grorp)",
}
-- currently only https://github.com/orgs/minetest/teams/triagers/members
@@ -43,18 +43,19 @@ local core_team = {
-- For updating active/previous contributors, see the script in ./util/gather_git_credits.py
local active_contributors = {
"Wuzzy [Features, translations, devtest]",
"Lars Müller [Bugfixes and entity features]",
"paradust7 [Bugfixes]",
"ROllerozxa [Bugfixes, Android]",
"srifqi [Android, translations]",
"Lexi Hale [Particlespawner animation]",
"Wuzzy [Features, translations, documentation]",
"numzero [Optimizations, work on OpenGL driver]",
"ROllerozxa [Bugfixes, Mainmenu]",
"Lars Müller [Bugfixes]",
"AFCMS [Documentation]",
"savilli [Bugfixes]",
"fluxionary [Bugfixes]",
"Gregor Parzefall [Bugfixes]",
"Bradley Pierce (Thresher) [Documentation]",
"Stvk imension [Android]",
"JosiahWI [Code cleanups]",
"OgelGames [UI, Bugfixes]",
"ndren [Bugfixes]",
"Abdou-31 [Documentation]",
"pecksin [Bouncy physics]",
"Daroc Alden [Fixes]",
}
local previous_core_developers = {
@@ -75,13 +76,14 @@ local previous_core_developers = {
"Pierre-Yves Rollo <dev@pyrollo.com>",
"hecks",
"Jude Melton-Houghton (TurkeyMcMac) [RIP]",
"Hugues Ross <hugues.ross@gmail.com>",
"Dmitry Kostenko (x2048) <codeforsmile@gmail.com>",
}
local previous_contributors = {
"Nils Dagsson Moskopp (erlehmann) <nils@dieweltistgarnichtso.net> [Minetest logo]",
"red-001 <red-001@outlook.ie>",
"Giuseppe Bilotta",
"numzero",
"HybridDog",
"ClobberXD",
"Dániel Juhász (juhdanad) <juhdanad@gmail.com>",
@@ -99,83 +101,79 @@ local previous_contributors = {
}
local function prepare_credits(dest, source)
for _, s in ipairs(source) do
-- if there's text inside brackets make it gray-ish
s = s:gsub("%[.-%]", core.colorize("#aaa", "%1"))
dest[#dest+1] = s
end
end
local string = table.concat(source, "\n") .. "\n"
local function build_hacky_list(items, spacing)
spacing = spacing or 0.5
local y = spacing / 2
local ret = {}
for _, item in ipairs(items) do
if item ~= "" then
ret[#ret+1] = ("label[0,%f;%s]"):format(y, core.formspec_escape(item))
end
y = y + spacing
end
return table.concat(ret, ""), y
local hypertext_escapes = {
["\\"] = "\\\\",
["<"] = "\\<",
[">"] = "\\>",
}
string = string:gsub("[\\<>]", hypertext_escapes)
string = string:gsub("%[.-%]", "<gray>%1</gray>")
table.insert(dest, string)
end
return {
name = "about",
caption = fgettext("About"),
cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version()
local credit_list = {}
table.insert_all(credit_list, {
core.colorize("#000", "Dedication of the current release"),
"The 5.7.0 release is dedicated to the memory of",
"Minetest developer Jude Melton-Houghton (TurkeyMcMac)",
"who died on February 1, 2023.",
"Our thoughts are with his family and friends.",
"",
core.colorize("#ff0", fgettext("Core Developers"))
local hypertext = {
"<tag name=heading color=#ff0>",
"<tag name=gray color=#aaa>",
}
table.insert_all(hypertext, {
"<heading>", fgettext_ne("Core Developers"), "</heading>\n",
})
prepare_credits(credit_list, core_developers)
table.insert_all(credit_list, {
"",
core.colorize("#ff0", fgettext("Core Team"))
prepare_credits(hypertext, core_developers)
table.insert_all(hypertext, {
"\n",
"<heading>", fgettext_ne("Core Team"), "</heading>\n",
})
prepare_credits(credit_list, core_team)
table.insert_all(credit_list, {
"",
core.colorize("#ff0", fgettext("Active Contributors"))
prepare_credits(hypertext, core_team)
table.insert_all(hypertext, {
"\n",
"<heading>", fgettext_ne("Active Contributors"), "</heading>\n",
})
prepare_credits(credit_list, active_contributors)
table.insert_all(credit_list, {
"",
core.colorize("#ff0", fgettext("Previous Core Developers"))
prepare_credits(hypertext, active_contributors)
table.insert_all(hypertext, {
"\n",
"<heading>", fgettext_ne("Previous Core Developers"), "</heading>\n",
})
prepare_credits(credit_list, previous_core_developers)
table.insert_all(credit_list, {
"",
core.colorize("#ff0", fgettext("Previous Contributors"))
prepare_credits(hypertext, previous_core_developers)
table.insert_all(hypertext, {
"\n",
"<heading>", fgettext_ne("Previous Contributors"), "</heading>\n",
})
prepare_credits(credit_list, previous_contributors)
local credit_fs, scroll_height = build_hacky_list(credit_list)
-- account for the visible portion
scroll_height = math.max(0, scroll_height - 6.9)
prepare_credits(hypertext, previous_contributors)
hypertext = table.concat(hypertext):sub(1, -2)
local fs = "image[1.5,0.6;2.5,2.5;" .. core.formspec_escape(logofile) .. "]" ..
"style[label_button;border=false]" ..
"button[0.1,3.4;5.3,0.5;label_button;" ..
core.formspec_escape(version.project .. " " .. version.string) .. "]" ..
"button[1.5,4.1;2.5,0.8;homepage;minetest.net]" ..
"scroll_container[5.5,0.1;9.5,6.9;scroll_credits;vertical;" ..
tostring(scroll_height / 1000) .. "]" .. credit_fs ..
"scroll_container_end[]"..
"scrollbar[15,0.1;0.4,6.9;vertical;scroll_credits;0]"
"hypertext[5.5,0.25;9.75,6.6;credits;" .. minetest.formspec_escape(hypertext) .. "]"
-- Render information
local active_renderer_info = fgettext("Active renderer:") .. " " ..
core.formspec_escape(core.get_active_renderer())
fs = fs .. "style[label_button2;border=false]" ..
"button[0.1,6;5.3,1;label_button2;" ..
fgettext("Active renderer:") .. "\n" ..
core.formspec_escape(core.get_active_renderer()) .. "]"
"button[0.1,6;5.3,0.5;label_button2;" .. active_renderer_info .. "]"..
"tooltip[label_button2;" .. active_renderer_info .. "]"
-- Irrlicht device information
local irrlicht_device_info = fgettext("Irrlicht device:") .. " " ..
core.formspec_escape(core.get_active_irrlicht_device())
fs = fs .. "style[label_button3;border=false]" ..
"button[0.1,6.5;5.3,0.5;label_button3;" .. irrlicht_device_info .. "]"..
"tooltip[label_button3;" .. irrlicht_device_info .. "]"
if PLATFORM == "Android" then
fs = fs .. "button[0.5,5.1;4.5,0.8;share_debug;" .. fgettext("Share debug log") .. "]"
@@ -186,8 +184,9 @@ return {
fs = fs .. "button[0.5,5.1;4.5,0.8;userdata;" .. fgettext("Open User Data Directory") .. "]"
end
return fs, "size[15.5,7.1,false]real_coordinates[true]"
return fs
end,
cbf_button_handler = function(this, fields, name, tabdata)
if fields.homepage then
core.open_url("https://www.minetest.net")
@@ -202,4 +201,10 @@ return {
core.open_dir(core.get_user_path())
end
end,
on_change = function(type)
if type == "ENTER" then
mm_game_theme.set_engine()
end
end,
}

View File

@@ -16,77 +16,108 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
local packages_raw
local packages
--------------------------------------------------------------------------------
local function get_formspec(tabview, name, tabdata)
if pkgmgr.global_mods == nil then
local function get_content_icons(packages_with_updates)
local ret = {}
for _, content in ipairs(packages_with_updates) do
ret[content.virtual_path or content.path] = { type = "update" }
end
return ret
end
local packages_raw, packages
local function update_packages()
if not pkgmgr.global_mods then
pkgmgr.refresh_globals()
end
if pkgmgr.games == nil then
if not pkgmgr.games then
pkgmgr.update_gamelist()
end
if packages == nil then
packages_raw = {}
table.insert_all(packages_raw, pkgmgr.games)
table.insert_all(packages_raw, pkgmgr.get_texture_packs())
table.insert_all(packages_raw, pkgmgr.global_mods:get_list())
packages_raw = {}
table.insert_all(packages_raw, pkgmgr.games)
table.insert_all(packages_raw, pkgmgr.get_texture_packs())
table.insert_all(packages_raw, pkgmgr.global_mods:get_list())
local function get_data()
return packages_raw
end
local function is_equal(element, uid) --uid match
return (element.type == "game" and element.id == uid) or
element.name == uid
end
packages = filterlist.create(get_data, pkgmgr.compare_package,
is_equal, nil, {})
local function get_data()
return packages_raw
end
if tabdata.selected_pkg == nil then
local function is_equal(element, uid) --uid match
return (element.type == "game" and element.id == uid) or
element.name == uid
end
packages = filterlist.create(get_data, pkgmgr.compare_package,
is_equal, nil, {})
end
local function on_change(type)
if type == "ENTER" then
mm_game_theme.set_engine()
update_packages()
end
end
local function get_formspec(tabview, name, tabdata)
if not packages then
update_packages()
end
if not tabdata.selected_pkg then
tabdata.selected_pkg = 1
end
local use_technical_names = core.settings:get_bool("show_technical_names")
local packages_with_updates = update_detector.get_all()
local update_icons = get_content_icons(packages_with_updates)
local update_count = #packages_with_updates
local contentdb_label
if update_count == 0 then
contentdb_label = fgettext("Browse online content")
else
contentdb_label = fgettext("Browse online content [$1]", update_count)
end
local retval =
"label[0.05,-0.25;".. fgettext("Installed Packages:") .. "]" ..
"tablecolumns[color;tree;text]" ..
"table[0,0.25;5.1,4.3;pkglist;" ..
pkgmgr.render_packagelist(packages, use_technical_names) ..
";" .. tabdata.selected_pkg .. "]" ..
"button[0,4.85;5.25,0.5;btn_contentdb;".. fgettext("Browse online content") .. "]"
local retval = {
"label[0.4,0.4;", fgettext("Installed Packages:"), "]",
"tablecolumns[color;tree;image,align=inline,width=1.5",
",tooltip=", fgettext("Update available?"),
",0=", core.formspec_escape(defaulttexturedir .. "blank.png"),
",4=", core.formspec_escape(defaulttexturedir .. "cdb_update_cropped.png"),
";text]",
"table[0.4,0.8;6.3,4.8;pkglist;",
pkgmgr.render_packagelist(packages, use_technical_names, update_icons),
";", tabdata.selected_pkg, "]",
"button[0.4,5.8;6.3,0.9;btn_contentdb;", contentdb_label, "]"
}
local selected_pkg
if filterlist.size(packages) >= tabdata.selected_pkg then
selected_pkg = packages:get_list()[tabdata.selected_pkg]
end
if selected_pkg ~= nil then
--check for screenshot beeing available
if selected_pkg then
-- Check for screenshot being available
local screenshotfilename = selected_pkg.path .. DIR_DELIM .. "screenshot.png"
local screenshotfile, error = io.open(screenshotfilename, "r")
local modscreenshot
if error == nil then
if not error then
screenshotfile:close()
modscreenshot = screenshotfilename
end
if modscreenshot == nil then
modscreenshot = defaulttexturedir .. "no_screenshot.png"
else
modscreenshot = defaulttexturedir .. "no_screenshot.png"
end
local info = core.get_content_info(selected_pkg.path)
local desc = fgettext("No package description available")
if info.description and info.description:trim() ~= "" then
desc = info.description
desc = core.formspec_escape(info.description)
end
local title_and_name
@@ -97,65 +128,76 @@ local function get_formspec(tabview, name, tabdata)
core.colorize("#BFBFBF", selected_pkg.name)
end
retval = retval ..
"image[5.5,0;3,2;" .. core.formspec_escape(modscreenshot) .. "]" ..
"label[8.25,0.6;" .. core.formspec_escape(title_and_name) .. "]" ..
"box[5.5,2.2;6.15,2.35;#000]"
local desc_height = 3.2
if selected_pkg.type == "mod" then
if selected_pkg.is_modpack then
retval = retval ..
"button[8.65,4.65;3.25,1;btn_mod_mgr_rename_modpack;" ..
fgettext("Rename") .. "]"
if selected_pkg.is_modpack then
desc_height = 2.1
table.insert_all(retval, {
"button[7.1,4.7;8,0.9;btn_mod_mgr_rename_modpack;",
fgettext("Rename"), "]"
})
elseif selected_pkg.type == "mod" then
-- Show dependencies for mods
desc = desc .. "\n\n"
local toadd_hard = table.concat(info.depends or {}, "\n")
local toadd_soft = table.concat(info.optional_depends or {}, "\n")
if toadd_hard == "" and toadd_soft == "" then
desc = desc .. fgettext("No dependencies.")
else
--show dependencies
desc = desc .. "\n\n"
local toadd_hard = table.concat(info.depends or {}, "\n")
local toadd_soft = table.concat(info.optional_depends or {}, "\n")
if toadd_hard == "" and toadd_soft == "" then
desc = desc .. fgettext("No dependencies.")
else
if toadd_hard ~= "" then
desc = desc ..fgettext("Dependencies:") ..
"\n" .. toadd_hard
end
if toadd_soft ~= "" then
if toadd_hard ~= "" then
desc = desc ..fgettext("Dependencies:") ..
"\n" .. toadd_hard
end
if toadd_soft ~= "" then
if toadd_hard ~= "" then
desc = desc .. "\n\n"
end
desc = desc .. fgettext("Optional dependencies:") ..
"\n" .. toadd_soft
desc = desc .. "\n\n"
end
desc = desc .. fgettext("Optional dependencies:") ..
"\n" .. toadd_soft
end
end
elseif selected_pkg.type == "txp" then
desc_height = 2.1
else
if selected_pkg.type == "txp" then
if selected_pkg.enabled then
retval = retval ..
"button[8.65,4.65;3.25,1;btn_mod_mgr_disable_txp;" ..
fgettext("Disable Texture Pack") .. "]"
else
retval = retval ..
"button[8.65,4.65;3.25,1;btn_mod_mgr_use_txp;" ..
fgettext("Use Texture Pack") .. "]"
end
if selected_pkg.enabled then
table.insert_all(retval, {
"button[7.1,4.7;8,0.9;btn_mod_mgr_disable_txp;",
fgettext("Disable Texture Pack"), "]"
})
else
table.insert_all(retval, {
"button[7.1,4.7;8,0.9;btn_mod_mgr_use_txp;",
fgettext("Use Texture Pack"), "]"
})
end
end
retval = retval .. "textarea[5.85,2.2;6.35,2.9;;" ..
fgettext("Information:") .. ";" .. desc .. "]"
table.insert_all(retval, {
"image[7.1,0.2;3,2;", core.formspec_escape(modscreenshot), "]",
"label[10.5,1;", core.formspec_escape(title_and_name), "]",
"box[7.1,2.4;8,", tostring(desc_height), ";#000]",
"textarea[7.1,2.4;8,", tostring(desc_height), ";;;", desc, "]",
})
if core.may_modify_path(selected_pkg.path) then
retval = retval ..
"button[5.5,4.65;3.25,1;btn_mod_mgr_delete_mod;" ..
fgettext("Uninstall Package") .. "]"
table.insert_all(retval, {
"button[7.1,5.8;4,0.9;btn_mod_mgr_delete_mod;",
fgettext("Uninstall"), "]"
})
end
if update_icons[selected_pkg.virtual_path or selected_pkg.path] then
table.insert_all(retval, {
"button[11.1,5.8;4,0.9;btn_mod_mgr_update;",
fgettext("Update"), "]"
})
end
end
return retval
return table.concat(retval)
end
--------------------------------------------------------------------------------
local function handle_doubleclick(pkg)
if pkg.type == "txp" then
if core.settings:get("texture_path") == pkg.path then
@@ -166,14 +208,14 @@ local function handle_doubleclick(pkg)
packages = nil
mm_game_theme.init()
mm_game_theme.reset()
mm_game_theme.set_engine()
end
end
--------------------------------------------------------------------------------
local function handle_buttons(tabview, fields, tabname, tabdata)
if fields["pkglist"] ~= nil then
local event = core.explode_table_event(fields["pkglist"])
if fields.pkglist then
local event = core.explode_table_event(fields.pkglist)
tabdata.selected_pkg = event.row
if event.type == "DCL" then
handle_doubleclick(packages:get_list()[tabdata.selected_pkg])
@@ -181,7 +223,7 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
return true
end
if fields["btn_contentdb"] ~= nil then
if fields.btn_contentdb then
local dlg = create_store_dlg()
dlg:set_parent(tabview)
tabview:hide()
@@ -190,7 +232,7 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
return true
end
if fields["btn_mod_mgr_rename_modpack"] ~= nil then
if fields.btn_mod_mgr_rename_modpack then
local mod = packages:get_list()[tabdata.selected_pkg]
local dlg_renamemp = create_rename_modpack_dlg(mod)
dlg_renamemp:set_parent(tabview)
@@ -200,7 +242,7 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
return true
end
if fields["btn_mod_mgr_delete_mod"] ~= nil then
if fields.btn_mod_mgr_delete_mod then
local mod = packages:get_list()[tabdata.selected_pkg]
local dlg_delmod = create_delete_content_dlg(mod)
dlg_delmod:set_parent(tabview)
@@ -210,6 +252,16 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
return true
end
if fields.btn_mod_mgr_update then
local pkg = packages:get_list()[tabdata.selected_pkg]
local dlg = create_store_dlg(nil, pkgmgr.get_contentdb_id(pkg))
dlg:set_parent(tabview)
tabview:hide()
dlg:show()
packages = nil
return true
end
if fields.btn_mod_mgr_use_txp or fields.btn_mod_mgr_disable_txp then
local txp_path = ""
if fields.btn_mod_mgr_use_txp then
@@ -220,18 +272,24 @@ local function handle_buttons(tabview, fields, tabname, tabdata)
packages = nil
mm_game_theme.init()
mm_game_theme.reset()
mm_game_theme.set_engine()
return true
end
return false
end
--------------------------------------------------------------------------------
return {
name = "content",
caption = fgettext("Content"),
caption = function()
local update_count = update_detector.get_count()
if update_count == 0 then
return fgettext("Content")
else
return fgettext("Content [$1]", update_count)
end
end,
cbf_formspec = get_formspec,
cbf_button_handler = handle_buttons,
on_change = pkgmgr.update_gamelist
on_change = on_change
}

View File

@@ -23,21 +23,40 @@ local valid_disabled_settings = {
["enable_server"]=true,
}
-- Name and port stored to persist when updating the formspec
local current_name = core.settings:get("name")
local current_port = core.settings:get("port")
-- Currently chosen game in gamebar for theming and filtering
function current_game()
local last_game_id = core.settings:get("menu_last_game")
local game = pkgmgr.find_by_gameid(last_game_id)
local gameid = core.settings:get("menu_last_game")
local game = gameid and pkgmgr.find_by_gameid(gameid)
-- Fall back to first game installed if one exists.
if not game and #pkgmgr.games > 0 then
-- If devtest is the first game in the list and there is another
-- game available, pick the other game instead.
local picked_game
if pkgmgr.games[1].id == "devtest" and #pkgmgr.games > 1 then
picked_game = 2
else
picked_game = 1
end
game = pkgmgr.games[picked_game]
gameid = game.id
core.settings:set("menu_last_game", gameid)
end
return game
end
-- Apply menu changes from given game
function apply_game(game)
core.set_topleft_text(game.name)
core.settings:set("menu_last_game", game.id)
menudata.worldlist:set_filtercriteria(game.id)
mm_game_theme.update("singleplayer", game) -- this refreshes the formspec
mm_game_theme.set_game(game)
local index = filterlist.get_current_index(menudata.worldlist,
tonumber(core.settings:get("mainmenu_last_selected_world")))
@@ -59,16 +78,12 @@ function singleplayer_refresh_gamebar()
old_bar:delete()
end
local function game_buttonbar_button_handler(fields)
if fields.game_open_cdb then
local maintab = ui.find_by_name("maintab")
local dlg = create_store_dlg("game")
dlg:set_parent(maintab)
maintab:hide()
dlg:show()
return true
end
-- Hide gamebar if no games are installed
if #pkgmgr.games == 0 then
return false
end
local function game_buttonbar_button_handler(fields)
for _, game in ipairs(pkgmgr.games) do
if fields["game_btnbar_" .. game.id] then
apply_game(game)
@@ -77,9 +92,12 @@ function singleplayer_refresh_gamebar()
end
end
local btnbar = buttonbar_create("game_button_bar",
game_buttonbar_button_handler,
{x=-0.3,y=5.9}, "horizontal", {x=12.4,y=1.15})
local btnbar = buttonbar_create(
"game_button_bar",
TOUCHSCREEN_GUI and {x = 0, y = 7.25} or {x = 0, y = 7.475},
{x = 15.5, y = 1.25},
"#000000",
game_buttonbar_button_handler)
for _, game in ipairs(pkgmgr.games) do
local btn_name = "game_btnbar_" .. game.id
@@ -105,6 +123,7 @@ function singleplayer_refresh_gamebar()
local plus_image = core.formspec_escape(defaulttexturedir .. "plus.png")
btnbar:add_button("game_open_cdb", "", plus_image, fgettext("Install games from ContentDB"))
return true
end
local function get_disabled_settings(game)
@@ -134,6 +153,15 @@ local function get_disabled_settings(game)
end
local function get_formspec(tabview, name, tabdata)
-- Point the player to ContentDB when no games are found
if #pkgmgr.games == 0 then
return table.concat({
"style[label_button;border=false]",
"button[2.75,1.5;10,1;label_button;", fgettext("You have no games installed."), "]",
"button[5.25,3.5;5,1.2;game_open_cdb;", fgettext("Install a game"), "]"})
end
local retval = ""
local index = filterlist.get_current_index(menudata.worldlist,
@@ -151,8 +179,8 @@ local function get_formspec(tabview, name, tabdata)
local creative, damage, host = "", "", ""
-- Y offsets for game settings checkboxes
local y = -0.2
local yo = 0.45
local y = 0.2
local yo = 0.5625
if disabled_settings["creative_mode"] == nil then
creative = "checkbox[0,"..y..";cb_creative_mode;".. fgettext("Creative Mode") .. ";" ..
@@ -171,41 +199,60 @@ local function get_formspec(tabview, name, tabdata)
end
retval = retval ..
"button[3.9,3.8;2.8,1;world_delete;".. fgettext("Delete") .. "]" ..
"button[6.55,3.8;2.8,1;world_configure;".. fgettext("Select Mods") .. "]" ..
"button[9.2,3.8;2.8,1;world_create;".. fgettext("New") .. "]" ..
"label[3.9,-0.05;".. fgettext("Select World:") .. "]"..
"container[5.25,4.875]" ..
"button[0,0;3.225,0.8;world_delete;".. fgettext("Delete") .. "]" ..
"button[3.325,0;3.225,0.8;world_configure;".. fgettext("Select Mods") .. "]" ..
"button[6.65,0;3.225,0.8;world_create;".. fgettext("New") .. "]" ..
"container_end[]" ..
"container[0.375,0.375]" ..
creative ..
damage ..
host ..
"textlist[3.9,0.4;7.9,3.45;sp_worlds;" ..
"container_end[]" ..
"container[5.25,0.375]" ..
"label[0,0.2;".. fgettext("Select World:") .. "]"..
"textlist[0,0.5;9.875,3.9;sp_worlds;" ..
menu_render_worldlist() ..
";" .. index .. "]"
";" .. index .. "]" ..
"container_end[]"
if core.settings:get_bool("enable_server") and disabled_settings["enable_server"] == nil then
retval = retval ..
"button[7.9,4.75;4.1,1;play;".. fgettext("Host Game") .. "]" ..
"button[10.1875,5.925;4.9375,0.8;play;".. fgettext("Host Game") .. "]" ..
"container[0.375,0.375]" ..
"checkbox[0,"..y..";cb_server_announce;" .. fgettext("Announce Server") .. ";" ..
dump(core.settings:get_bool("server_announce")) .. "]" ..
"field[0.3,2.85;3.8,0.5;te_playername;" .. fgettext("Name") .. ";" ..
core.formspec_escape(core.settings:get("name")) .. "]" ..
"pwdfield[0.3,4.05;3.8,0.5;te_passwd;" .. fgettext("Password") .. "]"
dump(core.settings:get_bool("server_announce")) .. "]"
-- Reset y so that the text fields always start at the same position,
-- regardless of whether some of the checkboxes are hidden.
y = 0.2 + 4 * yo + 0.35
retval = retval .. "field[0," .. y .. ";4.5,0.75;te_playername;" .. fgettext("Name") .. ";" ..
core.formspec_escape(current_name) .. "]"
y = y + 1.15 + 0.25
retval = retval .. "pwdfield[0," .. y .. ";4.5,0.75;te_passwd;" .. fgettext("Password") .. "]"
y = y + 1.15 + 0.25
local bind_addr = core.settings:get("bind_address")
if bind_addr ~= nil and bind_addr ~= "" then
retval = retval ..
"field[0.3,5.25;2.5,0.5;te_serveraddr;" .. fgettext("Bind Address") .. ";" ..
"field[0," .. y .. ";3,0.75;te_serveraddr;" .. fgettext("Bind Address") .. ";" ..
core.formspec_escape(core.settings:get("bind_address")) .. "]" ..
"field[2.85,5.25;1.25,0.5;te_serverport;" .. fgettext("Port") .. ";" ..
core.formspec_escape(core.settings:get("port")) .. "]"
"field[3.25," .. y .. ";1.25,0.75;te_serverport;" .. fgettext("Port") .. ";" ..
core.formspec_escape(current_port) .. "]"
else
retval = retval ..
"field[0.3,5.25;3.8,0.5;te_serverport;" .. fgettext("Server Port") .. ";" ..
core.formspec_escape(core.settings:get("port")) .. "]"
"field[0," .. y .. ";4.5,0.75;te_serverport;" .. fgettext("Server Port") .. ";" ..
core.formspec_escape(current_port) .. "]"
end
retval = retval .. "container_end[]"
else
retval = retval ..
"button[7.9,4.75;4.1,1;play;" .. fgettext("Play Game") .. "]"
"button[10.1875,5.925;4.9375,0.8;play;" .. fgettext("Play Game") .. "]"
end
return retval
@@ -215,12 +262,29 @@ local function main_button_handler(this, fields, name, tabdata)
assert(name == "local")
if fields.game_open_cdb then
local maintab = ui.find_by_name("maintab")
local dlg = create_store_dlg("game")
dlg:set_parent(maintab)
maintab:hide()
dlg:show()
return true
end
if this.dlg_create_world_closed_at == nil then
this.dlg_create_world_closed_at = 0
end
local world_doubleclick = false
if fields["te_playername"] then
current_name = fields["te_playername"]
end
if fields["te_serverport"] then
current_port = fields["te_serverport"]
end
if fields["sp_worlds"] ~= nil then
local event = core.explode_textlist_event(fields["sp_worlds"])
local selected = core.get_textlist_index("sp_worlds")
@@ -284,7 +348,7 @@ local function main_button_handler(this, fields, name, tabdata)
if selected == nil or gamedata.selected_world == 0 then
gamedata.errormessage =
fgettext("No world created or selected!")
fgettext_ne("No world created or selected!")
return true
end
@@ -331,7 +395,6 @@ local function main_button_handler(this, fields, name, tabdata)
create_world_dlg:set_parent(this)
this:hide()
create_world_dlg:show()
mm_game_theme.update("singleplayer", current_game())
return true
end
@@ -348,7 +411,6 @@ local function main_button_handler(this, fields, name, tabdata)
delete_world_dlg:set_parent(this)
this:hide()
delete_world_dlg:show()
mm_game_theme.update("singleplayer",current_game())
end
end
@@ -366,7 +428,6 @@ local function main_button_handler(this, fields, name, tabdata)
configdialog:set_parent(this)
this:hide()
configdialog:show()
mm_game_theme.update("singleplayer",current_game())
end
end
@@ -374,26 +435,24 @@ local function main_button_handler(this, fields, name, tabdata)
end
end
local function on_change(type, old_tab, new_tab)
if (type == "ENTER") then
local function on_change(type)
if type == "ENTER" then
local game = current_game()
if game then
apply_game(game)
else
mm_game_theme.set_engine()
end
singleplayer_refresh_gamebar()
ui.find_by_name("game_button_bar"):show()
else
if singleplayer_refresh_gamebar() then
ui.find_by_name("game_button_bar"):show()
end
elseif type == "LEAVE" then
menudata.worldlist:set_filtercriteria(nil)
local gamebar = ui.find_by_name("game_button_bar")
if gamebar then
gamebar:hide()
end
core.set_topleft_text("")
-- If new_tab is nil, a dialog is being shown; avoid resetting the theme
if new_tab then
mm_game_theme.update(new_tab,nil)
end
end
end

View File

@@ -67,6 +67,7 @@ local function get_formspec(tabview, name, tabdata)
local retval =
-- Search
"field[0.25,0.25;7,0.75;te_search;;" .. core.formspec_escape(tabdata.search_for) .. "]" ..
"field_enter_after_edit[te_search;true]" ..
"container[7.25,0.25]" ..
"image_button[0,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "search.png") .. ";btn_mp_search;]" ..
"image_button[0.75,0;0.75,0.75;" .. core.formspec_escape(defaulttexturedir .. "clear.png") .. ";btn_mp_clear;]" ..
@@ -114,7 +115,7 @@ local function get_formspec(tabview, name, tabdata)
"server_favorite_delete.png") .. ";btn_delete_favorite;]"
end
if gamedata.serverdescription then
retval = retval .. "textarea[0.25,1.85;5.2,2.75;;;" ..
retval = retval .. "textarea[0.25,1.85;5.25,2.7;;;" ..
core.formspec_escape(gamedata.serverdescription) .. "]"
end
end
@@ -180,7 +181,7 @@ local function get_formspec(tabview, name, tabdata)
retval = retval .. ";0]"
end
return retval, "size[15.5,7.1,false]real_coordinates[true]"
return retval
end
--------------------------------------------------------------------------------
@@ -415,9 +416,11 @@ local function main_button_handler(tabview, fields, name, tabdata)
return false
end
local function on_change(type, old_tab, new_tab)
if type == "LEAVE" then return end
serverlistmgr.sync()
local function on_change(type)
if type == "ENTER" then
mm_game_theme.set_engine()
serverlistmgr.sync()
end
end
return {

View File

@@ -1,399 +0,0 @@
--Minetest
--Copyright (C) 2013 sapier
--
--This program is free software; you can redistribute it and/or modify
--it under the terms of the GNU Lesser General Public License as published by
--the Free Software Foundation; either version 2.1 of the License, or
--(at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--GNU Lesser General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public License along
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--------------------------------------------------------------------------------
local labels = {
leaves = {
fgettext("Opaque Leaves"),
fgettext("Simple Leaves"),
fgettext("Fancy Leaves")
},
node_highlighting = {
fgettext("Node Outlining"),
fgettext("Node Highlighting"),
fgettext("None")
},
filters = {
fgettext("No Filter"),
fgettext("Bilinear Filter"),
fgettext("Trilinear Filter")
},
mipmap = {
fgettext("No Mipmap"),
fgettext("Mipmap"),
fgettext("Mipmap + Aniso. Filter")
},
antialiasing = {
fgettext("None"),
fgettext("2x"),
fgettext("4x"),
fgettext("8x")
},
shadow_levels = {
fgettext("Disabled"),
fgettext("Very Low"),
fgettext("Low"),
fgettext("Medium"),
fgettext("High"),
fgettext("Very High")
}
}
local dd_options = {
leaves = {
table.concat(labels.leaves, ","),
{"opaque", "simple", "fancy"}
},
node_highlighting = {
table.concat(labels.node_highlighting, ","),
{"box", "halo", "none"}
},
filters = {
table.concat(labels.filters, ","),
{"", "bilinear_filter", "trilinear_filter"}
},
mipmap = {
table.concat(labels.mipmap, ","),
{"", "mip_map", "anisotropic_filter"}
},
antialiasing = {
table.concat(labels.antialiasing, ","),
{"0", "2", "4", "8"}
},
shadow_levels = {
table.concat(labels.shadow_levels, ","),
{ "0", "1", "2", "3", "4", "5" }
}
}
local getSettingIndex = {
Leaves = function()
local style = core.settings:get("leaves_style")
for idx, name in pairs(dd_options.leaves[2]) do
if style == name then return idx end
end
return 1
end,
NodeHighlighting = function()
local style = core.settings:get("node_highlighting")
for idx, name in pairs(dd_options.node_highlighting[2]) do
if style == name then return idx end
end
return 1
end,
Filter = function()
if core.settings:get(dd_options.filters[2][3]) == "true" then
return 3
elseif core.settings:get(dd_options.filters[2][3]) == "false" and
core.settings:get(dd_options.filters[2][2]) == "true" then
return 2
end
return 1
end,
Mipmap = function()
if core.settings:get(dd_options.mipmap[2][3]) == "true" then
return 3
elseif core.settings:get(dd_options.mipmap[2][3]) == "false" and
core.settings:get(dd_options.mipmap[2][2]) == "true" then
return 2
end
return 1
end,
Antialiasing = function()
local antialiasing_setting = core.settings:get("fsaa")
for i = 1, #dd_options.antialiasing[2] do
if antialiasing_setting == dd_options.antialiasing[2][i] then
return i
end
end
return 1
end,
ShadowMapping = function()
local shadow_setting = core.settings:get("shadow_levels")
for i = 1, #dd_options.shadow_levels[2] do
if shadow_setting == dd_options.shadow_levels[2][i] then
return i
end
end
return 1
end
}
local function antialiasing_fname_to_name(fname)
for i = 1, #labels.antialiasing do
if fname == labels.antialiasing[i] then
return dd_options.antialiasing[2][i]
end
end
return 0
end
local function formspec(tabview, name, tabdata)
local tab_string =
"box[0,0;3.75,4.5;#999999]" ..
"checkbox[0.25,0;cb_smooth_lighting;" .. fgettext("Smooth Lighting") .. ";"
.. dump(core.settings:get_bool("smooth_lighting")) .. "]" ..
"checkbox[0.25,0.5;cb_particles;" .. fgettext("Particles") .. ";"
.. dump(core.settings:get_bool("enable_particles")) .. "]" ..
"checkbox[0.25,1;cb_3d_clouds;" .. fgettext("3D Clouds") .. ";"
.. dump(core.settings:get_bool("enable_3d_clouds")) .. "]" ..
"checkbox[0.25,1.5;cb_opaque_water;" .. fgettext("Opaque Water") .. ";"
.. dump(core.settings:get_bool("opaque_water")) .. "]" ..
"checkbox[0.25,2.0;cb_connected_glass;" .. fgettext("Connected Glass") .. ";"
.. dump(core.settings:get_bool("connected_glass")) .. "]" ..
"dropdown[0.25,2.8;3.5;dd_node_highlighting;" .. dd_options.node_highlighting[1] .. ";"
.. getSettingIndex.NodeHighlighting() .. "]" ..
"dropdown[0.25,3.6;3.5;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
.. getSettingIndex.Leaves() .. "]" ..
"box[4,0;3.75,4.9;#999999]" ..
"label[4.25,0.1;" .. fgettext("Texturing:") .. "]" ..
"dropdown[4.25,0.55;3.5;dd_filters;" .. dd_options.filters[1] .. ";"
.. getSettingIndex.Filter() .. "]" ..
"dropdown[4.25,1.35;3.5;dd_mipmap;" .. dd_options.mipmap[1] .. ";"
.. getSettingIndex.Mipmap() .. "]" ..
"label[4.25,2.15;" .. fgettext("Antialiasing:") .. "]" ..
"dropdown[4.25,2.6;3.5;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
.. getSettingIndex.Antialiasing() .. "]" ..
"box[8,0;3.75,4.5;#999999]"
local video_driver = core.settings:get("video_driver")
local shaders_enabled = core.settings:get_bool("enable_shaders")
if video_driver == "opengl" then
tab_string = tab_string ..
"checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders") .. ";"
.. tostring(shaders_enabled) .. "]"
elseif video_driver == "ogles2" then
tab_string = tab_string ..
"checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders (experimental)") .. ";"
.. tostring(shaders_enabled) .. "]"
else
core.settings:set_bool("enable_shaders", false)
shaders_enabled = false
tab_string = tab_string ..
"label[8.38,0.2;" .. core.colorize("#888888",
fgettext("Shaders (unavailable)")) .. "]"
end
tab_string = tab_string ..
"button[8,4.75;3.95,1;btn_change_keys;"
.. fgettext("Change Keys") .. "]"
tab_string = tab_string ..
"button[0,4.75;3.95,1;btn_advanced_settings;"
.. fgettext("All Settings") .. "]"
if core.settings:get("touchscreen_threshold") ~= nil then
tab_string = tab_string ..
"label[4.25,3.5;" .. fgettext("Touch threshold (px):") .. "]" ..
"dropdown[4.25,3.95;3.5;dd_touchthreshold;0,10,20,30,40,50;" ..
((tonumber(core.settings:get("touchscreen_threshold")) / 10) + 1) ..
"]"
else
tab_string = tab_string ..
"label[4.25,3.65;" .. fgettext("Screen:") .. "]" ..
"checkbox[4.25,3.9;cb_autosave_screensize;" .. fgettext("Autosave Screen Size") .. ";"
.. dump(core.settings:get_bool("autosave_screensize")) .. "]"
end
if shaders_enabled then
tab_string = tab_string ..
"checkbox[8.25,0.5;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
.. dump(core.settings:get_bool("tone_mapping")) .. "]" ..
"checkbox[8.25,1;cb_waving_water;" .. fgettext("Waving Liquids") .. ";"
.. dump(core.settings:get_bool("enable_waving_water")) .. "]" ..
"checkbox[8.25,1.5;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
.. dump(core.settings:get_bool("enable_waving_leaves")) .. "]" ..
"checkbox[8.25,2;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
.. dump(core.settings:get_bool("enable_waving_plants")) .. "]"
if video_driver == "opengl" then
tab_string = tab_string ..
"label[8.25,2.8;" .. fgettext("Dynamic shadows:") .. "]" ..
"label[8.25,3.2;" .. fgettext("(game support required)") .. "]" ..
"dropdown[8.25,3.7;3.5;dd_shadows;" .. dd_options.shadow_levels[1] .. ";"
.. getSettingIndex.ShadowMapping() .. "]"
else
tab_string = tab_string ..
"label[8.38,2.7;" .. core.colorize("#888888",
fgettext("Dynamic shadows")) .. "]"
end
else
tab_string = tab_string ..
"label[8.38,0.7;" .. core.colorize("#888888",
fgettext("Tone Mapping")) .. "]" ..
"label[8.38,1.2;" .. core.colorize("#888888",
fgettext("Waving Liquids")) .. "]" ..
"label[8.38,1.7;" .. core.colorize("#888888",
fgettext("Waving Leaves")) .. "]" ..
"label[8.38,2.2;" .. core.colorize("#888888",
fgettext("Waving Plants")) .. "]"..
"label[8.38,2.7;" .. core.colorize("#888888",
fgettext("Dynamic shadows")) .. "]"
end
return tab_string
end
--------------------------------------------------------------------------------
local function handle_settings_buttons(this, fields, tabname, tabdata)
if fields["btn_advanced_settings"] ~= nil then
local adv_settings_dlg = create_adv_settings_dlg()
adv_settings_dlg:set_parent(this)
this:hide()
adv_settings_dlg:show()
--mm_game_theme.update("singleplayer", current_game())
return true
end
if fields["cb_smooth_lighting"] then
core.settings:set("smooth_lighting", fields["cb_smooth_lighting"])
return true
end
if fields["cb_particles"] then
core.settings:set("enable_particles", fields["cb_particles"])
return true
end
if fields["cb_3d_clouds"] then
core.settings:set("enable_3d_clouds", fields["cb_3d_clouds"])
return true
end
if fields["cb_opaque_water"] then
core.settings:set("opaque_water", fields["cb_opaque_water"])
return true
end
if fields["cb_connected_glass"] then
core.settings:set("connected_glass", fields["cb_connected_glass"])
return true
end
if fields["cb_autosave_screensize"] then
core.settings:set("autosave_screensize", fields["cb_autosave_screensize"])
return true
end
if fields["cb_shaders"] then
core.settings:set("enable_shaders", fields["cb_shaders"])
return true
end
if fields["cb_tonemapping"] then
core.settings:set("tone_mapping", fields["cb_tonemapping"])
return true
end
if fields["cb_waving_water"] then
core.settings:set("enable_waving_water", fields["cb_waving_water"])
return true
end
if fields["cb_waving_leaves"] then
core.settings:set("enable_waving_leaves", fields["cb_waving_leaves"])
end
if fields["cb_waving_plants"] then
core.settings:set("enable_waving_plants", fields["cb_waving_plants"])
return true
end
if fields["btn_change_keys"] then
core.show_keys_menu()
return true
end
--Note dropdowns have to be handled LAST!
local ddhandled = false
for i = 1, #labels.leaves do
if fields["dd_leaves_style"] == labels.leaves[i] then
core.settings:set("leaves_style", dd_options.leaves[2][i])
ddhandled = true
end
end
for i = 1, #labels.node_highlighting do
if fields["dd_node_highlighting"] == labels.node_highlighting[i] then
core.settings:set("node_highlighting", dd_options.node_highlighting[2][i])
ddhandled = true
end
end
if fields["dd_filters"] == labels.filters[1] then
core.settings:set("bilinear_filter", "false")
core.settings:set("trilinear_filter", "false")
ddhandled = true
elseif fields["dd_filters"] == labels.filters[2] then
core.settings:set("bilinear_filter", "true")
core.settings:set("trilinear_filter", "false")
ddhandled = true
elseif fields["dd_filters"] == labels.filters[3] then
core.settings:set("bilinear_filter", "false")
core.settings:set("trilinear_filter", "true")
ddhandled = true
end
if fields["dd_mipmap"] == labels.mipmap[1] then
core.settings:set("mip_map", "false")
core.settings:set("anisotropic_filter", "false")
ddhandled = true
elseif fields["dd_mipmap"] == labels.mipmap[2] then
core.settings:set("mip_map", "true")
core.settings:set("anisotropic_filter", "false")
ddhandled = true
elseif fields["dd_mipmap"] == labels.mipmap[3] then
core.settings:set("mip_map", "true")
core.settings:set("anisotropic_filter", "true")
ddhandled = true
end
if fields["dd_antialiasing"] then
core.settings:set("fsaa",
antialiasing_fname_to_name(fields["dd_antialiasing"]))
ddhandled = true
end
if fields["dd_touchthreshold"] then
core.settings:set("touchscreen_threshold", fields["dd_touchthreshold"])
ddhandled = true
end
for i = 1, #labels.shadow_levels do
if fields["dd_shadows"] == labels.shadow_levels[i] then
core.settings:set("shadow_levels", dd_options.shadow_levels[2][i])
ddhandled = true
end
end
if fields["dd_shadows"] == labels.shadow_levels[1] then
core.settings:set("enable_dynamic_shadows", "false")
else
local shadow_presets = {
[2] = { 62, 512, "true", 0, "false" },
[3] = { 93, 1024, "true", 0, "false" },
[4] = { 140, 2048, "true", 1, "false" },
[5] = { 210, 4096, "true", 2, "true" },
[6] = { 300, 8192, "true", 2, "true" },
}
local s = shadow_presets[table.indexof(labels.shadow_levels, fields["dd_shadows"])]
if s then
core.settings:set("enable_dynamic_shadows", "true")
core.settings:set("shadow_map_max_distance", s[1])
core.settings:set("shadow_map_texture_size", s[2])
core.settings:set("shadow_map_texture_32bit", s[3])
core.settings:set("shadow_filters", s[4])
core.settings:set("shadow_map_color", s[5])
end
end
return ddhandled
end
return {
name = "settings",
caption = fgettext("Settings"),
cbf_formspec = formspec,
cbf_button_handler = handle_settings_buttons
}

View File

@@ -57,6 +57,25 @@
# Comments and (Readable name) are handled by gettext.
# Comments should be complete sentences that describe the setting and possibly
# give the user additional useful insight.
# The last line of a comment can contain the requirements for the setting, ie:
#
# # This is a comment
# #
# # Requires: shaders, enable_dynamic_shadows, !touchscreen_gui
# name (Readable name) type type_args
#
# A requirement can be the name of a boolean setting or an engine-defined value.
# These requirements may be:
#
# * The value of a boolean setting, such as enable_dynamic_shadows
# * An engine-defined value:
# * shaders_support (a video driver that supports shaders, may not be enabled)
# * shaders (both enable_shaders and shaders_support)
# * desktop / android
# * touchscreen_gui / keyboard_mouse
# * opengl / gles
# * You can negate any requirement by prepending with !
#
# 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-sub-sections have two * etc.
@@ -68,20 +87,18 @@
[*General]
# If enabled, you can place blocks at the position (feet + eye level) where you stand.
# This is helpful when working with nodeboxes in small areas.
enable_build_where_you_stand (Build inside player) bool false
# Smooths camera when looking around. Also called look or mouse smoothing.
# Useful for recording videos.
cinematic (Cinematic mode) bool false
# Smooths rotation of camera. 0 to disable.
# Smooths rotation of camera, also called look or mouse smoothing. 0 to disable.
camera_smoothing (Camera smoothing) float 0.0 0.0 0.99
# Smooths rotation of camera in cinematic mode. 0 to disable.
# Smooths rotation of camera when in cinematic mode, 0 to disable. Enter cinematic mode by using the key set in Change Keys.
#
# Requires: keyboard_mouse
cinematic_camera_smoothing (Camera smoothing in cinematic mode) float 0.7 0.0 0.99
# If enabled, you can place nodes at the position (feet + eye level) where you stand.
# This is helpful when working with nodeboxes in small areas.
enable_build_where_you_stand (Build inside player) bool false
# If enabled, "Aux1" key instead of "Sneak" key is used for climbing down and
# descending.
aux1_descends (Aux1 key for climbing/descending) bool false
@@ -95,38 +112,68 @@ always_fly_fast (Always fly fast) bool true
# The time in seconds it takes between repeated node placements when holding
# the place button.
#
# Requires: keyboard_mouse
repeat_place_time (Place repetition interval) float 0.25 0.16 2
# Automatically jump up single-node obstacles.
autojump (Automatic jumping) bool false
# Prevent digging and placing from repeating when holding the mouse buttons.
# Prevent digging and placing from repeating when holding the respective buttons.
# Enable this when you dig or place too often by accident.
# On touchscreens, this only affects digging.
safe_dig_and_place (Safe digging and placing) bool false
[*Keyboard and Mouse]
# Invert vertical mouse movement.
#
# Requires: keyboard_mouse
invert_mouse (Invert mouse) bool false
# Mouse sensitivity multiplier.
#
# Requires: keyboard_mouse
mouse_sensitivity (Mouse sensitivity) float 0.2 0.001 10.0
# Enable mouse wheel (scroll) for item selection in hotbar.
#
# Requires: keyboard_mouse
enable_hotbar_mouse_wheel (Hotbar: Enable mouse wheel for selection) bool true
# Invert mouse wheel (scroll) direction for item selection in hotbar.
#
# Requires: keyboard_mouse
invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
[*Touchscreen]
# The length in pixels it takes for touch screen interaction to start.
touchscreen_threshold (Touch screen threshold) int 20 0 100
# The length in pixels it takes for touchscreen interaction to start.
#
# Requires: touchscreen_gui
touchscreen_threshold (Touchscreen threshold) int 20 0 100
# Touchscreen sensitivity multiplier.
#
# Requires: touchscreen_gui
touchscreen_sensitivity (Touchscreen sensitivity) float 0.2 0.001 10.0
# 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_gui
touch_use_crosshair (Use crosshair for touch screen) bool false
# (Android) Fixes the position of virtual joystick.
# Fixes the position of virtual joystick.
# If disabled, virtual joystick will center to first-touch's position.
#
# Requires: touchscreen_gui
fixed_virtual_joystick (Fixed virtual joystick) bool false
# (Android) Use virtual joystick to trigger "Aux1" button.
# Use virtual joystick to trigger "Aux1" button.
# If enabled, virtual joystick will also tap "Aux1" button when out of main circle.
#
# Requires: touchscreen_gui
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
@@ -136,20 +183,38 @@ virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool fals
[**Screen]
# Width component of the initial window size. Ignored in fullscreen mode.
# Width component of the initial window size.
#
# Requires: desktop
screen_w (Screen width) int 1024 1 65535
# Height component of the initial window size. Ignored in fullscreen mode.
# Height component of the initial window size.
#
# Requires: desktop
screen_h (Screen height) int 600 1 65535
# Whether the window is maximized.
#
# Requires: desktop
window_maximized (Window maximized) bool false
# Save window size automatically when modified.
autosave_screensize (Autosave screen size) bool true
# If true, screen size is saved in screen_w and screen_h, and whether the window
# is maximized is stored in window_maximized.
# (Autosaving window_maximized only works if compiled with SDL.)
#
# Requires: desktop
autosave_screensize (Remember screen size) bool true
# Fullscreen mode.
#
# Requires: desktop
fullscreen (Full screen) bool false
# Open the pause menu when the window's focus is lost. Does not pause if a formspec is
# open.
#
# Requires: desktop
pause_on_lost_focus (Pause on lost window focus) bool false
[**FPS]
@@ -158,7 +223,7 @@ pause_on_lost_focus (Pause on lost window focus) bool false
# to not waste CPU power for no benefit.
fps_max (Maximum FPS) int 60 1 4294967295
# Vertical screen synchronization.
# Vertical screen synchronization. Your system may still force VSync on even if this is disabled.
vsync (VSync) bool false
# Maximum FPS when the window is not focused, or when the game is paused.
@@ -198,13 +263,13 @@ performance_tradeoffs (Tradeoffs for performance) bool false
# Adds particles when digging a node.
enable_particles (Digging particles) bool true
[**3d]
[**3D]
# 3D support.
# Currently supported:
# - none: no 3d output.
# - anaglyph: cyan/magenta color 3d.
# - interlaced: odd/even line based polarisation screen support.
# - interlaced: odd/even line based polarization screen support.
# - topbottom: split screen top/bottom.
# - sidebyside: split screen side by side.
# - crossview: Cross-eyed 3d
@@ -230,12 +295,6 @@ fall_bobbing_amount (Fall bobbing factor) float 0.03 0.0 100.0
[**Camera]
# Camera 'near clipping plane' distance in nodes, between 0 and 0.25
# Only works on GLES platforms. Most users will not need to change this.
# Increasing can reduce artifacting on weaker GPUs.
# 0.1 = Default, 0.25 = Good value for weaker tablets.
near_plane (Near plane) float 0.1 0 0.25
# Field of view in degrees.
fov (Field of view) int 72 45 160
@@ -250,20 +309,26 @@ display_gamma (Light curve gamma) float 1.0 0.33 3.0
# Lower is darker, Higher is lighter. The valid range of values for this
# setting is 0.25 to 4.0 inclusive. If the value is out of range it will be
# set to the nearest valid value.
ambient_occlusion_gamma (Ambient occlusion gamma) float 2.2 0.25 4.0
ambient_occlusion_gamma (Ambient occlusion gamma) float 1.8 0.25 4.0
[**Screenshots]
# Path to save screenshots at. Can be an absolute or relative path.
# The folder will be created if it doesn't already exist.
#
# Requires: desktop
screenshot_path (Screenshot folder) path screenshots
# Format of screenshots.
#
# Requires: desktop
screenshot_format (Screenshot format) enum png png,jpg
# Screenshot quality. Only used for JPEG format.
# 1 means worst quality; 100 means best quality.
# Use 0 for default quality.
#
# Requires: desktop
screenshot_quality (Screenshot quality) int 0 0 100
[**Node and Entity Highlighting]
@@ -295,59 +360,81 @@ crosshair_alpha (Crosshair alpha) int 255 0 255
enable_fog (Fog) bool true
# Make fog and sky colors depend on daytime (dawn/sunset) and view direction.
#
# Requires: enable_fog
directional_colored_fog (Colored fog) bool true
# Fraction of the visible distance at which fog starts to be rendered
#
# Requires: enable_fog
fog_start (Fog start) float 0.4 0.0 0.99
[**Clouds]
# Clouds are a client side effect.
# Clouds are a client-side effect.
enable_clouds (Clouds) bool true
# Use 3D cloud look instead of flat.
#
# Requires: enable_clouds
enable_3d_clouds (3D clouds) bool true
[**Filtering and Antialiasing]
# Use mipmapping to scale textures. May slightly increase performance,
# especially when using a high resolution texture pack.
# Gamma correct downscaling is not supported.
# Use mipmaps when scaling textures. May slightly increase performance,
# especially when using a high-resolution texture pack.
# Gamma-correct downscaling is not supported.
mip_map (Mipmapping) bool false
# Use anisotropic filtering when viewing at textures from an angle.
anisotropic_filter (Anisotropic filtering) bool false
# Use bilinear filtering when scaling textures.
bilinear_filter (Bilinear filtering) bool false
# Use trilinear filtering when scaling textures.
# If both bilinear and trilinear filtering are enabled, trilinear filtering
# is applied.
trilinear_filter (Trilinear filtering) bool false
# Filtered textures can blend RGB values with fully-transparent neighbors,
# which PNG optimizers usually discard, often resulting in dark or
# light edges to transparent textures. Apply a filter to clean that up
# at texture load time. This is automatically enabled if mipmapping is enabled.
texture_clean_transparent (Clean transparent textures) bool false
# Use anisotropic filtering when looking at textures from an angle.
anisotropic_filter (Anisotropic filtering) bool false
# When using bilinear/trilinear/anisotropic filters, low-resolution textures
# can be blurred, so automatically upscale them with nearest-neighbor
# interpolation to preserve crisp pixels. This sets the minimum texture size
# for the upscaled textures; higher values look sharper, but require more
# memory. Powers of 2 are recommended. This setting is ONLY applied if
# bilinear/trilinear/anisotropic filtering is enabled.
# This is also used as the base node texture size for world-aligned
# texture autoscaling.
texture_min_size (Minimum texture size) int 64 1 32768
# Select the antialiasing method to apply.
#
# * None - No antialiasing (default)
#
# * FSAA - Hardware-provided full-screen antialiasing
# (incompatible with Post Processing and Undersampling)
# A.K.A multi-sample antialiasing (MSAA)
# Smoothens out block edges but does not affect the insides of textures.
# A restart is required to change this option.
#
# * FXAA - Fast approximate antialiasing (requires shaders)
# Applies a post-processing filter to detect and smoothen high-contrast edges.
# Provides balance between speed and image quality.
#
# * SSAA - Super-sampling antialiasing (requires shaders)
# Renders higher-resolution image of the scene, then scales down to reduce
# the aliasing effects. This is the slowest and the most accurate method.
antialiasing (Antialiasing method) enum none none,fsaa,fxaa,ssaa
# Defines the size of the sampling grid for FSAA and SSAA antialiasing methods.
# Value of 2 means taking 2x2 = 4 samples.
fsaa (Anti-aliasing scale) enum 2 2,4,8,16
[**Occlusion Culling]
# Type of occlusion_culler
#
# "loops" is the legacy algorithm with nested loops and O(n³) complexity
# "bfs" is the new algorithm based on breadth-first-search and side culling
#
# This setting should only be changed if you have performance problems.
occlusion_culler (Occlusion Culler) enum bfs bfs,loops
# Use raytraced occlusion culling in the new culler.
# This flag enables use of raytraced occlusion culling test for
# client mesh sizes smaller than 4x4x4 map blocks.
enable_raytraced_culling (Enable Raytraced Culling) bool true
# Use multi-sample antialiasing (MSAA) to smooth out block edges.
# This algorithm smooths out the 3D viewport while keeping the image sharp,
# but it doesn't affect the insides of textures
# (which is especially noticeable with transparent textures).
# Visible spaces appear between nodes when shaders are disabled.
# If set to 0, MSAA is disabled.
# A restart is required after changing this option.
fsaa (FSAA) enum 0 0,1,2,4,8,16
[*Shaders]
@@ -355,138 +442,184 @@ fsaa (FSAA) enum 0 0,1,2,4,8,16
# Shaders allow advanced visual effects and may increase performance on some video
# cards.
# This only works with the OpenGL video backend.
#
# Requires: shaders_support
enable_shaders (Shaders) bool true
[**Tone Mapping]
# Enables Hable's 'Uncharted 2' filmic tone mapping.
# Simulates the tone curve of photographic film and how this approximates the
# appearance of high dynamic range images. Mid-range contrast is slightly
# enhanced, highlights and shadows are gradually compressed.
tone_mapping (Filmic tone mapping) bool false
[**Waving Nodes]
# Set to true to enable waving leaves.
# Requires shaders to be enabled.
#
# Requires: shaders
enable_waving_leaves (Waving leaves) bool false
# Set to true to enable waving plants.
# Requires shaders to be enabled.
#
# Requires: shaders
enable_waving_plants (Waving plants) bool false
# Set to true to enable waving liquids (like water).
# Requires shaders to be enabled.
#
# Requires: shaders
enable_waving_water (Waving liquids) bool false
# The maximum height of the surface of waving liquids.
# 4.0 = Wave height is two nodes.
# 0.0 = Wave doesn't move at all.
# Default is 1.0 (1/2 node).
# Requires waving liquids to be enabled.
#
# Requires: shaders, enable_waving_water
water_wave_height (Waving liquids wave height) float 1.0 0.0 4.0
# Length of liquid waves.
# Requires waving liquids to be enabled.
#
# Requires: shaders, enable_waving_water
water_wave_length (Waving liquids wavelength) float 20.0 0.1
# How fast liquid waves will move. Higher = faster.
# If negative, liquid waves will move backwards.
# Requires waving liquids to be enabled.
#
# Requires: shaders, enable_waving_water
water_wave_speed (Waving liquids wave speed) float 5.0
[**Dynamic shadows]
# Set to true to enable Shadow Mapping.
# Requires shaders to be enabled.
#
# Requires: shaders, opengl
enable_dynamic_shadows (Dynamic shadows) bool false
# Set the shadow strength gamma.
# Adjusts the intensity of in-game dynamic shadows.
# Lower value means lighter shadows, higher value means darker shadows.
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_strength_gamma (Shadow strength gamma) float 1.0 0.1 10.0
# Maximum distance to render shadows.
shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 120.0 10.0 1000.0
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 140.0 10.0 1000.0
# Texture size to render the shadow map on.
# This must be a power of two.
# Bigger numbers create better shadows but it is also more expensive.
shadow_map_texture_size (Shadow map texture size) int 1024 128 8192
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_map_texture_size (Shadow map texture size) int 2048 128 8192
# Sets shadow texture quality to 32 bits.
# On false, 16 bits texture will be used.
# This can cause much more artifacts in the shadow.
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true
# Enable Poisson disk filtering.
# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering.
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_poisson_filter (Poisson filtering) bool true
# Define shadow filtering quality.
# This simulates the soft shadows effect by applying a PCF or Poisson disk
# but also uses more resources.
# Define shadow filtering quality.
# This simulates the soft shadows effect by applying a PCF or Poisson disk
# but also uses more resources.
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_filters (Shadow filter quality) enum 1 0,1,2
# Enable colored shadows.
# On true translucent nodes cast colored shadows. This is expensive.
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_map_color (Colored shadows) bool false
# Spread a complete update of shadow map over given amount of frames.
# Spread a complete update of shadow map over given number of frames.
# Higher values might make shadows laggy, lower values
# will consume more resources.
# Minimum value: 1; maximum value: 16
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_update_frames (Map shadows update frames) int 8 1 16
# Set the soft shadow radius size.
# Lower values mean sharper shadows, bigger values mean softer shadows.
# Minimum value: 1.0; maximum value: 15.0
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0
# Set the default tilt of Sun/Moon orbit in degrees.
# Games may change orbit tilt via API.
# Value of 0 means no tilt / vertical orbit.
# type: float min: -60 max: 60
#
# Requires: shaders, enable_dynamic_shadows, opengl
shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 -60.0 60.0
[**Post processing]
[**Post Processing]
# Set the exposure compensation in EV units.
# Value of 0.0 (default) means no exposure compensation.
# Range: from -1 to 1.0
exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0
# Enables the post processing pipeline.
#
# Requires: shaders
enable_post_processing (Enable Post Processing) bool true
# Enables Hable's 'Uncharted 2' filmic tone mapping.
# Simulates the tone curve of photographic film and how this approximates the
# appearance of high dynamic range images. Mid-range contrast is slightly
# enhanced, highlights and shadows are gradually compressed.
#
# Requires: shaders, enable_post_processing
tone_mapping (Filmic tone mapping) bool false
# Enable automatic exposure correction
# When enabled, the post-processing engine will
# automatically adjust to the brightness of the scene,
# simulating the behavior of human eye.
#
# Requires: shaders, enable_post_processing
enable_auto_exposure (Enable Automatic Exposure) bool false
# Set the exposure compensation in EV units.
# Value of 0.0 (default) means no exposure compensation.
# Range: from -1 to 1.0
#
# Requires: shaders, enable_post_processing, enable_auto_exposure
exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0
[**Bloom]
# Set to true to enable bloom effect.
# Bright colors will bleed over the neighboring objects.
#
# Requires: shaders, enable_post_processing
enable_bloom (Enable Bloom) bool false
# Set to true to render debugging breakdown of the bloom effect.
# In debug mode, the screen is split into 4 quadrants:
# top-left - processed base image, top-right - final image
# bottom-left - raw base image, bottom-right - bloom texture.
#
# Requires: shaders, enable_post_processing, enable_bloom
enable_bloom_debug (Enable Bloom Debug) bool false
# Defines how much bloom is applied to the rendered image
# Smaller values make bloom more subtle
# Range: from 0.01 to 1.0, default: 0.05
#
# Requires: shaders, enable_post_processing, enable_bloom
bloom_intensity (Bloom Intensity) float 0.05 0.01 1.0
# Defines the magnitude of bloom overexposure.
# Range: from 0.1 to 10.0, default: 1.0
#
# Requires: shaders, enable_post_processing, enable_bloom
bloom_strength_factor (Bloom Strength Factor) float 1.0 0.1 10.0
# Logical value that controls how far the bloom effect spreads
# from the bright objects.
# Range: from 0.1 to 8, default: 1
#
# Requires: shaders, enable_post_processing, enable_bloom
bloom_radius (Bloom Radius) float 1 0.1 8
@@ -494,7 +627,7 @@ bloom_radius (Bloom Radius) float 1 0.1 8
# Volume of all sounds.
# Requires the sound system to be enabled.
sound_volume (Volume) float 0.7 0.0 1.0
sound_volume (Volume) float 0.8 0.0 1.0
# Whether to mute sounds. You can unmute sounds at any time, unless the
# sound system is disabled (enable_sound=false).
@@ -508,7 +641,7 @@ mute_sound (Mute sound) bool false
# A restart is required after changing this.
language (Language) enum ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,id,it,ja,jbo,kk,ko,lt,lv,ms,nb,nl,nn,pl,pt,pt_BR,ro,ru,sk,sl,sr_Cyrl,sr_Latn,sv,sw,tr,uk,vi,zh_CN,zh_TW
[**GUIs]
[**GUI]
# Scale GUI by a user specified value.
# Use a nearest-neighbor-anti-alias filter to scale the GUI.
@@ -577,7 +710,7 @@ hud_hotbar_max_width (Maximum hotbar width) float 1.0 0.001 1.0
clickable_chat_weblinks (Chat weblinks) bool true
# Optional override for chat weblink color.
chat_weblink_color (Weblink color) string
chat_weblink_color (Weblink color) string #8888FF
# Font size of the recent chat text and chat prompt in point (pt).
# Value 0 will use the default font size.
@@ -619,26 +752,6 @@ enable_split_login_register (Enable split login/register) bool true
# URL to JSON file which provides information about the newest Minetest release
update_information_url (Update information URL) string https://www.minetest.net/release_info.json
# Unix timestamp (integer) of when the client last checked for an update
# Set this value to "disabled" to never check for updates.
update_last_checked (Last update check) string
# Version number which was last seen during an update check.
#
# Representation: MMMIIIPPP, where M=Major, I=Minor, P=Patch
# Ex: 5.5.0 is 005005000
update_last_known (Last known version update) int 0
# Type of occlusion_culler
# "loops" is the legacy algorithm with nested loops and O(N^3) complexity
# "bfs" is the new algorithm based on breadth-first-search and side culling
occlusion_culler (Occlusion Culler) enum bfs bfs,loops
# Use raytraced occlusion culling in the new culler.
# This flag enables use of raytraced occlusion culling test for
# client mesh sizes smaller than 4x4x4 map blocks.
enable_raytraced_culling (Enable Raytraced Culling) bool true
[*Server]
# Name of the player.
@@ -673,7 +786,7 @@ motd (Message of the day) string
max_users (Maximum users) int 15 0 65535
# If this is set, players will always (re)spawn at the given position.
static_spawnpoint (Static spawnpoint) string
static_spawnpoint (Static spawn point) string
[**Networking]
@@ -738,7 +851,7 @@ csm_restriction_flags (Client side modding restrictions) int 62 0 63
# If the CSM restriction for node range is enabled, get_node calls are limited
# to this distance from the player to the node.
csm_restriction_noderange (Client side node lookup range restriction) int 0 0 4294967295
csm_restriction_noderange (Client-side node lookup range restriction) int 0 0 4294967295
[**Chat]
@@ -749,8 +862,8 @@ strip_color_codes (Strip color codes) bool false
# Set the maximum length of a chat message (in characters) sent by clients.
chat_message_max_size (Chat message max length) int 500 10 65535
# Amount of messages a player may send per 10 seconds.
chat_message_limit_per_10sec (Chat message count limit) float 10.0 1.0
# Number of messages a player may send per 10 seconds.
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.
chat_message_limit_trigger_kick (Chat message kick threshold) int 50 1 65535
@@ -846,7 +959,7 @@ mapgen_limit (Map generation limit) int 31007 0 31007
# and jungle grass, in all other mapgens this flag controls all decorations.
mg_flags (Mapgen flags) flags caves,dungeons,light,decorations,biomes,ores caves,dungeons,light,decorations,biomes,ores,nocaves,nodungeons,nolight,nodecorations,nobiomes,noores
[*Biome API noise parameters]
[*Biome API]
# Temperature variation for biomes.
mg_biome_np_heat (Heat noise) noise_params_2d 50, 50, (1000, 1000, 1000), 5349, 3, 0.5, 2.0, eased
@@ -1029,7 +1142,7 @@ mgv7_floatland_density (Floatland density) float -0.6
# to above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the
# upper tapering).
# ***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***:
# When enabling water placement the floatlands must be configured and tested
# When enabling water placement, floatlands must be configured and tested
# to be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other
# required value depending on 'mgv7_np_floatland'), to avoid
# server-intensive extreme water flow and to avoid vast flooding of the
@@ -1456,7 +1569,7 @@ mgfractal_np_dungeons (Dungeon noise) noise_params_3d 0.9, 0.5, (500, 500, 500),
mgvalleys_spflags (Mapgen Valleys specific flags) flags altitude_chill,humid_rivers,vary_river_depth,altitude_dry altitude_chill,humid_rivers,vary_river_depth,altitude_dry,noaltitude_chill,nohumid_rivers,novary_river_depth,noaltitude_dry
# The vertical distance over which heat drops by 20 if 'altitude_chill' is
# enabled. Also the vertical distance over which humidity drops by 10 if
# enabled. Also, the vertical distance over which humidity drops by 10 if
# 'altitude_dry' is enabled.
mgvalleys_altitude_chill (Altitude chill) int 90 0 65535
@@ -1512,7 +1625,7 @@ mgvalleys_np_cave1 (Cave noise #1) noise_params_3d 0, 12, (61, 61, 61), 52534, 3
# Second of two 3D noises that together define tunnels.
mgvalleys_np_cave2 (Cave noise #2) noise_params_3d 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0
# The depth of dirt or other biome filler node.
# Variation of biome filler depth.
mgvalleys_np_filler_depth (Filler depth) noise_params_2d 0, 1.2, (256, 256, 256), 1605, 3, 0.5, 2.0, eased
# 3D noise defining giant caverns.
@@ -1609,8 +1722,8 @@ profiler.load (Load the game profiler) bool false
# when calling `/profiler save [format]` without format.
profiler.default_report_format (Default report format) enum txt txt,csv,lua,json,json_pretty
# The file path relative to your worldpath in which profiles will be saved to.
profiler.report_path (Report path) string ""
# The file path relative to your world path in which profiles will be saved to.
profiler.report_path (Report path) string
# Instrument the methods of entities on registration.
instrument.entity (Entity methods) bool true
@@ -1638,7 +1751,7 @@ instrument.builtin (Builtin) bool false
# * Instrument the sampler being used to update the statistics.
instrument.profiler (Profiler) bool false
[**Engine profiler]
[**Engine Profiler]
# Print the engine's profiling data in regular intervals (in seconds).
# 0 = disable. Useful for developers.
@@ -1658,13 +1771,15 @@ ignore_world_load_errors (Ignore world errors) bool false
[**Graphics]
# Path to shader directory. If no path is defined, default location will be used.
#
# Requires: shaders
shader_path (Shader path) path
# The rendering back-end.
# Note: A restart is required after changing this!
# OpenGL is the default for desktop, and OGLES2 for Android.
# Shaders are supported by OpenGL and OGLES2 (experimental).
video_driver (Video driver) enum opengl opengl,ogles1,ogles2
video_driver (Video driver) enum ,opengl,ogles1,ogles2
# Distance in nodes at which transparency depth sorting is enabled
# Use this to limit the performance impact of transparency depth sorting
@@ -1679,7 +1794,7 @@ enable_vbo (VBO) bool true
cloud_radius (Cloud radius) int 12 1 62
# Whether node texture animations should be desynchronized per mapblock.
desynchronize_mapblock_texture_animation (Desynchronize block animation) bool true
desynchronize_mapblock_texture_animation (Desynchronize block animation) bool false
# Enables caching of facedir rotated meshes.
enable_mesh_cache (Mesh cache) bool false
@@ -1692,7 +1807,6 @@ mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50
# Value of 0 (default) will let Minetest autodetect the number of available threads.
mesh_generation_threads (Mapblock mesh generation threads) int 0 0 8
# Size of the MapBlock cache of the mesh generator. Increasing this will
# increase the cache hit %, reducing the data being copied from the main
# thread, thus reducing jitter.
@@ -1719,6 +1833,16 @@ world_aligned_mode (World-aligned textures mode) enum enable disable,enable,forc
# Warning: This option is EXPERIMENTAL!
autoscale_mode (Autoscaling mode) enum disable disable,enable,force
# When using bilinear/trilinear/anisotropic filters, low-resolution textures
# can be blurred, so automatically upscale them with nearest-neighbor
# interpolation to preserve crisp pixels. This sets the minimum texture size
# for the upscaled textures; higher values look sharper, but require more
# memory. Powers of 2 are recommended. This setting is ONLY applied if
# bilinear/trilinear/anisotropic filtering is enabled.
# This is also used as the base node texture size for world-aligned
# texture autoscaling.
texture_min_size (Base texture size) int 64 1 32768
# Side length of a cube of map blocks that the client will consider together
# when generating meshes.
# Larger values increase the utilization of the GPU by reducing the number of
@@ -1808,9 +1932,9 @@ lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
# Metrics can be fetched on http://127.0.0.1:30000/metrics
prometheus_listener_address (Prometheus listener address) string 127.0.0.1:30000
# Maximum size of the out chat queue.
# Maximum size of the outgoing chat queue.
# 0 to disable queueing and -1 to make the queue size unlimited.
max_out_chat_queue_size (Maximum size of the out chat queue) int 20 -1 32767
max_out_chat_queue_size (Maximum size of the outgoing chat queue) int 20 -1 32767
# 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
@@ -1943,16 +2067,16 @@ liquid_update (Liquid update tick) float 1.0 0.001
# Stated in mapblocks (16 nodes).
block_send_optimize_distance (Block send optimize distance) int 4 2 32767
# If enabled the server will perform map block occlusion culling based on
# If enabled, the server will perform map block occlusion culling based on
# on the eye position of the player. This can reduce the number of blocks
# sent to the client 50-80%. The client will not longer receive most invisible
# so that the utility of noclip mode is reduced.
server_side_occlusion_culling (Server side occlusion culling) bool true
# sent to the client by 50-80%. Clients will no longer receive most
# invisible blocks, so that the utility of noclip mode is reduced.
server_side_occlusion_culling (Server-side occlusion culling) bool true
[**Mapgen]
# 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
# increasing this value above 5.
# Reducing this value increases cave and dungeon density.
# Altering this value is for special usage, leaving it unchanged is
@@ -1988,7 +2112,7 @@ num_emerge_threads (Number of emerge threads) int 1 0 32767
[**cURL]
# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
curl_timeout (cURL interactive timeout) int 20000 100 2147483647
curl_timeout (cURL interactive timeout) int 20000 1000 2147483647
# Limits number of parallel HTTP requests. Affects:
# - Media fetch if server uses remote_media setting.
@@ -1998,9 +2122,9 @@ curl_timeout (cURL interactive timeout) int 20000 100 2147483647
curl_parallel_limit (cURL parallel limit) int 8 1 2147483647
# Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.
curl_file_download_timeout (cURL file download timeout) int 300000 100 2147483647
curl_file_download_timeout (cURL file download timeout) int 300000 5000 2147483647
[**Misc]
[**Miscellaneous]
# Adjust dpi configuration to your screen (non X11/Android only) e.g. for 4k screens.
screen_dpi (DPI) int 72 1
@@ -2063,7 +2187,7 @@ joystick_deadzone (Joystick dead zone) int 2048 0 65535
joystick_frustum_sensitivity (Joystick frustum sensitivity) float 170.0 0.001
[*Temporary Settings]
[*Hide: Temporary Settings]
# Path to texture directory. All textures are first searched from here.
texture_path (Texture path) path
@@ -2083,10 +2207,6 @@ address (Server address) string
# Note that the port field in the main menu overrides this setting.
remote_port (Remote port) int 30000 1 65535
# Default game when creating a new world.
# This will be overridden when creating a world from the main menu.
default_game (Default game) string minetest
# Enable players getting damage and dying.
enable_damage (Damage) bool false
@@ -2115,24 +2235,38 @@ noclip (Noclip) bool false
# Press the autoforward key again or the backwards movement to disable.
continuous_forward (Continuous forward) bool false
# Formspec default background opacity (between 0 and 255).
formspec_default_bg_opacity (Formspec Default Background Opacity) int 140 0 255
# This can be bound to a key to toggle camera smoothing when looking around.
# Useful for recording videos
cinematic (Cinematic mode) bool false
# Formspec default background color (R,G,B).
formspec_default_bg_color (Formspec Default Background Color) string (0,0,0)
# Whether to show technical names.
# Affects mods and texture packs in the Content and Select Mods menus, as well as
# setting names in All Settings.
# Controlled by the checkbox in the "All settings" menu.
# setting names.
# Controlled by a checkbox in the settings menu.
show_technical_names (Show technical names) bool false
# Controlled by a checkbox in the settings menu.
show_advanced (Show advanced settings) bool false
# Enables the sound system.
# If disabled, this completely disables all sounds everywhere and the in-game
# sound controls will be non-functional.
# Changing this setting requires a restart.
enable_sound (Sound) bool true
# Unix timestamp (integer) of when the client last checked for an update
# Set this value to "disabled" to never check for updates.
update_last_checked (Last update check) string
# Version number which was last seen during an update check.
#
# Representation: MMMIIIPPP, where M=Major, I=Minor, P=Patch
# Ex: 5.5.0 is 005005000
update_last_known (Last known version update) int 0
# If this is set to true, the user will never (again) be shown the
# "reinstall Minetest Game" notification.
no_mtg_notification (Don't show "reinstall Minetest Game" notification) bool false
# Key for moving the player forward.
keymap_forward (Forward key) key KEY_KEY_W
@@ -2153,11 +2287,13 @@ keymap_jump (Jump key) key KEY_SPACE
# Also used for climbing down and descending in water if aux1_descends is disabled.
keymap_sneak (Sneak key) key KEY_LSHIFT
# Key for digging.
keymap_dig (Dig key) key KEY_LBUTTON
# Key for digging, punching or using something.
# (Note: The actual meaning might vary on a per-game basis.)
keymap_dig (Dig/punch/use key) key KEY_LBUTTON
# Key for placing.
keymap_place (Place key) key KEY_RBUTTON
# Key for placing an item/block or for using something.
# (Note: The actual meaning might vary on a per-game basis.)
keymap_place (Place/use key) key KEY_RBUTTON
# Key for opening the inventory.
keymap_inventory (Inventory key) key KEY_KEY_I

View File

@@ -0,0 +1,116 @@
#define rendered texture0
uniform sampler2D rendered;
uniform vec2 texelSize0;
varying vec2 sampleNW;
varying vec2 sampleNE;
varying vec2 sampleSW;
varying vec2 sampleSE;
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
/**
Basic FXAA implementation based on the code on geeks3d.com with the
modification that the texture2DLod stuff was removed since it's
unsupported by WebGL.
--
From:
https://github.com/mitsuhiko/webgl-meincraft
Copyright (c) 2011 by Armin Ronacher.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FXAA_REDUCE_MIN
#define FXAA_REDUCE_MIN (1.0/ 128.0)
#endif
#ifndef FXAA_REDUCE_MUL
#define FXAA_REDUCE_MUL (1.0 / 8.0)
#endif
#ifndef FXAA_SPAN_MAX
#define FXAA_SPAN_MAX 8.0
#endif
//optimized version for mobile, where dependent
//texture reads can be a bottleneck
vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 inverseVP,
vec2 v_rgbNW, vec2 v_rgbNE,
vec2 v_rgbSW, vec2 v_rgbSE,
vec2 v_rgbM) {
vec4 color;
vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;
vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;
vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;
vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;
vec4 texColor = texture2D(tex, v_rgbM);
vec3 rgbM = texColor.xyz;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
float lumaNE = dot(rgbNE, luma);
float lumaSW = dot(rgbSW, luma);
float lumaSE = dot(rgbSE, luma);
float lumaM = dot(rgbM, luma);
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
mediump vec2 dir;
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
(0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
dir * rcpDirMin)) * inverseVP;
vec3 rgbA = 0.5 * (
texture2D(tex, fragCoord + dir * (1.0 / 3.0 - 0.5)).xyz +
texture2D(tex, fragCoord + dir * (2.0 / 3.0 - 0.5)).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (
texture2D(tex, fragCoord + dir * -0.5).xyz +
texture2D(tex, fragCoord + dir * 0.5).xyz);
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax))
color = vec4(rgbA, 1.0);
else
color = vec4(rgbB, 1.0);
return color;
}
void main(void)
{
vec2 uv = varTexCoord.st;
gl_FragColor = fxaa(rendered, uv, texelSize0,
sampleNW, sampleNE, sampleSW, sampleSE, uv);
}

View File

@@ -0,0 +1,27 @@
uniform vec2 texelSize0;
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif
varying vec2 sampleNW;
varying vec2 sampleNE;
varying vec2 sampleSW;
varying vec2 sampleSE;
/*
Based on
https://github.com/mattdesl/glsl-fxaa/
Portions Copyright (c) 2011 by Armin Ronacher.
*/
void main(void)
{
varTexCoord.st = inTexCoord0.st;
sampleNW = varTexCoord.st + vec2(-1.0, -1.0) * texelSize0;
sampleNE = varTexCoord.st + vec2(1.0, -1.0) * texelSize0;
sampleSW = varTexCoord.st + vec2(-1.0, 1.0) * texelSize0;
sampleSE = varTexCoord.st + vec2(1.0, 1.0) * texelSize0;
gl_Position = inVertexPosition;
}

View File

@@ -3,6 +3,7 @@ uniform sampler2D baseTexture;
uniform vec3 dayLight;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform float fogShadingParameter;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
@@ -20,7 +21,7 @@ uniform float animationTimer;
uniform vec4 CameraPos;
uniform float xyPerspectiveBias0;
uniform float xyPerspectiveBias1;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
@@ -49,9 +50,6 @@ varying vec3 tsEyeVec;
varying vec3 lightVec;
varying vec3 tsLightVec;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
#ifdef ENABLE_DYNAMIC_SHADOWS
// assuming near is always 1.0

View File

@@ -3,6 +3,7 @@ uniform sampler2D baseTexture;
uniform vec3 dayLight;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform float fogShadingParameter;
uniform vec3 eyePosition;
// The cameraOffset is the current center of the visible world.
@@ -20,7 +21,7 @@ uniform float animationTimer;
uniform vec4 CameraPos;
uniform float xyPerspectiveBias0;
uniform float xyPerspectiveBias1;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
@@ -48,9 +49,6 @@ varying float nightRatio;
varying float vIDiff;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / (1.0 - fogStart);
#ifdef ENABLE_DYNAMIC_SHADOWS
// assuming near is always 1.0

View File

@@ -148,7 +148,7 @@ void main(void)
nNormal = normalize(vNormal);
cosLight = max(1e-5, dot(nNormal, -v_LightDirection));
float sinLight = pow(1 - pow(cosLight, 2.0), 0.5);
normalOffsetScale = 0.1 * pFactor * pFactor * sinLight * min(f_shadowfar, 500.0) /
normalOffsetScale = 0.1 * pFactor * pFactor * sinLight * min(f_shadowfar, 500.0) /
xyPerspectiveBias1 / f_textureresolution;
z_bias = 1e3 * sinLight / cosLight * (0.5 + f_textureresolution / 1024.0);
}

View File

@@ -8,6 +8,8 @@ struct ExposureParams {
uniform sampler2D rendered;
uniform sampler2D bloom;
uniform vec2 texelSize0;
uniform ExposureParams exposureParams;
uniform lowp float bloomIntensity;
uniform lowp float saturation;
@@ -80,7 +82,15 @@ vec3 applySaturation(vec3 color, float factor)
void main(void)
{
vec2 uv = varTexCoord.st;
#ifdef ENABLE_SSAA
vec4 color = vec4(0.);
for (float dx = 1.; dx < SSAA_SCALE; dx += 2.)
for (float dy = 1.; dy < SSAA_SCALE; dy += 2.)
color += texture2D(rendered, uv + texelSize0 * vec2(dx, dy)).rgba;
color /= SSAA_SCALE * SSAA_SCALE / 4.;
#else
vec4 color = texture2D(rendered, uv).rgba;
#endif
// translate to linear colorspace (approximate)
color.rgb = pow(color.rgb, vec3(2.2));

View File

@@ -0,0 +1,31 @@
set(DEPS "${CMAKE_SOURCE_DIR}/android/native/deps/${ANDROID_ABI}")
add_library(IrrlichtMt::IrrlichtMt STATIC IMPORTED)
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${DEPS}/Irrlicht/include)
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
IMPORTED_LOCATION ${DEPS}/Irrlicht/libIrrlichtMt.a)
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
INTERFACE_LINK_LIBRARIES "EGL;GLESv1_CM;GLESv2;${DEPS}/Irrlicht/libpng.a;${DEPS}/Irrlicht/libjpeg.a")
set(CURL_INCLUDE_DIR ${DEPS}/Curl/include)
set(CURL_LIBRARY ${DEPS}/Curl/libcurl.a;${DEPS}/Curl/libmbedcrypto.a;${DEPS}/Curl/libmbedtls.a;${DEPS}/Curl/libmbedx509.a)
set(FREETYPE_INCLUDE_DIR_ft2build ${DEPS}/Freetype/include/freetype2)
set(FREETYPE_INCLUDE_DIR_freetype2 ${FREETYPE_INCLUDE_DIR_ft2build}/freetype)
set(FREETYPE_LIBRARY ${DEPS}/Freetype/libfreetype.a)
set(GETTEXT_INCLUDE_DIR ${DEPS}/Gettext/include;${DEPS}/Iconv/include)
set(GETTEXT_LIBRARY ${DEPS}/Gettext/libintl.a)
set(ICONV_LIBRARY ${DEPS}/Iconv/libiconv.a;${DEPS}/Iconv/libcharset.a)
set(LUA_INCLUDE_DIR ${DEPS}/LuaJIT/include)
set(LUA_LIBRARY ${DEPS}/LuaJIT/libluajit.a)
set(OGG_INCLUDE_DIR ${DEPS}/Vorbis/include)
set(OGG_LIBRARY ${DEPS}/Vorbis/libogg.a)
set(OPENAL_INCLUDE_DIR ${DEPS}/OpenAL-Soft/include)
set(OPENAL_LIBRARY ${DEPS}/OpenAL-Soft/libopenal.a;OpenSLES)
set(SQLITE3_INCLUDE_DIR ${DEPS}/SQLite/include)
set(SQLITE3_LIBRARY ${DEPS}/SQLite/libsqlite3.a)
set(VORBIS_INCLUDE_DIR ${DEPS}/Vorbis/include)
set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a)
set(VORBIS_LIBRARY ${DEPS}/Vorbis/libvorbis.a)
set(ZSTD_INCLUDE_DIR ${DEPS}/Zstd/include)
set(ZSTD_LIBRARY ${DEPS}/Zstd/libzstd.a)

View File

@@ -1,81 +0,0 @@
Minetest: Android version
=========================
Controls
--------
The Android port doesn't support everything you can do on PC due to the
limited capabilities of common devices. What can be done is described
below:
While you're playing the game normally (that is, no menu or inventory is
shown), the following controls are available:
* Look around: touch screen and slide finger
* double tap: place a node or use selected item
* long tap: dig node
* touch shown buttons: press button
* Buttons:
** left upper corner: chat
** right lower corner: jump
** right lower corner: crouch
** left lower corner: walk/step...
left up right
down
** left lower corner: display inventory
When a menu or inventory is displayed:
* double tap outside menu area: close menu
* tap on an item stack: select that stack
* tap on an empty slot: if you selected a stack already, that stack is placed here
* drag and drop: touch stack and hold finger down, move the stack to another
slot, tap another finger while keeping first finger on screen
--> places a single item from dragged stack into current (first touched) slot
Special settings
----------------
There are some settings especially useful for Android users. Minetest's config
file can usually be found at /mnt/sdcard/Minetest.
* gui_scaling: this is a user-specified scaling factor for the GUI- In case
main menu is too big or small on your device, try changing this
value.
Requirements
------------
In order to build, your PC has to be set up to build Minetest in the usual
manner (see the regular Minetest documentation for how to get this done).
In addition to what is required for Minetest in general, you will need the
following software packages. The version number in parenthesis denotes the
version that was tested at the time this README was drafted; newer/older
versions may or may not work.
* Android SDK 29
* Android NDK r21
* Android Studio 3 [optional]
Additionally, you'll need to have an Internet connection available on the
build system, as the Android build will download some source packages.
Build
-----
The new build system Minetest Android is fully functional and is designed to
speed up and simplify the work, as well as adding the possibility of
cross-platform build.
You can use `./gradlew assemblerelease` or `./gradlew assembledebug` from the
command line or use Android Studio and click the build button.
When using gradlew, the newest NDK will be downloaded and installed
automatically. Or you can create a `local.properties` file and specify
`sdk.dir` and `ndk.dir` yourself.
* In order to make a release build you'll have to have a keystore setup to sign
the resulting apk package. How this is done is not part of this README. There
are different tutorials on the web explaining how to do it
- choose one yourself.
* Once your keystore is setup, enter the android subdirectory and create a new
file "ant.properties" there. Add following lines to that file:
> key.store=<path to your keystore>
> key.alias=Minetest

126
doc/android.md Normal file
View File

@@ -0,0 +1,126 @@
# Minetest Android build
All Minetest builds, including the Android variant, are based on the same code.
However, additional Java code is used for proper Android integration.
## Controls
Compared to Minetest binaries for PC, the Android port has limited functionality
due to limited capabilities of common devices. What can be done is described below:
While you're playing the game normally (that is, no menu or inventory is
shown), the following controls are available:
* Look around: touch screen and slide finger
* Tap: Place a node
* Long tap: Dig node or use the held item
* Press back: Pause menu
* Touch buttons: Press button
* Buttons:
1. Left upper corner: Chat
2. Right lower corner: Jump
3. Right lower corner: Crouch
4. Left lower corner (Joystick): Walk/step...
5. Left lower corner: Display inventory
When a menu or inventory is displayed:
* Double tap outside menu area: Close menu
* Press back: Close menu
* Tap on an item stack: Select that stack
* Tap on an empty slot: If a stack are selected already, that stack is placed here
* Drag and drop: Touch stack and hold finger down, move the stack to another
slot, tap another finger while keeping first finger on screen
--> places a single item from dragged stack into current (first touched) slot. If a stack is selected, the stack will be split as half and one of the splitted stack will be selected
### Limitations
* Some old Android device only support 2 touch at a time, some game/mod contain button combination that need 3 touch (example: jump + Aux1 + hold)
* Complicated control can be difficult or impossible on Android device
## File Path
There are some settings especially useful for Android users. The Minetest-wide
configuration file can usually be found at:
* Before 5.4.2:
* `/sdcard/Minetest/` or `/storage/emulated/0/` if stored on the device
* `/storage/emulated/(varying folder name)/` if stored on an SD card
* After 5.4.2:
* `/sdcard/Android/data/net.minetest.minetest/` or `/storage/emulated/0/Android/data/net.minetest.minetest/` if stored on the device
* `/storage/emulated/(varying folder name)/Android/data/net.minetest.minetest/` if stored on the SD card
* [Learn more about Android directory](https://wiki.minetest.net/Accessing_Android_Data_Directory)
## Useful settings
### gui_scaling
this is a user-specified scaling factor for the GUI in case main menu is too big or small on your device, try changing this value.
### mapblock_limit
Mobile device generally have less RAM than PC, this setting limit how many mapblock can keep in RAM
### fps_limit
this setting limit max FPS (Frame per second). Default value is 60, which lowest Android device screen refresh rate commonly found, but if you're using an device have lower refresh rate, change this
## Requirements
The minimal and recommended system requirements for Minetest are listed below.
### CPU
Supported architectures:
1. ARM v7
2. ARM v8
3. x86
4. x86_64
CPU architectures similar to ARM or x86 might run Minetest but are not tested.
### Minimum
1. Graphics API: OpenGL ES 1.0
* Shaders might not work correctly or work at all on OpenGL ES 1.0.
2. Android version: Android 4.1 (API Level 16)
3. Free RAM: 500 MB
4. Free storage: 100 MB
* More storage is highly recommended
### Recommended
1. Graphics API: OpenGL ES 2.0
2. Android version: Android 4.4 (API Level 19) or newer
3. Empty RAM: 850 MB
4. Free storage: 480 MB
## Rendering
Unlike on PC, Android devices use OpenGL ES which less powerful than OpenGL, thus
some shader settings cannot be used on OpenGL ES.
Changing the graphic driver setting to OpenGL will result in undesirable behavior.
## Building Requirements
In order to build, your PC has to be set up to build Minetest in the usual
manner (see the regular Minetest documentation for how to get this done).
In addition to what is required for Minetest in general, you will need the
following software packages. The version number in parenthesis denotes the
version that was tested at the time this README was drafted; newer/older
versions may or may not work.
* Android SDK 29
* Android NDK r21
* Android Studio 3 [optional]
Additionally, you'll need to have an Internet connection available on the
build system, as the Android build will download some source packages.
## Build
The new build system Minetest Android is fully functional and is designed to
speed up and simplify the work, as well as adding the possibility of
cross-platform build.
You can use `./gradlew assemblerelease` or `./gradlew assembledebug` from the
command line or use Android Studio and click the build button.
When using gradlew, the newest NDK will be downloaded and installed
automatically. Or you can create a `local.properties` file and specify
`sdk.dir` and `ndk.dir` yourself.
* In order to make a release build you'll have to have a keystore setup to sign
the resulting apk package. How this is done is not part of this README. There
are different tutorials on the web explaining how to do it
- choose one yourself.
* Once your keystore is setup, enter the android subdirectory and create a new
file "ant.properties" there. Add following lines to that file:
> key.store=<path to your keystore>
> key.alias=Minetest

View File

@@ -1,12 +1,23 @@
# Minetest Major Breakages List
This document contains a list of breaking changes to be made in the next major version.
This list is largely advisory and items may be reevaluated once the time comes.
* Remove attachment space multiplier (*10)
* Remove player gravity multiplier (*2)
* remove attachment space multiplier (*10)
* remove space multiplier for models (*10)
* remove player gravity multiplier (*2)
* `get_sky()` returns a table (without arg)
* `game.conf` name/id mess
* remove `depends.txt` / `description.txt` (would simplify ContentDB and Minetest code a little)
* rotate moon texture by 180°, making it coherent with the sun (see https://github.com/minetest/minetest/pull/11902)
* rotate moon texture by 180°, making it coherent with the sun
* https://github.com/minetest/minetest/pull/11902
* remove undocumented `set_physics_override(num, num, num)`
* remove special handling of `${key}` syntax in metadata values
* remove old_move
* change physics_override `sneak` to disable the speed change and not just the node clipping
* https://github.com/minetest/minetest/issues/13699
* 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
* merge `sound` and `sounds` table in itemdef
* remove `DIR_DELIM` from Lua
* stop reading initial properties from bare entity def

View File

@@ -1,4 +1,4 @@
Minetest Lua Client Modding API Reference 5.7.0
Minetest Lua Client Modding API Reference 5.8.1
================================================
* More information at <http://www.minetest.net/>
* Developer Wiki: <http://dev.minetest.net/>
@@ -170,26 +170,28 @@ from the available ones of the following files:
Examples of sound parameter tables:
-- Play locationless
{
gain = 1.0, -- default
}
-- Play locationless, looped
{
gain = 1.0, -- default
loop = true,
}
-- Play in a location
{
pos = {x = 1, y = 2, z = 3},
gain = 1.0, -- default
}
-- Play connected to an object, looped
{
object = <an ObjectRef>,
gain = 1.0, -- default
loop = true,
}
```lua
-- Play locationless
{
gain = 1.0, -- default
}
-- Play locationless, looped
{
gain = 1.0, -- default
loop = true,
}
-- Play in a location
{
pos = {x = 1, y = 2, z = 3},
gain = 1.0, -- default
}
-- Play connected to an object, looped
{
object = <an ObjectRef>,
gain = 1.0, -- default
loop = true,
}
```
Looped sounds must either be connected to an object or played locationless.
@@ -205,7 +207,9 @@ Representations of simple things
### Position/vector
{x=num, y=num, z=num}
```lua
{x=num, y=num, z=num}
```
For helper functions see "Vector helpers".
@@ -231,19 +235,27 @@ is present, mapped to a boolean of any value, the specified flag is unset.
E.g. A flag field of value
{place_center_x = true, place_center_y=false, place_center_z=true}
```lua
{place_center_x = true, place_center_y=false, place_center_z=true}
```
is equivalent to
{place_center_x = true, noplace_center_y=true, place_center_z=true}
```lua
{place_center_x = true, noplace_center_y=true, place_center_z=true}
```
which is equivalent to
"place_center_x, noplace_center_y, place_center_z"
```lua
"place_center_x, noplace_center_y, place_center_z"
```
or even
"place_center_x, place_center_z"
```lua
"place_center_x, place_center_z"
```
since, by default, no schematic attributes are set.
@@ -660,6 +672,9 @@ Minetest namespace reference
* If a flag in this table is set to true, the feature is RESTRICTED.
* Possible flags: `load_client_mods`, `chat_messages`, `read_itemdefs`,
`read_nodedefs`, `lookup_nodes`, `read_playerinfo`
* `minetest.urlencode(str)`: Encodes non-unreserved URI characters by a
percent sign followed by two hex digits. See
[RFC 3986, section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3).
### Logging
* `minetest.debug(...)`
@@ -742,9 +757,9 @@ Call these functions only at load time!
* `minetest.sound_play(spec, parameters)`: returns a handle
* `spec` is a `SimpleSoundSpec`
* `parameters` is a sound parameter table
* `minetest.sound_stop(handle)`
* `handle:stop()` or `minetest.sound_stop(handle)`
* `handle` is a handle returned by `minetest.sound_play`
* `minetest.sound_fade(handle, step, gain)`
* `handle:fade(step, gain)` or `minetest.sound_fade(handle, step, gain)`
* `handle` is a handle returned by `minetest.sound_play`
* `step` determines how fast a sound will fade.
Negative step will lower the sound volume, positive step will increase
@@ -947,7 +962,7 @@ Setting-related
---------------
* `minetest.settings`: Settings object containing all of the settings from the
main config file (`minetest.conf`). Check lua_api.txt for class reference.
main config file (`minetest.conf`). Check lua_api.md for class reference.
* `minetest.setting_get_pos(name)`: Loads a setting from the main settings and
parses it as a position (in the format `(1,2,3)`). Returns a position or nil.
@@ -996,14 +1011,14 @@ Please do not try to access the reference until the camera is initialized, other
* `get_fov()`
* Returns a table with X, Y, maximum and actual FOV in degrees:
```lua
{
x = number,
y = number,
max = number,
actual = number
}
```
```lua
{
x = number,
y = number,
max = number,
actual = number
}
```
* `get_pos()`
* Returns position of camera with view bobbing
@@ -1053,16 +1068,16 @@ Methods:
* `get_physics_override()`
* returns:
```lua
{
speed = float,
jump = float,
gravity = float,
sneak = boolean,
sneak_glitch = boolean,
new_move = boolean,
}
```
```lua
{
speed = float,
jump = float,
gravity = float,
sneak = boolean,
sneak_glitch = boolean,
new_move = boolean,
}
```
* `get_override_pos()`
* returns override position
@@ -1075,38 +1090,38 @@ Methods:
* `get_movement_acceleration()`
* returns acceleration of the player in different environments:
```lua
{
fast = float,
air = float,
default = float,
}
```
```lua
{
fast = float,
air = float,
default = float,
}
```
* `get_movement_speed()`
* returns player's speed in different environments:
```lua
{
walk = float,
jump = float,
crouch = float,
fast = float,
climb = float,
}
```
```lua
{
walk = float,
jump = float,
crouch = float,
fast = float,
climb = float,
}
```
* `get_movement()`
* returns player's movement in different environments:
```lua
{
liquid_fluidity = float,
liquid_sink = float,
liquid_fluidity_smooth = float,
gravity = float,
}
```
```lua
{
liquid_fluidity = float,
liquid_sink = float,
liquid_fluidity_smooth = float,
gravity = float,
}
```
* `get_last_look_horizontal()`:
* returns last look horizontal angle
@@ -1115,20 +1130,20 @@ Methods:
* `get_control()`:
* returns pressed player controls
```lua
{
up = boolean,
down = boolean,
left = boolean,
right = boolean,
jump = boolean,
aux1 = boolean,
sneak = boolean,
zoom = boolean,
dig = boolean,
place = boolean,
}
```
```lua
{
up = boolean,
down = boolean,
left = boolean,
right = boolean,
jump = boolean,
aux1 = boolean,
sneak = boolean,
zoom = boolean,
dig = boolean,
place = boolean,
}
```
* `get_armor_groups()`
* returns a table with the armor group ratings
@@ -1176,10 +1191,12 @@ Can be obtained via `minetest.get_meta(pos)`.
A raycast on the map. It works with selection boxes.
Can be used as an iterator in a for loop as:
local ray = Raycast(...)
for pointed_thing in ray do
...
end
```lua
local ray = Raycast(...)
for pointed_thing in ray do
...
end
```
The map is loaded as the ray advances. If the map is modified after the
`Raycast` is created, the changes may or may not have an effect on the object.
@@ -1207,97 +1224,100 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
#### Node Definition
```lua
{
has_on_construct = bool, -- Whether the node has the on_construct callback defined
has_on_destruct = bool, -- Whether the node has the on_destruct callback defined
has_after_destruct = bool, -- Whether the node has the after_destruct callback defined
name = string, -- The name of the node e.g. "air", "default:dirt"
groups = table, -- The groups of the node
paramtype = string, -- Paramtype of the node
paramtype2 = string, -- ParamType2 of the node
drawtype = string, -- Drawtype of the node
mesh = <string>, -- Mesh name if existent
minimap_color = <Color>, -- Color of node on minimap *May not exist*
visual_scale = number, -- Visual scale of node
alpha = number, -- Alpha of the node. Only used for liquids
color = <Color>, -- Color of node *May not exist*
palette_name = <string>, -- Filename of palette *May not exist*
palette = <{ -- List of colors
Color,
Color
}>,
waving = number, -- 0 of not waving, 1 if waving
connect_sides = number, -- Used for connected nodes
connects_to = { -- List of nodes to connect to
"node1",
"node2"
},
post_effect_color = Color, -- Color overlayed on the screen when the player is in the node
leveled = number, -- Max level for node
sunlight_propogates = bool, -- Whether light passes through the block
light_source = number, -- Light emitted by the block
is_ground_content = bool, -- Whether caves should cut through the node
walkable = bool, -- Whether the player collides with the node
pointable = bool, -- Whether the player can select the node
diggable = bool, -- Whether the player can dig the node
climbable = bool, -- Whether the player can climb up the node
buildable_to = bool, -- Whether the player can replace the node by placing a node on it
rightclickable = bool, -- Whether the player can place nodes pointing at this node
damage_per_second = number, -- HP of damage per second when the player is in the node
liquid_type = <string>, -- A string containing "none", "flowing", or "source" *May not exist*
liquid_alternative_flowing = <string>, -- Alternative node for liquid *May not exist*
liquid_alternative_source = <string>, -- Alternative node for liquid *May not exist*
liquid_viscosity = <number>, -- How slow the liquid flows *May not exist*
liquid_renewable = <boolean>, -- Whether the liquid makes an infinite source *May not exist*
liquid_range = <number>, -- How far the liquid flows *May not exist*
drowning = bool, -- Whether the player will drown in the node
floodable = bool, -- Whether nodes will be replaced by liquids (flooded)
node_box = table, -- Nodebox to draw the node with
collision_box = table, -- Nodebox to set the collision area
selection_box = table, -- Nodebox to set the area selected by the player
sounds = { -- Table of sounds that the block makes
sound_footstep = SimpleSoundSpec,
sound_dig = SimpleSoundSpec,
sound_dug = SimpleSoundSpec
},
legacy_facedir_simple = bool, -- Whether to use old facedir
legacy_wallmounted = bool -- Whether to use old wallmounted
move_resistance = <number>, -- How slow players can move through the node *May not exist*
}
{
has_on_construct = bool, -- Whether the node has the on_construct callback defined
has_on_destruct = bool, -- Whether the node has the on_destruct callback defined
has_after_destruct = bool, -- Whether the node has the after_destruct callback defined
name = string, -- The name of the node e.g. "air", "default:dirt"
groups = table, -- The groups of the node
paramtype = string, -- Paramtype of the node
paramtype2 = string, -- ParamType2 of the node
drawtype = string, -- Drawtype of the node
mesh = <string>, -- Mesh name if existent
minimap_color = <Color>, -- Color of node on minimap *May not exist*
visual_scale = number, -- Visual scale of node
alpha = number, -- Alpha of the node. Only used for liquids
color = <Color>, -- Color of node *May not exist*
palette_name = <string>, -- Filename of palette *May not exist*
palette = <{ -- List of colors
Color,
Color
}>,
waving = number, -- 0 of not waving, 1 if waving
connect_sides = number, -- Used for connected nodes
connects_to = { -- List of nodes to connect to
"node1",
"node2"
},
post_effect_color = Color, -- Color overlayed on the screen when the player is in the node
leveled = number, -- Max level for node
sunlight_propogates = bool, -- Whether light passes through the block
light_source = number, -- Light emitted by the block
is_ground_content = bool, -- Whether caves should cut through the node
walkable = bool, -- Whether the player collides with the node
pointable = bool, -- Whether the player can select the node
diggable = bool, -- Whether the player can dig the node
climbable = bool, -- Whether the player can climb up the node
buildable_to = bool, -- Whether the player can replace the node by placing a node on it
rightclickable = bool, -- Whether the player can place nodes pointing at this node
damage_per_second = number, -- HP of damage per second when the player is in the node
liquid_type = <string>, -- A string containing "none", "flowing", or "source" *May not exist*
liquid_alternative_flowing = <string>, -- Alternative node for liquid *May not exist*
liquid_alternative_source = <string>, -- Alternative node for liquid *May not exist*
liquid_viscosity = <number>, -- How slow the liquid flows *May not exist*
liquid_renewable = <boolean>, -- Whether the liquid makes an infinite source *May not exist*
liquid_range = <number>, -- How far the liquid flows *May not exist*
drowning = bool, -- Whether the player will drown in the node
floodable = bool, -- Whether nodes will be replaced by liquids (flooded)
node_box = table, -- Nodebox to draw the node with
collision_box = table, -- Nodebox to set the collision area
selection_box = table, -- Nodebox to set the area selected by the player
sounds = { -- Table of sounds that the block makes
sound_footstep = SimpleSoundSpec,
sound_dig = SimpleSoundSpec,
sound_dug = SimpleSoundSpec
},
legacy_facedir_simple = bool, -- Whether to use old facedir
legacy_wallmounted = bool -- Whether to use old wallmounted
move_resistance = <number>, -- How slow players can move through the node *May not exist*
}
```
#### Item Definition
```lua
{
name = string, -- Name of the item e.g. "default:stone"
description = string, -- Description of the item e.g. "Stone"
type = string, -- Item type: "none", "node", "craftitem", "tool"
inventory_image = string, -- Image in the inventory
wield_image = string, -- Image in wieldmesh
palette_image = string, -- Image for palette
color = Color, -- Color for item
wield_scale = Vector, -- Wieldmesh scale
stack_max = number, -- Number of items stackable together
usable = bool, -- Has on_use callback defined
liquids_pointable = bool, -- Whether you can point at liquids with the item
tool_capabilities = <table>, -- If the item is a tool, tool capabilities of the item
groups = table, -- Groups of the item
sound_place = SimpleSoundSpec, -- Sound played when placed
sound_place_failed = SimpleSoundSpec, -- Sound played when placement failed
node_placement_prediction = string -- Node placed in client until server catches up
}
{
name = string, -- Name of the item e.g. "default:stone"
description = string, -- Description of the item e.g. "Stone"
type = string, -- Item type: "none", "node", "craftitem", "tool"
inventory_image = string, -- Image in the inventory
wield_image = string, -- Image in wieldmesh
palette_image = string, -- Image for palette
color = Color, -- Color for item
wield_scale = Vector, -- Wieldmesh scale
stack_max = number, -- Number of items stackable together
usable = bool, -- Has on_use callback defined
liquids_pointable = bool, -- Whether you can point at liquids with the item
tool_capabilities = <table>, -- If the item is a tool, tool capabilities of the item
groups = table, -- Groups of the item
sound_place = SimpleSoundSpec, -- Sound played when placed
sound_place_failed = SimpleSoundSpec, -- Sound played when placement failed
node_placement_prediction = string -- Node placed in client until server catches up
}
```
-----------------
### Chat command definition (`register_chatcommand`)
{
params = "<name> <privilege>", -- Short parameter description
description = "Remove privilege from player", -- Full description
func = function(param), -- Called when command is run.
-- Returns boolean success and text output.
}
```lua
{
params = "<name> <privilege>", -- Short parameter description
description = "Remove privilege from player", -- Full description
func = function(param), -- Called when command is run.
-- Returns boolean success and text output.
}
```
### Server info
```lua
{
@@ -1309,29 +1329,30 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or
```
### HUD Definition (`hud_add`, `hud_get`)
```lua
{
hud_elem_type = "image", -- see HUD element types, default "text"
-- ^ type of HUD element, can be either of "image", "text", "statbar", or "inventory"
position = {x=0.5, y=0.5},
-- ^ Left corner position of element, default `{x=0,y=0}`.
name = "<name>", -- default ""
scale = {x=2, y=2}, -- default {x=0,y=0}
text = "<text>", -- default ""
number = 2, -- default 0
item = 3, -- default 0
-- ^ Selected item in inventory. 0 for no item selected.
direction = 0, -- default 0
-- ^ Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
alignment = {x=0, y=0}, -- default {x=0, y=0}
-- ^ See "HUD Element Types"
offset = {x=0, y=0}, -- default {x=0, y=0}
-- ^ See "HUD Element Types"
size = { x=100, y=100 }, -- default {x=0, y=0}
-- ^ Size of element in pixels
style = 0,
-- ^ For "text" elements sets font style: bitfield with 1 = bold, 2 = italic, 4 = monospace
}
{
hud_elem_type = "image", -- see HUD element types, default "text"
-- ^ type of HUD element, can be either of "image", "text", "statbar", or "inventory"
position = {x=0.5, y=0.5},
-- ^ Left corner position of element, default `{x=0,y=0}`.
name = "<name>", -- default ""
scale = {x=2, y=2}, -- default {x=0,y=0}
text = "<text>", -- default ""
number = 2, -- default 0
item = 3, -- default 0
-- ^ Selected item in inventory. 0 for no item selected.
direction = 0, -- default 0
-- ^ Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
alignment = {x=0, y=0}, -- default {x=0, y=0}
-- ^ See "HUD Element Types"
offset = {x=0, y=0}, -- default {x=0, y=0}
-- ^ See "HUD Element Types"
size = { x=100, y=100 }, -- default {x=0, y=0}
-- ^ Size of element in pixels
style = 0,
-- ^ For "text" elements sets font style: bitfield with 1 = bold, 2 = italic, 4 = monospace
}
```
Escape sequences
@@ -1478,55 +1499,59 @@ Same as `image`, but does not accept a `position`; the position is instead deter
### Particle definition (`add_particle`)
{
pos = {x=0, y=0, z=0},
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
```lua
{
pos = {x=0, y=0, z=0},
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
-- ^ Spawn particle at pos with velocity and acceleration
expirationtime = 1,
expirationtime = 1,
-- ^ Disappears after expirationtime seconds
size = 1,
collisiondetection = false,
size = 1,
collisiondetection = false,
-- ^ collisiondetection: if true collides with physical objects
collision_removal = false,
collision_removal = false,
-- ^ collision_removal: if true then particle is removed when it collides,
-- ^ requires collisiondetection = true to have any effect
vertical = false,
vertical = false,
-- ^ vertical: if true faces player using y axis only
texture = "image.png",
texture = "image.png",
-- ^ Uses texture (string)
animation = {Tile Animation definition},
animation = {Tile Animation definition},
-- ^ optional, specifies how to animate the particle texture
glow = 0
glow = 0
-- ^ optional, specify particle self-luminescence in darkness
}
}
```
### `ParticleSpawner` definition (`add_particlespawner`)
{
amount = 1,
time = 1,
```lua
{
amount = 1,
time = 1,
-- ^ If time is 0 has infinite lifespan and spawns the amount on a per-second base
minpos = {x=0, y=0, z=0},
maxpos = {x=0, y=0, z=0},
minvel = {x=0, y=0, z=0},
maxvel = {x=0, y=0, z=0},
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1,
maxexptime = 1,
minsize = 1,
maxsize = 1,
minpos = {x=0, y=0, z=0},
maxpos = {x=0, y=0, z=0},
minvel = {x=0, y=0, z=0},
maxvel = {x=0, y=0, z=0},
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1,
maxexptime = 1,
minsize = 1,
maxsize = 1,
-- ^ The particle's properties are random values in between the bounds:
-- ^ minpos/maxpos, minvel/maxvel (velocity), minacc/maxacc (acceleration),
-- ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
collisiondetection = false,
collisiondetection = false,
-- ^ collisiondetection: if true uses collision detection
collision_removal = false,
collision_removal = false,
-- ^ collision_removal: if true then particle is removed when it collides,
-- ^ requires collisiondetection = true to have any effect
vertical = false,
vertical = false,
-- ^ vertical: if true faces player using y axis only
texture = "image.png",
texture = "image.png",
-- ^ Uses texture (string)
}
}
```

88
doc/compiling/README.md Normal file
View File

@@ -0,0 +1,88 @@
# Compiling Minetest
- [Compiling on GNU/Linux](linux.md)
- [Compiling on Windows](windows.md)
- [Compiling on MacOS](macos.md)
## CMake options
General options and their default values:
BUILD_CLIENT=TRUE - Build Minetest client
BUILD_SERVER=FALSE - Build Minetest server
BUILD_UNITTESTS=TRUE - Build unittest sources
BUILD_BENCHMARKS=FALSE - Build benchmark sources
BUILD_DOCUMENTATION=TRUE - Build doxygen documentation
CMAKE_BUILD_TYPE=Release - Type of build (Release vs. Debug)
Release - Release build
Debug - Debug build
SemiDebug - Partially optimized debug build
RelWithDebInfo - Release build with debug information
MinSizeRel - Release build with -Os passed to compiler to make executable as small as possible
ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http
ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations
ENABLE_LEVELDB=ON - Build with LevelDB; Enables use of LevelDB map backend
ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended)
ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend
ENABLE_SPATIAL=ON - Build with LibSpatial; Speeds up AreaStores
ENABLE_SOUND=ON - Build with OpenAL, libogg & libvorbis; in-game sounds
ENABLE_LTO=ON - Build with IPO/LTO optimizations (smaller and more efficient than regular build)
ENABLE_LUAJIT=ON - Build with LuaJIT (much faster than non-JIT Lua)
ENABLE_PROMETHEUS=OFF - Build with Prometheus metrics exporter (listens on tcp/30000 by default)
ENABLE_SYSTEM_GMP=ON - Use GMP from system (much faster than bundled mini-gmp)
ENABLE_SYSTEM_JSONCPP=ON - Use JsonCPP from system
RUN_IN_PLACE=FALSE - Create a portable install (worlds, settings etc. in current directory)
ENABLE_UPDATE_CHECKER=TRUE - Whether to enable update checks by default
INSTALL_DEVTEST=FALSE - Whether the Development Test game should be installed alongside Minetest
USE_GPROF=FALSE - Enable profiling using GProf
VERSION_EXTRA= - Text to append to version (e.g. VERSION_EXTRA=foobar -> Minetest 0.4.9-foobar)
ENABLE_TOUCH=FALSE - Enable Touchscreen support (requires support by IrrlichtMt)
Library specific options:
CURL_DLL - Only if building with cURL on Windows; path to libcurl.dll
CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located
CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib
EXTRA_DLL - Only on Windows; optional paths to additional DLLs that should be packaged
FREETYPE_INCLUDE_DIR_freetype2 - Directory that contains files such as ftimage.h
FREETYPE_INCLUDE_DIR_ft2build - Directory that contains ft2build.h
FREETYPE_LIBRARY - Path to libfreetype.a/libfreetype.so/freetype.lib
FREETYPE_DLL - Only on Windows; path to libfreetype-6.dll
GETTEXT_DLL - Only when building with gettext on Windows; paths to libintl + libiconv DLLs
GETTEXT_INCLUDE_DIR - Only when building with gettext; directory that contains libintl.h
GETTEXT_LIBRARY - Optional/platform-dependent with gettext; path to libintl.so/libintl.dll.a
GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe
ICONV_LIBRARY - Optional/platform-dependent; path to libiconv.so/libiconv.dylib
IRRLICHT_DLL - Only on Windows; path to IrrlichtMt.dll
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h (usable for server build only)
LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h
LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll
PostgreSQL_INCLUDE_DIR - Only when building with PostgreSQL; directory that contains libpq-fe.h
PostgreSQL_LIBRARY - Only when building with PostgreSQL; path to libpq.a/libpq.so/libpq.lib
REDIS_INCLUDE_DIR - Only when building with Redis; directory that contains hiredis.h
REDIS_LIBRARY - Only when building with Redis; path to libhiredis.a/libhiredis.so
SPATIAL_INCLUDE_DIR - Only when building with LibSpatial; directory that contains spatialindex/SpatialIndex.h
SPATIAL_LIBRARY - Only when building with LibSpatial; path to libspatialindex.so/spatialindex-32.lib
LUA_INCLUDE_DIR - Only if you want to use LuaJIT; directory where luajit.h is located
LUA_LIBRARY - Only if you want to use LuaJIT; path to libluajit.a/libluajit.so
OGG_DLL - Only if building with sound on Windows; path to libogg.dll
OGG_INCLUDE_DIR - Only if building with sound; directory that contains an ogg directory which contains ogg.h
OGG_LIBRARY - Only if building with sound; path to libogg.a/libogg.so/libogg.dll.a
OPENAL_DLL - Only if building with sound on Windows; path to OpenAL32.dll
OPENAL_INCLUDE_DIR - Only if building with sound; directory where al.h is located
OPENAL_LIBRARY - Only if building with sound; path to libopenal.a/libopenal.so/OpenAL32.lib
SQLITE3_INCLUDE_DIR - Directory that contains sqlite3.h
SQLITE3_LIBRARY - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib
VORBISFILE_LIBRARY - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a
VORBIS_DLL - Only if building with sound on Windows; paths to vorbis DLLs
VORBIS_INCLUDE_DIR - Only if building with sound; directory that contains a directory vorbis with vorbisenc.h inside
VORBIS_LIBRARY - Only if building with sound; path to libvorbis.a/libvorbis.so/libvorbis.dll.a
ZLIB_DLL - Only on Windows; path to zlib1.dll
ZLIB_INCLUDE_DIR - Directory that contains zlib.h
ZLIB_LIBRARY - Path to libz.a/libz.so/zlib.lib
ZSTD_DLL - Only on Windows; path to libzstd.dll
ZSTD_INCLUDE_DIR - Directory that contains zstd.h
ZSTD_LIBRARY - Path to libzstd.a/libzstd.so/ztd.lib

116
doc/compiling/linux.md Normal file
View File

@@ -0,0 +1,116 @@
# Compiling on GNU/Linux
## Dependencies
| Dependency | Version | Commentary |
| ---------- | ------- | ---------- |
| GCC | 7.5+ | or Clang 7.0.1+ |
| CMake | 3.5+ | |
| IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
| Freetype | 2.0+ | |
| SQLite3 | 3+ | |
| Zstd | 1.0+ | |
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present |
| Curl | 7.56.0+ | Optional |
| gettext | - | Optional |
For Debian/Ubuntu users:
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext
For Fedora users:
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext
For openSUSE users:
sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel
For Arch users:
sudo pacman -S base-devel libcurl-gnutls cmake libxi libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext
For Alpine users:
sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext
For Void users:
sudo xbps-install cmake libpng-devel jpeg-devel libXi-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel libzstd-devel gettext
## Download
You can install Git for easily keeping your copy up to date.
If you dont want Git, read below on how to get the source without Git.
This is an example for installing Git on Debian/Ubuntu:
sudo apt install git
For Fedora users:
sudo dnf install git
For Arch users:
sudo pacman -S git
For Alpine users:
sudo apk add git
For Void users:
sudo xbps-install 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
cd minetest
Download IrrlichtMt to `lib/irrlichtmt`, it will be used to satisfy the IrrlichtMt dependency that way:
git clone --depth 1 https://github.com/minetest/irrlicht.git lib/irrlichtmt
Download source, without using Git:
wget https://github.com/minetest/minetest/archive/master.tar.gz
tar xf master.tar.gz
cd minetest-master
Download IrrlichtMt, without using Git:
cd lib/
wget https://github.com/minetest/irrlicht/archive/master.tar.gz
tar xf master.tar.gz
mv irrlicht-master irrlichtmt
cd ..
## Build
Build a version that runs directly from the source directory:
cmake . -DRUN_IN_PLACE=TRUE
make -j$(nproc)
Run it:
./bin/minetest
- 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),
you will want to use `-DRUN_IN_PLACE=FALSE`.
- You can build a bare server by specifying `-DBUILD_SERVER=TRUE`.
- You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`.
- You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`.
- Debug build is slower, but gives much more useful output in a debugger.
- If you build a bare server you don't need to compile IrrlichtMt, just the headers suffice.
- In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlichtmt/include`.
- Minetest will use the IrrlichtMt package that is found first, given by the following order:
1. Specified `IRRLICHTMT_BUILD_DIR` CMake variable
2. `${PROJECT_SOURCE_DIR}/lib/irrlichtmt` (if existent)
3. Installation of IrrlichtMt in the system-specific library paths
4. For server builds with disabled `BUILD_CLIENT` variable, the headers from `IRRLICHT_INCLUDE_DIR` will be used.
- NOTE: Changing the IrrlichtMt build directory (includes system installs) requires regenerating the CMake cache (`rm CMakeCache.txt`)

49
doc/compiling/macos.md Normal file
View File

@@ -0,0 +1,49 @@
# Compiling on MacOS
## Requirements
- [Homebrew](https://brew.sh/)
- [Git](https://git-scm.com/downloads)
Install dependencies with homebrew:
```
brew install cmake freetype gettext gmp hiredis jpeg jsoncpp leveldb libogg libpng libvorbis luajit zstd gettext
```
## Download
Download source (this is the URL to the latest of source repository, which might not work at all times) using Git:
```bash
git clone --depth 1 https://github.com/minetest/minetest.git
cd minetest
```
Download Minetest's fork of Irrlicht:
```
git clone --depth 1 https://github.com/minetest/irrlicht.git lib/irrlichtmt
```
## Build
```bash
mkdir build
cd build
cmake .. \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14 \
-DCMAKE_FIND_FRAMEWORK=LAST \
-DCMAKE_INSTALL_PREFIX=../build/macos/ \
-DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE
make -j$(sysctl -n hw.logicalcpu)
make install
```
## Run
```
open ./build/macos/minetest.app
```

73
doc/compiling/windows.md Normal file
View File

@@ -0,0 +1,73 @@
# Compiling on Windows using MSVC
## Requirements
- [Visual Studio 2015 or newer](https://visualstudio.microsoft.com)
- [CMake](https://cmake.org/download/)
- [vcpkg](https://github.com/Microsoft/vcpkg)
- [Git](https://git-scm.com/downloads)
## Compiling and installing the dependencies
It is highly recommended to use vcpkg as package manager.
After you successfully built vcpkg you can easily install the required libraries:
```powershell
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry gettext --triplet x64-windows
```
- **Don't forget about IrrlichtMt.** The easiest way is to clone it to `lib/irrlichtmt` as described in the Linux section.
- `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store.
- `openal-soft`, `libvorbis` and `libogg` are optional, but required to use sound.
- `luajit` is optional, it replaces the integrated Lua interpreter with a faster just-in-time interpreter.
- `gmp` and `jsoncpp` are optional, otherwise the bundled versions will be compiled
- `gettext` is optional, but required to use translations.
There are other optional libraries, but they are not tested if they can build and link correctly.
Use `--triplet` to specify the target triplet, e.g. `x64-windows` or `x86-windows`.
## Compile Minetest
### a) Using the vcpkg toolchain and CMake GUI
1. Start up the CMake GUI
2. Select **Browse Source...** and select DIR/minetest
3. Select **Browse Build...** and select DIR/minetest-build
4. Select **Configure**
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**
7. Click **Next**
8. Select the vcpkg toolchain file e.g. `D:/vcpkg/scripts/buildsystems/vcpkg.cmake`
9. Click Finish
10. Wait until cmake have generated the cash file
11. If there are any errors, solve them and hit **Configure**
12. Click **Generate**
13. Click **Open Project**
14. Compile Minetest inside Visual studio.
### b) Using the vcpkg toolchain and the commandline
Run the following script in PowerShell:
```powershell
cmake . -G"Visual Studio 15 2017 Win64" -DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_GETTEXT=OFF -DENABLE_CURSES=OFF
cmake --build . --config Release
```
Make sure that the right compiler is selected and the path to the vcpkg toolchain is correct.
## Windows Installer using WiX Toolset
Requirements:
* [Visual Studio 2017](https://visualstudio.microsoft.com/)
* [WiX Toolset](https://wixtoolset.org/)
In the Visual Studio 2017 Installer select **Optional Features -> WiX Toolset**.
Build the binaries as described above, but make sure you unselect `RUN_IN_PLACE`.
Open the generated project file with Visual Studio. Right-click **Package** and choose **Generate**.
It may take some minutes to generate the installer.

25
doc/developing/docker.md Normal file
View File

@@ -0,0 +1,25 @@
# Developing minetestserver with Docker
Docker provides an easy cross-platform solution to create a development environment. The advantage of this method is that it does not require you to install any development tools and libraries on your machine besides git and docker. This is a short guide describing how to set up a development environment for minetestserver; people unfamiliar with docker may also want to refer to the [Docker Documentation](https://docs.docker.com//) which is well written.
## Creating an image
The first step is to create a development image of minetestserver:
```bash
docker buildx build --target dev -t minetest-dev:0 .
```
The `--target dev` option instructs docker to build the intermediate development image, and the `-t minetest-dev:0` option tags the image so we can refer to it by that name.
## Opening a new container
Once an image has been created, a new container can be opened, with the source code mounted into it:
```bash
docker run -it \
--mount type=bind,source=/home/bob/minetest,target=/minetest \
minetest-dev:0
```
The `-it` runs the container interactively and puts you into a terminal in the container. The source and target of the bind mount should point to the directory on the host machine, and the directory in the container, respectively.
### For VSCode users
If you install the development container extension from the VSCode marketplace, you can attach VSCode to the running container, and open the source in VSCode to work with it as you would any other project. Note that extensions must be installed in the container from the extensions tab once the container has been attached if you wish to use them. For more information, see the VSCode documentation on [Developing inside a Container using Visual Studio Code Remote Development](https://code.visualstudio.com/docs/devcontainers/containers#:~:text=The%20Visual%20Studio%20Code%20Dev%20Containers%20extension%20lets,advantage%20of%20Visual%20Studio%20Code%27s%20full%20feature%20set.).

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