Compare commits
512 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ad81c1ce3 | ||
|
|
25b1cca415 | ||
|
|
767b2e7b17 | ||
|
|
2902a29c2d | ||
|
|
829426c714 | ||
|
|
8e1d78e9de | ||
|
|
4b31a38ae9 | ||
|
|
bf9f50bc0e | ||
|
|
3aa28bc7a2 | ||
|
|
a5377251e2 | ||
|
|
a58b47d0f6 | ||
|
|
7ae0b90ff7 | ||
|
|
a50db0e824 | ||
|
|
e1f9ba435f | ||
|
|
ba8fa0bd42 | ||
|
|
1ed90c90c3 | ||
|
|
49cec3f782 | ||
|
|
38d112033b | ||
|
|
54dbd78f90 | ||
|
|
c9ac9992c7 | ||
|
|
3946d2a504 | ||
|
|
5fd92d67d5 | ||
|
|
c120ea57c9 | ||
|
|
848f80b2e5 | ||
|
|
e9e9fd7c3f | ||
|
|
9772322613 | ||
|
|
7a4c1e7327 | ||
|
|
15c316765d | ||
|
|
c3708b456e | ||
|
|
83853ccd41 | ||
|
|
e275b7099a | ||
|
|
0d990bd189 | ||
|
|
b03135548b | ||
|
|
0a903e69fb | ||
|
|
0404bbf671 | ||
|
|
0ea3e6dbe2 | ||
|
|
67bf7130ce | ||
|
|
d9ef072305 | ||
|
|
33de69a173 | ||
|
|
76036abdb0 | ||
|
|
4ccaa6d0af | ||
|
|
dfd1f87762 | ||
|
|
6c4a8766ab | ||
|
|
dae03382bf | ||
|
|
50b0e9f7a4 | ||
|
|
206565d965 | ||
|
|
3cc45fd8ad | ||
|
|
83cc882335 | ||
|
|
bbae8eb751 | ||
|
|
a0dce51af6 | ||
|
|
96f753a108 | ||
|
|
e15681080e | ||
|
|
35f88ac67c | ||
|
|
22dbbf0a6f | ||
|
|
000da6b25d | ||
|
|
e51ad5337f | ||
|
|
15be2659ea | ||
|
|
d9de9f23d9 | ||
|
|
2330267d22 | ||
|
|
60113bde74 | ||
|
|
1309e52198 | ||
|
|
5004f31575 | ||
|
|
6cbd1b8bf7 | ||
|
|
6fa3892a71 | ||
|
|
04e9a9d541 | ||
|
|
f3439c40d8 | ||
|
|
20e3d550fa | ||
|
|
de0cdbc01c | ||
|
|
e605d70256 | ||
|
|
4696c59a5f | ||
|
|
4594ba6522 | ||
|
|
06baf05c64 | ||
|
|
d879a539cd | ||
|
|
752e11e114 | ||
|
|
9a927476ca | ||
|
|
ff7d7080e3 | ||
|
|
769b2d7c05 | ||
|
|
5be786c804 | ||
|
|
747bc40840 | ||
|
|
d19a69cd0d | ||
|
|
d02ce1cf4d | ||
|
|
2e66aca357 | ||
|
|
b08d7558de | ||
|
|
ff25218374 | ||
|
|
7433d65d3e | ||
|
|
1fd9a11e30 | ||
|
|
4f246f0e22 | ||
|
|
f87c1c2410 | ||
|
|
122875c30c | ||
|
|
068dd796f5 | ||
|
|
16bd368374 | ||
|
|
83f1d9ae6b | ||
|
|
374e68d205 | ||
|
|
fb150e0504 | ||
|
|
c439bdd4e5 | ||
|
|
d661cb320d | ||
|
|
78f1fcf450 | ||
|
|
28c21ed566 | ||
|
|
d7b0fcb2f0 | ||
|
|
e5b1447d72 | ||
|
|
dfc268d88b | ||
|
|
8c3cf606a6 | ||
|
|
c28810f6df | ||
|
|
012551f16f | ||
|
|
4d165f5ea5 | ||
|
|
71cc575ea0 | ||
|
|
e023e7228e | ||
|
|
80981f80f3 | ||
|
|
ab601e8710 | ||
|
|
ee0b8da844 | ||
|
|
6f851c9692 | ||
|
|
e52d811110 | ||
|
|
5323d800cc | ||
|
|
98e4e2b373 | ||
|
|
b38afc9311 | ||
|
|
0c8bf7cf94 | ||
|
|
0930911efa | ||
|
|
86ef7147b6 | ||
|
|
a55c073ce9 | ||
|
|
21789ccc5f | ||
|
|
b2d9205796 | ||
|
|
eadc943159 | ||
|
|
dc407e219f | ||
|
|
d419e4cbb6 | ||
|
|
aa172bdda4 | ||
|
|
a439aea9ba | ||
|
|
367b5382a3 | ||
|
|
a92fc3563c | ||
|
|
533785ec9a | ||
|
|
3985c01ad7 | ||
|
|
cca4f09ba1 | ||
|
|
e396fb2984 | ||
|
|
90e7832408 | ||
|
|
35606cfb67 | ||
|
|
371b39a09a | ||
|
|
3f519eb729 | ||
|
|
9a750450ed | ||
|
|
5094a39f05 | ||
|
|
a935d81053 | ||
|
|
bb54e2cf1d | ||
|
|
22a59b3912 | ||
|
|
0f9440fa61 | ||
|
|
d75b1718f8 | ||
|
|
a92e90f684 | ||
|
|
b401e58c0d | ||
|
|
0aeecf3f7f | ||
|
|
b6bb3ffec4 | ||
|
|
7bd30b59ee | ||
|
|
1afd359550 | ||
|
|
1d856b734b | ||
|
|
3d63492f50 | ||
|
|
8ad052881c | ||
|
|
d886f34003 | ||
|
|
8903c68460 | ||
|
|
6f44492238 | ||
|
|
2e89209cf1 | ||
|
|
e46c527733 | ||
|
|
1a96987d0f | ||
|
|
7be18657b1 | ||
|
|
cf0786dc9d | ||
|
|
4a8a50a2a2 | ||
|
|
0fd29b7e09 | ||
|
|
4c2687775f | ||
|
|
50ea8601d5 | ||
|
|
68bbdf1b2c | ||
|
|
5fbc39a76c | ||
|
|
25edae00ea | ||
|
|
0b78889289 | ||
|
|
06a5eceb81 | ||
|
|
2636c92075 | ||
|
|
d11c76b9f2 | ||
|
|
0d35350b69 | ||
|
|
2bf9abade2 | ||
|
|
69a59f1e41 | ||
|
|
b1c82f332c | ||
|
|
fba2650e39 | ||
|
|
1cbba877ff | ||
|
|
53ab2f8def | ||
|
|
bd6d4666ab | ||
|
|
2f10cfb226 | ||
|
|
8bc68645cb | ||
|
|
6e17503208 | ||
|
|
382357d61c | ||
|
|
a924409bd1 | ||
|
|
e232f7311f | ||
|
|
12504a18ec | ||
|
|
b3591019ad | ||
|
|
34e0a0ca0f | ||
|
|
4e5760a541 | ||
|
|
19742d8d98 | ||
|
|
f86cdf0960 | ||
|
|
ee9f4f11a3 | ||
|
|
919ffd9d36 | ||
|
|
406bed1164 | ||
|
|
d0ddcecbe5 | ||
|
|
25304b53a1 | ||
|
|
14e562e92b | ||
|
|
b3ad0f1ed4 | ||
|
|
5f3806c93c | ||
|
|
5598f3c81b | ||
|
|
afb27329fc | ||
|
|
2170c9958a | ||
|
|
2134316c80 | ||
|
|
a9c0961e0c | ||
|
|
731392866f | ||
|
|
5dce44ec5e | ||
|
|
f0edd88dff | ||
|
|
8bc7ea61b9 | ||
|
|
372d638ec1 | ||
|
|
4ea0e4f606 | ||
|
|
fb6a789991 | ||
|
|
9e6bdc377f | ||
|
|
27947d85f7 | ||
|
|
f7ee5da4c1 | ||
|
|
c0398224ef | ||
|
|
9bccd75e34 | ||
|
|
c9eb17aba3 | ||
|
|
cfe6eaa66b | ||
|
|
62bc5331aa | ||
|
|
4c704fe306 | ||
|
|
d308352dbd | ||
|
|
3c4734d69a | ||
|
|
da9fe64851 | ||
|
|
4feea0ac68 | ||
|
|
681e136d5f | ||
|
|
e0f9f15d1d | ||
|
|
214da7bef9 | ||
|
|
dd5c451e03 | ||
|
|
d820a6bfd8 | ||
|
|
10a38a3005 | ||
|
|
c6e3797c1a | ||
|
|
168fa2ffe0 | ||
|
|
6fb4a78d71 | ||
|
|
217b66e5d2 | ||
|
|
95e4a93b1b | ||
|
|
3725179736 | ||
|
|
1f3402e7a1 | ||
|
|
49a75b1894 | ||
|
|
321ac66558 | ||
|
|
d423a8fc20 | ||
|
|
f1e4a671dc | ||
|
|
1cc1c56234 | ||
|
|
7e44c2ace1 | ||
|
|
58841ef12f | ||
|
|
71a8769bb5 | ||
|
|
6de16bb438 | ||
|
|
6291fd1cbb | ||
|
|
4a2203413f | ||
|
|
0be633a61d | ||
|
|
2963f631e3 | ||
|
|
df3a5a2abf | ||
|
|
211b372e26 | ||
|
|
8489980039 | ||
|
|
7935044820 | ||
|
|
e8b9467905 | ||
|
|
7860097eda | ||
|
|
5b518ed2fe | ||
|
|
af490330e7 | ||
|
|
1ad9365d34 | ||
|
|
e61b1773c9 | ||
|
|
1ecf51a13f | ||
|
|
71a6ffa762 | ||
|
|
5d0f19fd7d | ||
|
|
a0ef75d32d | ||
|
|
fd6e7cef92 | ||
|
|
d01d9217dd | ||
|
|
1751fdf937 | ||
|
|
7766420cf4 | ||
|
|
e69764a6f3 | ||
|
|
525483c500 | ||
|
|
18bf767014 | ||
|
|
cfaa9b3be5 | ||
|
|
902d5927f0 | ||
|
|
82e1ab7b2b | ||
|
|
d470842e8e | ||
|
|
439079cad8 | ||
|
|
fead7a27ca | ||
|
|
4679455c3f | ||
|
|
d05b15df77 | ||
|
|
151617c552 | ||
|
|
5a0cadab0c | ||
|
|
c9449c6fb7 | ||
|
|
833183ddb4 | ||
|
|
f4ef91debf | ||
|
|
e74dfaf868 | ||
|
|
4260b99df2 | ||
|
|
9ebed5e497 | ||
|
|
342629a3bf | ||
|
|
ca58c2464a | ||
|
|
9f2b08ddf0 | ||
|
|
ba335958d6 | ||
|
|
78ea818aaf | ||
|
|
deaa8dc287 | ||
|
|
ade70fe4b9 | ||
|
|
4242782dc2 | ||
|
|
8548bb75b6 | ||
|
|
72b9b0fe3a | ||
|
|
392689e7ba | ||
|
|
09a50d0458 | ||
|
|
787b43b218 | ||
|
|
3ee8098708 | ||
|
|
4095e8f383 | ||
|
|
a2380bf76f | ||
|
|
75a139e62c | ||
|
|
1e4e64f831 | ||
|
|
b94f18298d | ||
|
|
d52185c43e | ||
|
|
5e312dc40d | ||
|
|
d8337034b5 | ||
|
|
7921fe2cd1 | ||
|
|
a97c085e9e | ||
|
|
58beca005c | ||
|
|
4e1f50035e | ||
|
|
6228d634fb | ||
|
|
fc72d7fbb6 | ||
|
|
fc571ad46d | ||
|
|
d718b0b34e | ||
|
|
c8930850e3 | ||
|
|
c06caa14c3 | ||
|
|
56b9377c1c | ||
|
|
0d60bc55e4 | ||
|
|
35c5ccfad3 | ||
|
|
2ed3067bbe | ||
|
|
218f82f798 | ||
|
|
8b9bf47166 | ||
|
|
7294f28c3a | ||
|
|
779165144e | ||
|
|
7fbc8152bf | ||
|
|
7b13d119ed | ||
|
|
ba65e2ae6c | ||
|
|
53bf62bb83 | ||
|
|
61f240946a | ||
|
|
14eab22d81 | ||
|
|
96c34d369e | ||
|
|
2336d21efd | ||
|
|
314e4dd4a6 | ||
|
|
44eb01695a | ||
|
|
0b0919e81c | ||
|
|
714a8cef38 | ||
|
|
be4670fecf | ||
|
|
2af5864534 | ||
|
|
3fd84edb61 | ||
|
|
383153419b | ||
|
|
fe1fe1b1e4 | ||
|
|
e6687be493 | ||
|
|
8831669505 | ||
|
|
742614180c | ||
|
|
bc5db9b027 | ||
|
|
c50c9a10f1 | ||
|
|
45589fae58 | ||
|
|
5e433fa913 | ||
|
|
0b77588e87 | ||
|
|
06cdce1e12 | ||
|
|
0e89bca173 | ||
|
|
c6cb97e693 | ||
|
|
251e3e01c7 | ||
|
|
ff7c380d0e | ||
|
|
4fb4efd8ed | ||
|
|
174285f298 | ||
|
|
037e84d377 | ||
|
|
3aedfac968 | ||
|
|
e65d8ad655 | ||
|
|
215e37aac3 | ||
|
|
a59f85c1a0 | ||
|
|
8e2467c393 | ||
|
|
3629a90c2e | ||
|
|
a0f5b70568 | ||
|
|
0b4b9e7f3a | ||
|
|
a38f8d9900 | ||
|
|
4f3bc05a5b | ||
|
|
b3db44f801 | ||
|
|
4e2b394ae8 | ||
|
|
e7ba4777fe | ||
|
|
60225be7fa | ||
|
|
07fb257c04 | ||
|
|
8beb0f19d1 | ||
|
|
32001d1e2b | ||
|
|
e3827fbc23 | ||
|
|
5160be91ae | ||
|
|
d6c052038f | ||
|
|
8a1658ec3e | ||
|
|
baf5614880 | ||
|
|
868f35e27a | ||
|
|
5c7ecdb7c5 | ||
|
|
80a2acaa86 | ||
|
|
47a0a5c746 | ||
|
|
7a9f365ba4 | ||
|
|
0850d3fcf8 | ||
|
|
46d1d70e4c | ||
|
|
8cae659786 | ||
|
|
413f0d0353 | ||
|
|
cba90d4441 | ||
|
|
d19c8b815d | ||
|
|
ab145c8827 | ||
|
|
ecb024af64 | ||
|
|
4e5a45952a | ||
|
|
112dbba7c4 | ||
|
|
9733dd5b5e | ||
|
|
a70993d6d2 | ||
|
|
0a2de78da4 | ||
|
|
288948edf7 | ||
|
|
a0771d0940 | ||
|
|
38bc38cd88 | ||
|
|
494fa0c81a | ||
|
|
7dbbbfc665 | ||
|
|
ac7a44792c | ||
|
|
fc6725f14e | ||
|
|
320a00e7c6 | ||
|
|
6027c8d259 | ||
|
|
52beafff53 | ||
|
|
e8f201cefa | ||
|
|
1c7c5d571d | ||
|
|
e3b7c8e0cc | ||
|
|
c8bd2ae11c | ||
|
|
e1a13608d8 | ||
|
|
eedb29346e | ||
|
|
39d03148e5 | ||
|
|
f419f66546 | ||
|
|
fca4610f11 | ||
|
|
ce955f37ba | ||
|
|
c813a3cc53 | ||
|
|
0b5f18754c | ||
|
|
a75afb85ca | ||
|
|
9dcd21911a | ||
|
|
9bd5f612f7 | ||
|
|
6bc3a43d52 | ||
|
|
88d43af276 | ||
|
|
7e73b7cae9 | ||
|
|
b3001bcd6e | ||
|
|
07715b1b6a | ||
|
|
39ab22070e | ||
|
|
ae8ff4b8e2 | ||
|
|
d22baa88ed | ||
|
|
65874c25db | ||
|
|
06266abd6e | ||
|
|
55ecde665d | ||
|
|
307c57dcc4 | ||
|
|
18d7bc7fa1 | ||
|
|
3607fae75a | ||
|
|
922a30ee47 | ||
|
|
92833a07d1 | ||
|
|
a013f762c4 | ||
|
|
3f6f327cb9 | ||
|
|
b850f0f038 | ||
|
|
a225efaec5 | ||
|
|
ad4c065344 | ||
|
|
89533f0811 | ||
|
|
8f1d5d34a6 | ||
|
|
b1ef850877 | ||
|
|
967121a34b | ||
|
|
fe4ce03d52 | ||
|
|
8161ab573f | ||
|
|
caf0b67e47 | ||
|
|
90b095aa54 | ||
|
|
4bbb78a99b | ||
|
|
dd6d1afd8e | ||
|
|
131eb56f52 | ||
|
|
37ca8854f7 | ||
|
|
067888d549 | ||
|
|
848c3fe51a | ||
|
|
21a4adcd27 | ||
|
|
0003fc8215 | ||
|
|
9126823c7e | ||
|
|
3f13dc790c | ||
|
|
280946ba83 | ||
|
|
9e100bc42b | ||
|
|
6b3169e4d0 | ||
|
|
2e292b67a0 | ||
|
|
18882a4d26 | ||
|
|
8aa930f28e | ||
|
|
2c0b51795e | ||
|
|
d6ac3d8d9a | ||
|
|
e47f6fdfe9 | ||
|
|
30d6d4c733 | ||
|
|
f764297be2 | ||
|
|
75b8c13b00 | ||
|
|
f960c3be31 | ||
|
|
309c5f3641 | ||
|
|
130464c268 | ||
|
|
4d77781ce7 | ||
|
|
c1b829077a | ||
|
|
b1a74df26d | ||
|
|
3af90db5b5 | ||
|
|
58f3cd3eb5 | ||
|
|
b1ebd9f79c | ||
|
|
c2cdaceed0 | ||
|
|
469d0b120e | ||
|
|
81c8b404e7 | ||
|
|
9b6f1d647c | ||
|
|
53066024f6 | ||
|
|
e65ac4d626 | ||
|
|
26165453d2 | ||
|
|
f18b4872ea | ||
|
|
261f559339 | ||
|
|
d74c377337 | ||
|
|
c8ed61b281 | ||
|
|
816ffa99ba | ||
|
|
0b20768a24 | ||
|
|
56093b6614 | ||
|
|
0a8519a26f | ||
|
|
eccd1fdbed | ||
|
|
b5918760fb | ||
|
|
4405310184 | ||
|
|
0413f8ad9d | ||
|
|
93dfc3ec70 | ||
|
|
3e4f1462bc | ||
|
|
40b2f36eb8 | ||
|
|
7a58c1d4ca | ||
|
|
21d6b39fd7 | ||
|
|
2cdf0ff4ab | ||
|
|
773471750d | ||
|
|
29e9d09c68 |
1
.gitignore
vendored
@@ -31,6 +31,7 @@ CMakeFiles/*
|
||||
src/CMakeFiles/*
|
||||
src/Makefile
|
||||
src/cmake_config.h
|
||||
src/cmake_config_githash.h
|
||||
src/cmake_install.cmake
|
||||
src/script/CMakeFiles/*
|
||||
src/script/common/CMakeFiles/*
|
||||
|
||||
@@ -12,9 +12,12 @@ set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||
# Also remember to set PROTOCOL_VERSION in clientserver.h when releasing
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 4)
|
||||
set(VERSION_PATCH 7)
|
||||
set(VERSION_PATCH 9)
|
||||
if(VERSION_EXTRA)
|
||||
set(VERSION_PATCH ${VERSION_PATCH}-${VERSION_EXTRA})
|
||||
else()
|
||||
# Comment the following line during release
|
||||
#set(VERSION_PATCH ${VERSION_PATCH}-dev)
|
||||
endif()
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
|
||||
@@ -28,6 +31,13 @@ else()
|
||||
set(RUN_IN_PLACE 0 CACHE BOOL "Run directly in source directory structure")
|
||||
endif()
|
||||
|
||||
# RUN_IN_PLACE is exported as a #define value, ensure it's 1/0 instead of ON/OFF
|
||||
if(RUN_IN_PLACE)
|
||||
set(RUN_IN_PLACE 1)
|
||||
else()
|
||||
set(RUN_IN_PLACE 0)
|
||||
endif()
|
||||
|
||||
set(BUILD_CLIENT 1 CACHE BOOL "Build client")
|
||||
if(WIN32)
|
||||
set(BUILD_SERVER 0 CACHE BOOL "Build server")
|
||||
@@ -146,7 +156,7 @@ if(BUILD_CLIENT)
|
||||
endif()
|
||||
if(RUN_IN_PLACE)
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/mods/mods_here.txt" DESTINATION "${SHAREDIR}/mods")
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/all/textures_here.txt" DESTINATION "${SHAREDIR}/textures/all")
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/textures/texture_packs_here.txt" DESTINATION "${SHAREDIR}/textures")
|
||||
endif()
|
||||
|
||||
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/fonts" DESTINATION "${SHAREDIR}")
|
||||
|
||||
22
README.txt
@@ -16,7 +16,7 @@ See the README.txt in it.
|
||||
Further documentation
|
||||
----------------------
|
||||
- Website: http://minetest.net/
|
||||
- Wiki: http://wiki.minetest.com/
|
||||
- Wiki: http://wiki.minetest.net/
|
||||
- Developer wiki: http://dev.minetest.net/
|
||||
- Forum: http://forum.minetest.net/
|
||||
- Github: https://github.com/minetest/minetest/
|
||||
@@ -382,17 +382,31 @@ DejaVu Sans Mono:
|
||||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||
|
||||
Bitstream Vera Fonts Copyright:
|
||||
Bitstream Vera Fonts Copyright:
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||
a trademark of Bitstream, Inc.
|
||||
|
||||
Arev Fonts Copyright:
|
||||
Arev Fonts Copyright:
|
||||
|
||||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||
|
||||
Liberation Fonts Copyright:
|
||||
Liberation Fonts Copyright:
|
||||
|
||||
Copyright (c) 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.
|
||||
|
||||
DroidSansFallback:
|
||||
|
||||
Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
19
builtin/async_env.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
engine.log("info","Initializing Asynchronous environment")
|
||||
|
||||
dofile(SCRIPTDIR .. DIR_DELIM .. "misc_helpers.lua")
|
||||
|
||||
function engine.job_processor(serialized_function, serialized_data)
|
||||
|
||||
local fct = marshal.decode(serialized_function)
|
||||
local params = marshal.decode(serialized_data)
|
||||
local retval = marshal.encode(nil)
|
||||
|
||||
if fct ~= nil and type(fct) == "function" then
|
||||
local result = fct(params)
|
||||
retval = marshal.encode(result)
|
||||
else
|
||||
engine.log("error","ASYNC WORKER: unable to deserialize function")
|
||||
end
|
||||
|
||||
return retval,retval:len()
|
||||
end
|
||||
59
builtin/async_event.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
local tbl = engine or minetest
|
||||
|
||||
tbl.async_jobs = {}
|
||||
|
||||
if engine ~= nil then
|
||||
function tbl.async_event_handler(jobid, serialized_retval)
|
||||
local retval = nil
|
||||
if serialized_retval ~= "ERROR" then
|
||||
retval= marshal.decode(serialized_retval)
|
||||
else
|
||||
tbl.log("error","Error fetching async result")
|
||||
end
|
||||
|
||||
assert(type(tbl.async_jobs[jobid]) == "function")
|
||||
tbl.async_jobs[jobid](retval)
|
||||
tbl.async_jobs[jobid] = nil
|
||||
end
|
||||
else
|
||||
|
||||
minetest.register_globalstep(
|
||||
function(dtime)
|
||||
local list = tbl.get_finished_jobs()
|
||||
|
||||
for i=1,#list,1 do
|
||||
local retval = marshal.decode(list[i].retval)
|
||||
|
||||
assert(type(tbl.async_jobs[jobid]) == "function")
|
||||
tbl.async_jobs[list[i].jobid](retval)
|
||||
tbl.async_jobs[list[i].jobid] = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function tbl.handle_async(fct, parameters, callback)
|
||||
|
||||
--serialize fct
|
||||
local serialized_fct = marshal.encode(fct)
|
||||
|
||||
assert(marshal.decode(serialized_fct) ~= nil)
|
||||
|
||||
--serialize parameters
|
||||
local serialized_params = marshal.encode(parameters)
|
||||
|
||||
if serialized_fct == nil or
|
||||
serialized_params == nil or
|
||||
serialized_fct:len() == 0 or
|
||||
serialized_params:len() == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local jobid = tbl.do_async_callback( serialized_fct,
|
||||
serialized_fct:len(),
|
||||
serialized_params,
|
||||
serialized_params:len())
|
||||
|
||||
tbl.async_jobs[jobid] = callback
|
||||
|
||||
return true
|
||||
end
|
||||
@@ -10,19 +10,27 @@ print = minetest.debug
|
||||
math.randomseed(os.time())
|
||||
os.setlocale("C", "numeric")
|
||||
|
||||
-- Load other files
|
||||
dofile(minetest.get_modpath("__builtin").."/serialize.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/misc_helpers.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/item.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/misc_register.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/item_entity.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/deprecated.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/misc.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/privileges.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/auth.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/chatcommands.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/static_spawn.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/detached_inventory.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/falling.lua")
|
||||
dofile(minetest.get_modpath("__builtin").."/features.lua")
|
||||
local errorfct = error
|
||||
error = function(text)
|
||||
print(debug.traceback(""))
|
||||
errorfct(text)
|
||||
end
|
||||
|
||||
-- Load other files
|
||||
local modpath = minetest.get_modpath("__builtin")
|
||||
dofile(modpath.."/serialize.lua")
|
||||
dofile(modpath.."/misc_helpers.lua")
|
||||
dofile(modpath.."/item.lua")
|
||||
dofile(modpath.."/misc_register.lua")
|
||||
dofile(modpath.."/item_entity.lua")
|
||||
dofile(modpath.."/deprecated.lua")
|
||||
dofile(modpath.."/misc.lua")
|
||||
dofile(modpath.."/privileges.lua")
|
||||
dofile(modpath.."/auth.lua")
|
||||
dofile(modpath.."/chatcommands.lua")
|
||||
dofile(modpath.."/static_spawn.lua")
|
||||
dofile(modpath.."/detached_inventory.lua")
|
||||
dofile(modpath.."/falling.lua")
|
||||
dofile(modpath.."/features.lua")
|
||||
dofile(modpath.."/voxelarea.lua")
|
||||
dofile(modpath.."/vector.lua")
|
||||
|
||||
@@ -272,6 +272,9 @@ minetest.register_chatcommand("teleport", {
|
||||
local teleportee = nil
|
||||
local p = {}
|
||||
p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
teleportee = minetest.get_player_by_name(name)
|
||||
if teleportee and p.x and p.y and p.z then
|
||||
minetest.chat_send_player(name, "Teleporting to ("..p.x..", "..p.y..", "..p.z..")")
|
||||
@@ -302,6 +305,9 @@ minetest.register_chatcommand("teleport", {
|
||||
local p = {}
|
||||
local teleportee_name = nil
|
||||
teleportee_name, p.x, p.y, p.z = string.match(param, "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
|
||||
p.x = tonumber(p.x)
|
||||
p.y = tonumber(p.y)
|
||||
p.z = tonumber(p.z)
|
||||
if teleportee_name then
|
||||
teleportee = minetest.get_player_by_name(teleportee_name)
|
||||
end
|
||||
@@ -465,10 +471,10 @@ minetest.register_chatcommand("spawnentity", {
|
||||
minetest.chat_send_player(name, "entityname required")
|
||||
return
|
||||
end
|
||||
print('/spawnentity invoked, entityname="'..entityname..'"')
|
||||
minetest.log("action", '/spawnentity invoked, entityname="'..entityname..'"')
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player == nil then
|
||||
print("Unable to spawn entity, player is nil")
|
||||
minetest.log("error", "Unable to spawn entity, player is nil")
|
||||
return true -- Handled chat message
|
||||
end
|
||||
local p = player:getpos()
|
||||
@@ -485,7 +491,7 @@ minetest.register_chatcommand("pulverize", {
|
||||
func = function(name, param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player == nil then
|
||||
print("Unable to pulverize, player is nil")
|
||||
minetest.log("error", "Unable to pulverize, player is nil")
|
||||
return true -- Handled chat message
|
||||
end
|
||||
if player:get_wielded_item():is_empty() then
|
||||
@@ -509,34 +515,45 @@ minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("rollback_check", {
|
||||
params = "[<range>] [<seconds>]",
|
||||
params = "[<range>] [<seconds>] [limit]",
|
||||
description = "check who has last touched a node or near it, "..
|
||||
"max. <seconds> ago (default range=0, seconds=86400=24h)",
|
||||
"max. <seconds> ago (default range=0, seconds=86400=24h, limit=5)",
|
||||
privs = {rollback=true},
|
||||
func = function(name, param)
|
||||
local range, seconds = string.match(param, "(%d+) *(%d*)")
|
||||
local range, seconds, limit =
|
||||
param:match("(%d+) *(%d*) *(%d*)")
|
||||
range = tonumber(range) or 0
|
||||
seconds = tonumber(seconds) or 86400
|
||||
minetest.chat_send_player(name, "Punch a node (limits set: range="..
|
||||
dump(range).." seconds="..dump(seconds).."s)")
|
||||
limit = tonumber(limit) or 5
|
||||
if limit > 100 then
|
||||
minetest.chat_send_player(name, "That limit is too high!")
|
||||
return
|
||||
end
|
||||
minetest.chat_send_player(name, "Punch a node (range="..
|
||||
range..", seconds="..seconds.."s, limit="..limit..")")
|
||||
|
||||
minetest.rollback_punch_callbacks[name] = function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
minetest.chat_send_player(name, "Checking...")
|
||||
local actor, act_p, act_seconds =
|
||||
minetest.rollback_get_last_node_actor(pos, range, seconds)
|
||||
if actor == "" then
|
||||
minetest.chat_send_player(name, "Checking "..minetest.pos_to_string(pos).."...")
|
||||
local actions = minetest.rollback_get_node_actions(pos, range, seconds, limit)
|
||||
local num_actions = #actions
|
||||
if num_actions == 0 then
|
||||
minetest.chat_send_player(name, "Nobody has touched the "..
|
||||
"specified location in "..dump(seconds).." seconds")
|
||||
"specified location in "..seconds.." seconds")
|
||||
return
|
||||
end
|
||||
local nodedesc = "this node"
|
||||
if act_p.x ~= pos.x or act_p.y ~= pos.y or act_p.z ~= pos.z then
|
||||
nodedesc = minetest.pos_to_string(act_p)
|
||||
local time = os.time()
|
||||
for i = num_actions, 1, -1 do
|
||||
local action = actions[i]
|
||||
minetest.chat_send_player(name,
|
||||
("%s %s %s -> %s %d seconds ago.")
|
||||
:format(
|
||||
minetest.pos_to_string(action.pos),
|
||||
action.actor,
|
||||
action.oldnode.name,
|
||||
action.newnode.name,
|
||||
time - action.time))
|
||||
end
|
||||
local nodename = minetest.get_node(act_p).name
|
||||
minetest.chat_send_player(name, "Last actor on "..nodedesc..
|
||||
" was "..actor..", "..dump(act_seconds)..
|
||||
"s ago (node is now "..nodename..")")
|
||||
end
|
||||
end,
|
||||
})
|
||||
@@ -548,7 +565,7 @@ minetest.register_chatcommand("rollback", {
|
||||
func = function(name, param)
|
||||
local target_name, seconds = string.match(param, ":([^ ]+) *(%d*)")
|
||||
if not target_name then
|
||||
local player_name = nil;
|
||||
local player_name = nil
|
||||
player_name, seconds = string.match(param, "([^ ]+) *(%d*)")
|
||||
if not player_name then
|
||||
minetest.chat_send_player(name, "Invalid parameters. See /help rollback and /help rollback_check")
|
||||
@@ -558,13 +575,13 @@ minetest.register_chatcommand("rollback", {
|
||||
end
|
||||
seconds = tonumber(seconds) or 60
|
||||
minetest.chat_send_player(name, "Reverting actions of "..
|
||||
dump(target_name).." since "..dump(seconds).." seconds.")
|
||||
target_name.." since "..seconds.." seconds.")
|
||||
local success, log = minetest.rollback_revert_actions_by(
|
||||
target_name, seconds)
|
||||
if #log > 10 then
|
||||
if #log > 100 then
|
||||
minetest.chat_send_player(name, "(log is too long to show)")
|
||||
else
|
||||
for _,line in ipairs(log) do
|
||||
for _, line in pairs(log) do
|
||||
minetest.chat_send_player(name, line)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,7 +38,7 @@ setmetatable(minetest.env, {
|
||||
local func = minetest[key]
|
||||
if type(func) == "function" then
|
||||
rawset(table, key, function(self, ...)
|
||||
return func(unpack({...}))
|
||||
return func(...)
|
||||
end)
|
||||
else
|
||||
rawset(table, key, nil)
|
||||
@@ -46,3 +46,8 @@ setmetatable(minetest.env, {
|
||||
return rawget(table, key)
|
||||
end
|
||||
})
|
||||
|
||||
function minetest.rollback_get_last_node_actor(pos, range, seconds)
|
||||
return minetest.rollback_get_node_actions(pos, range, seconds, 1)[1]
|
||||
end
|
||||
|
||||
|
||||
@@ -7,17 +7,18 @@
|
||||
minetest.register_entity("__builtin:falling_node", {
|
||||
initial_properties = {
|
||||
physical = true,
|
||||
collide_with_objects = false,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
visual = "wielditem",
|
||||
textures = {},
|
||||
visual_size = {x=0.667, y=0.667},
|
||||
},
|
||||
|
||||
nodename = "",
|
||||
node = {},
|
||||
|
||||
set_node = function(self, nodename)
|
||||
self.nodename = nodename
|
||||
local stack = ItemStack(nodename)
|
||||
set_node = function(self, node)
|
||||
self.node = node
|
||||
local stack = ItemStack(node.name)
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
if itemtable then
|
||||
@@ -31,20 +32,19 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
end
|
||||
prop = {
|
||||
is_visible = true,
|
||||
textures = {nodename},
|
||||
textures = {node.name},
|
||||
}
|
||||
self.object:set_properties(prop)
|
||||
end,
|
||||
|
||||
get_staticdata = function(self)
|
||||
return self.nodename
|
||||
return self.node.name
|
||||
end,
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
self.nodename = staticdata
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
--self.object:setacceleration({x=0, y=-10, z=0})
|
||||
self:set_node(self.nodename)
|
||||
self:set_node({name=staticdata})
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
@@ -54,10 +54,25 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
local pos = self.object:getpos()
|
||||
local bcp = {x=pos.x, y=pos.y-0.7, z=pos.z} -- Position of bottom center point
|
||||
local bcn = minetest.get_node(bcp)
|
||||
local bcd = minetest.registered_nodes[bcn.name]
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if minetest.registered_nodes[bcn.name] and
|
||||
minetest.registered_nodes[bcn.name].walkable then
|
||||
if minetest.registered_nodes[bcn.name].buildable_to then
|
||||
if not bcd or
|
||||
(bcd.walkable or
|
||||
(minetest.get_node_group(self.node.name, "float") ~= 0 and
|
||||
bcd.liquidtype ~= "none")) then
|
||||
if bcd and bcd.leveled and
|
||||
bcn.name == self.node.name then
|
||||
local addlevel = self.node.level
|
||||
if addlevel == nil or addlevel <= 0 then
|
||||
addlevel = bcd.leveled
|
||||
end
|
||||
if minetest.add_node_level(bcp, addlevel) == 0 then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
elseif bcd and bcd.buildable_to and
|
||||
(minetest.get_node_group(self.node.name, "float") == 0 or
|
||||
bcd.liquidtype == "none") then
|
||||
minetest.remove_node(bcp)
|
||||
return
|
||||
end
|
||||
@@ -82,7 +97,7 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
end
|
||||
end
|
||||
-- Create node and remove entity
|
||||
minetest.add_node(np, {name=self.nodename})
|
||||
minetest.add_node(np, self.node)
|
||||
self.object:remove()
|
||||
nodeupdate(np)
|
||||
else
|
||||
@@ -91,9 +106,9 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
end
|
||||
})
|
||||
|
||||
function spawn_falling_node(p, nodename)
|
||||
function spawn_falling_node(p, node)
|
||||
obj = minetest.add_entity(p, "__builtin:falling_node")
|
||||
obj:get_luaentity():set_node(nodename)
|
||||
obj:get_luaentity():set_node(node)
|
||||
end
|
||||
|
||||
function drop_attached_node(p)
|
||||
@@ -149,13 +164,16 @@ function nodeupdate_single(p, delay)
|
||||
n_bottom = minetest.get_node(p_bottom)
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if minetest.registered_nodes[n_bottom.name] and
|
||||
(minetest.get_node_group(n.name, "float") == 0 or minetest.registered_nodes[n_bottom.name].liquidtype == "none") and
|
||||
(n.name ~= n_bottom.name or (minetest.registered_nodes[n_bottom.name].leveled and minetest.env:get_node_level(p_bottom) < minetest.env:get_node_max_level(p_bottom))) and
|
||||
(not minetest.registered_nodes[n_bottom.name].walkable or
|
||||
minetest.registered_nodes[n_bottom.name].buildable_to) then
|
||||
if delay then
|
||||
minetest.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false)
|
||||
else
|
||||
n.level = minetest.env:get_node_level(p)
|
||||
minetest.remove_node(p)
|
||||
spawn_falling_node(p, n.name)
|
||||
spawn_falling_node(p, n)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
@@ -169,7 +187,7 @@ function nodeupdate_single(p, delay)
|
||||
end
|
||||
end
|
||||
|
||||
function nodeupdate(p)
|
||||
function nodeupdate(p, delay)
|
||||
-- Round p to prevent falling entities to get stuck
|
||||
p.x = math.floor(p.x+0.5)
|
||||
p.y = math.floor(p.y+0.5)
|
||||
@@ -178,7 +196,7 @@ function nodeupdate(p)
|
||||
for x = -1,1 do
|
||||
for y = -1,1 do
|
||||
for z = -1,1 do
|
||||
nodeupdate_single({x=p.x+x, y=p.y+y, z=p.z+z}, not (x==0 and y==0 and z==0))
|
||||
nodeupdate_single({x=p.x+x, y=p.y+y, z=p.z+z}, delay or not (x==0 and y==0 and z==0))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ minetest.features = {
|
||||
chat_send_player_param3 = true,
|
||||
get_all_craft_recipes_works = true,
|
||||
use_texture_alpha = true,
|
||||
no_legacy_abms = true,
|
||||
}
|
||||
|
||||
function minetest.has_feature(arg)
|
||||
|
||||
301
builtin/filterlist.lua
Normal file
@@ -0,0 +1,301 @@
|
||||
--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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Generic implementation of a filter/sortable list --
|
||||
-- Usage: --
|
||||
-- Filterlist needs to be initialized on creation. To achieve this you need to --
|
||||
-- pass following functions: --
|
||||
-- raw_fct() (mandatory): --
|
||||
-- function returning a table containing the elements to be filtered --
|
||||
-- compare_fct(element1,element2) (mandatory): --
|
||||
-- function returning true/false if element1 is same element as element2 --
|
||||
-- uid_match_fct(element1,uid) (optional) --
|
||||
-- function telling if uid is attached to element1 --
|
||||
-- filter_fct(element,filtercriteria) (optional) --
|
||||
-- function returning true/false if filtercriteria met to element --
|
||||
-- fetch_param (optional) --
|
||||
-- parameter passed to raw_fct to aquire correct raw data --
|
||||
-- --
|
||||
--------------------------------------------------------------------------------
|
||||
filterlist = {}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.refresh(this)
|
||||
this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
|
||||
filterlist.process(this)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.create(raw_fct,compare_fct,uid_match_fct,filter_fct,fetch_param)
|
||||
|
||||
assert((raw_fct ~= nil) and (type(raw_fct) == "function"))
|
||||
assert((compare_fct ~= nil) and (type(compare_fct) == "function"))
|
||||
|
||||
local this = {}
|
||||
|
||||
this.m_raw_list_fct = raw_fct
|
||||
this.m_compare_fct = compare_fct
|
||||
this.m_filter_fct = filter_fct
|
||||
this.m_uid_match_fct = uid_match_fct
|
||||
|
||||
this.m_filtercriteria = nil
|
||||
this.m_fetch_param = fetch_param
|
||||
|
||||
this.m_sortmode = "none"
|
||||
this.m_sort_list = {}
|
||||
|
||||
this.m_processed_list = nil
|
||||
this.m_raw_list = this.m_raw_list_fct(this.m_fetch_param)
|
||||
|
||||
filterlist.process(this)
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.add_sort_mechanism(this,name,fct)
|
||||
this.m_sort_list[name] = fct
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.set_filtercriteria(this,criteria)
|
||||
if criteria == this.m_filtercriteria and
|
||||
type(criteria) ~= "table" then
|
||||
return
|
||||
end
|
||||
this.m_filtercriteria = criteria
|
||||
filterlist.process(this)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.get_filtercriteria(this)
|
||||
return this.m_filtercriteria
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--supported sort mode "alphabetic|none"
|
||||
function filterlist.set_sortmode(this,mode)
|
||||
if (mode == this.m_sortmode) then
|
||||
return
|
||||
end
|
||||
this.m_sortmode = mode
|
||||
filterlist.process(this)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.get_list(this)
|
||||
return this.m_processed_list
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.get_raw_list(this)
|
||||
return this.m_raw_list
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.get_raw_element(this,idx)
|
||||
if type(idx) ~= "number" then
|
||||
idx = tonumber(idx)
|
||||
end
|
||||
|
||||
if idx ~= nil and idx > 0 and idx < #this.m_raw_list then
|
||||
return this.m_raw_list[idx]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.get_raw_index(this,listindex)
|
||||
assert(this.m_processed_list ~= nil)
|
||||
|
||||
if listindex ~= nil and listindex > 0 and
|
||||
listindex <= #this.m_processed_list then
|
||||
local entry = this.m_processed_list[listindex]
|
||||
|
||||
for i,v in ipairs(this.m_raw_list) do
|
||||
|
||||
if this.m_compare_fct(v,entry) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.get_current_index(this,listindex)
|
||||
assert(this.m_processed_list ~= nil)
|
||||
|
||||
if listindex ~= nil and listindex > 0 and
|
||||
listindex <= #this.m_raw_list then
|
||||
local entry = this.m_raw_list[listindex]
|
||||
|
||||
for i,v in ipairs(this.m_processed_list) do
|
||||
|
||||
if this.m_compare_fct(v,entry) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.process(this)
|
||||
assert(this.m_raw_list ~= nil)
|
||||
|
||||
if this.m_sortmode == "none" and
|
||||
this.m_filtercriteria == nil then
|
||||
this.m_processed_list = this.m_raw_list
|
||||
return
|
||||
end
|
||||
|
||||
this.m_processed_list = {}
|
||||
|
||||
for k,v in pairs(this.m_raw_list) do
|
||||
if this.m_filtercriteria == nil or
|
||||
this.m_filter_fct(v,this.m_filtercriteria) then
|
||||
table.insert(this.m_processed_list,v)
|
||||
end
|
||||
end
|
||||
|
||||
if this.m_sortmode == "none" then
|
||||
return
|
||||
end
|
||||
|
||||
if this.m_sort_list[this.m_sortmode] ~= nil and
|
||||
type(this.m_sort_list[this.m_sortmode]) == "function" then
|
||||
|
||||
this.m_sort_list[this.m_sortmode](this)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.size(this)
|
||||
if this.m_processed_list == nil then
|
||||
return 0
|
||||
end
|
||||
|
||||
return #this.m_processed_list
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.uid_exists_raw(this,uid)
|
||||
for i,v in ipairs(this.m_raw_list) do
|
||||
if this.m_uid_match_fct(v,uid) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function filterlist.raw_index_by_uid(this, uid)
|
||||
local elementcount = 0
|
||||
local elementidx = 0
|
||||
for i,v in ipairs(this.m_raw_list) do
|
||||
if this.m_uid_match_fct(v,uid) then
|
||||
elementcount = elementcount +1
|
||||
elementidx = i
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- If there are more elements than one with same name uid can't decide which
|
||||
-- one is meant. This shouldn't be possible but just for sure.
|
||||
if elementcount > 1 then
|
||||
elementidx=0
|
||||
end
|
||||
|
||||
return elementidx
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- COMMON helper functions --
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function compare_worlds(world1,world2)
|
||||
|
||||
if world1.path ~= world2.path then
|
||||
return false
|
||||
end
|
||||
|
||||
if world1.name ~= world2.name then
|
||||
return false
|
||||
end
|
||||
|
||||
if world1.gameid ~= world2.gameid then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function sort_worlds_alphabetic(this)
|
||||
|
||||
table.sort(this.m_processed_list, function(a, b)
|
||||
--fixes issue #857 (crash due to sorting nil in worldlist)
|
||||
if a == nil or b == nil then
|
||||
if a == nil and b ~= nil then return false end
|
||||
if b == nil and a ~= nil then return true end
|
||||
return false
|
||||
end
|
||||
if a.name:lower() == b.name:lower() then
|
||||
return a.name < b.name
|
||||
end
|
||||
return a.name:lower() < b.name:lower()
|
||||
end)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function sort_mod_list(this)
|
||||
|
||||
table.sort(this.m_processed_list, function(a, b)
|
||||
-- Show game mods at bottom
|
||||
if a.typ ~= b.typ then
|
||||
return b.typ == "game_mod"
|
||||
end
|
||||
-- If in same or no modpack, sort by name
|
||||
if a.modpack == b.modpack then
|
||||
if a.name:lower() == b.name:lower() then
|
||||
return a.name < b.name
|
||||
end
|
||||
return a.name:lower() < b.name:lower()
|
||||
-- Else compare name to modpack name
|
||||
else
|
||||
-- Always show modpack pseudo-mod on top of modpack mod list
|
||||
if a.name == b.modpack then
|
||||
return true
|
||||
elseif b.name == a.modpack then
|
||||
return false
|
||||
end
|
||||
|
||||
local name_a = a.modpack or a.name
|
||||
local name_b = b.modpack or b.name
|
||||
if name_a:lower() == name_b:lower() then
|
||||
return name_a < name_b
|
||||
end
|
||||
return name_a:lower() < name_b:lower()
|
||||
end
|
||||
end)
|
||||
end
|
||||
322
builtin/gamemgr.lua
Normal file
@@ -0,0 +1,322 @@
|
||||
--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.
|
||||
|
||||
gamemgr = {}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.dialog_new_game()
|
||||
local retval =
|
||||
"label[2,2;" .. fgettext("Game Name") .. "]"..
|
||||
"field[4.5,2.4;6,0.5;te_game_name;;]" ..
|
||||
"button[5,4.2;2.6,0.5;new_game_confirm;" .. fgettext("Create") .. "]" ..
|
||||
"button[7.5,4.2;2.8,0.5;new_game_cancel;" .. fgettext("Cancel") .. "]"
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.handle_games_buttons(fields)
|
||||
if fields["gamelist"] ~= nil then
|
||||
local event = explode_textlist_event(fields["gamelist"])
|
||||
gamemgr.selected_game = event.index
|
||||
end
|
||||
|
||||
if fields["btn_game_mgr_edit_game"] ~= nil then
|
||||
return {
|
||||
is_dialog = true,
|
||||
show_buttons = false,
|
||||
current_tab = "dialog_edit_game"
|
||||
}
|
||||
end
|
||||
|
||||
if fields["btn_game_mgr_new_game"] ~= nil then
|
||||
return {
|
||||
is_dialog = true,
|
||||
show_buttons = false,
|
||||
current_tab = "dialog_new_game"
|
||||
}
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.handle_new_game_buttons(fields)
|
||||
|
||||
if fields["new_game_confirm"] and
|
||||
fields["te_game_name"] ~= nil and
|
||||
fields["te_game_name"] ~= "" then
|
||||
local gamepath = engine.get_gamepath()
|
||||
|
||||
if gamepath ~= nil and
|
||||
gamepath ~= "" then
|
||||
local gamefolder = cleanup_path(fields["te_game_name"])
|
||||
|
||||
--TODO check for already existing first
|
||||
engine.create_dir(gamepath .. DIR_DELIM .. gamefolder)
|
||||
engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "mods")
|
||||
engine.create_dir(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "menu")
|
||||
|
||||
local gameconf =
|
||||
io.open(gamepath .. DIR_DELIM .. gamefolder .. DIR_DELIM .. "game.conf","w")
|
||||
|
||||
if gameconf then
|
||||
gameconf:write("name = " .. fields["te_game_name"])
|
||||
gameconf:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
is_dialog = false,
|
||||
show_buttons = true,
|
||||
current_tab = engine.setting_get("main_menu_tab")
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.handle_edit_game_buttons(fields)
|
||||
local current_game = gamemgr.get_game(gamemgr.selected_game)
|
||||
|
||||
if fields["btn_close_edit_game"] ~= nil or
|
||||
current_game == nil then
|
||||
return {
|
||||
is_dialog = false,
|
||||
show_buttons = true,
|
||||
current_tab = engine.setting_get("main_menu_tab")
|
||||
}
|
||||
end
|
||||
|
||||
if fields["btn_remove_mod_from_game"] ~= nil then
|
||||
gamemgr.delete_mod(current_game,engine.get_textlist_index("mods_current"))
|
||||
end
|
||||
|
||||
if fields["btn_add_mod_to_game"] ~= nil then
|
||||
local modindex = engine.get_textlist_index("mods_available")
|
||||
|
||||
local mod = modmgr.get_global_mod(modindex)
|
||||
if mod ~= nil then
|
||||
|
||||
local sourcepath = mod.path
|
||||
|
||||
if not gamemgr.add_mod(current_game,sourcepath) then
|
||||
gamedata.errormessage =
|
||||
fgettext("Gamemgr: Unable to copy mod \"$1\" to game \"$2\"", mod.name, current_game.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.add_mod(gamespec,sourcepath)
|
||||
if gamespec.gamemods_path ~= nil and
|
||||
gamespec.gamemods_path ~= "" then
|
||||
|
||||
local modname = get_last_folder(sourcepath)
|
||||
|
||||
return engine.copy_dir(sourcepath,gamespec.gamemods_path .. DIR_DELIM .. modname);
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.delete_mod(gamespec,modindex)
|
||||
if gamespec.gamemods_path ~= nil and
|
||||
gamespec.gamemods_path ~= "" then
|
||||
local game_mods = {}
|
||||
get_mods(gamespec.gamemods_path,game_mods)
|
||||
|
||||
if modindex > 0 and
|
||||
#game_mods >= modindex then
|
||||
|
||||
if game_mods[modindex].path:sub(0,gamespec.gamemods_path:len())
|
||||
== gamespec.gamemods_path then
|
||||
engine.delete_dir(game_mods[modindex].path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.find_by_gameid(gameid)
|
||||
for i=1,#gamemgr.games,1 do
|
||||
if gamemgr.games[i].id == gameid then
|
||||
return gamemgr.games[i], i
|
||||
end
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.get_game_mods(gamespec, retval)
|
||||
if gamespec ~= nil and
|
||||
gamespec.gamemods_path ~= nil and
|
||||
gamespec.gamemods_path ~= "" then
|
||||
get_mods(gamespec.gamemods_path, retval)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.get_game_modlist(gamespec)
|
||||
local retval = ""
|
||||
local game_mods = {}
|
||||
gamemgr.get_game_mods(gamespec, game_mods)
|
||||
for i=1,#game_mods,1 do
|
||||
if retval ~= "" then
|
||||
retval = retval..","
|
||||
end
|
||||
retval = retval .. game_mods[i].name
|
||||
end
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.gettab(name)
|
||||
local retval = ""
|
||||
|
||||
if name == "dialog_edit_game" then
|
||||
retval = retval .. gamemgr.dialog_edit_game()
|
||||
end
|
||||
|
||||
if name == "dialog_new_game" then
|
||||
retval = retval .. gamemgr.dialog_new_game()
|
||||
end
|
||||
|
||||
if name == "game_mgr" then
|
||||
retval = retval .. gamemgr.tab()
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.tab()
|
||||
if gamemgr.selected_game == nil then
|
||||
gamemgr.selected_game = 1
|
||||
end
|
||||
|
||||
local retval =
|
||||
"vertlabel[0,-0.25;" .. fgettext("GAMES") .. "]" ..
|
||||
"label[1,-0.25;" .. fgettext("Games") .. ":]" ..
|
||||
"textlist[1,0.25;4.5,4.4;gamelist;" ..
|
||||
gamemgr.gamelist() ..
|
||||
";" .. gamemgr.selected_game .. "]"
|
||||
|
||||
local current_game = gamemgr.get_game(gamemgr.selected_game)
|
||||
|
||||
if current_game ~= nil then
|
||||
if current_game.menuicon_path ~= nil and
|
||||
current_game.menuicon_path ~= "" then
|
||||
retval = retval ..
|
||||
"image[5.8,-0.25;2,2;" ..
|
||||
engine.formspec_escape(current_game.menuicon_path) .. "]"
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"field[8,-0.25;6,2;;" .. current_game.name .. ";]"..
|
||||
"label[6,1.4;" .. fgettext("Mods:") .."]" ..
|
||||
"button[9.7,1.5;2,0.2;btn_game_mgr_edit_game;" .. fgettext("edit game") .. "]" ..
|
||||
"textlist[6,2;5.5,3.3;game_mgr_modlist;"
|
||||
.. gamemgr.get_game_modlist(current_game) ..";0]" ..
|
||||
"button[1,4.75;3.2,0.5;btn_game_mgr_new_game;" .. fgettext("new game") .. "]"
|
||||
end
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.dialog_edit_game()
|
||||
local current_game = gamemgr.get_game(gamemgr.selected_game)
|
||||
if current_game ~= nil then
|
||||
local retval =
|
||||
"vertlabel[0,-0.25;" .. fgettext("EDIT GAME") .."]" ..
|
||||
"label[0,-0.25;" .. current_game.name .. "]" ..
|
||||
"button[11.55,-0.2;0.75,0.5;btn_close_edit_game;x]"
|
||||
|
||||
if current_game.menuicon_path ~= nil and
|
||||
current_game.menuicon_path ~= "" then
|
||||
retval = retval ..
|
||||
"image[5.25,0;2,2;" ..
|
||||
engine.formspec_escape(current_game.menuicon_path) .. "]"
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"textlist[0.5,0.5;4.5,4.3;mods_current;"
|
||||
.. gamemgr.get_game_modlist(current_game) ..";0]"
|
||||
|
||||
|
||||
retval = retval ..
|
||||
"textlist[7,0.5;4.5,4.3;mods_available;"
|
||||
.. modmgr.render_modlist() .. ";0]"
|
||||
|
||||
retval = retval ..
|
||||
"button[0.55,4.95;4.7,0.5;btn_remove_mod_from_game;" .. fgettext("Remove selected mod") .."]"
|
||||
|
||||
retval = retval ..
|
||||
"button[7.05,4.95;4.7,0.5;btn_add_mod_to_game;" .. fgettext("<<-- Add mod") .."]"
|
||||
|
||||
return retval
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.handle_buttons(tab,fields)
|
||||
local retval = nil
|
||||
|
||||
if tab == "dialog_edit_game" then
|
||||
retval = gamemgr.handle_edit_game_buttons(fields)
|
||||
end
|
||||
|
||||
if tab == "dialog_new_game" then
|
||||
retval = gamemgr.handle_new_game_buttons(fields)
|
||||
end
|
||||
|
||||
if tab == "game_mgr" then
|
||||
retval = gamemgr.handle_games_buttons(fields)
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.get_game(index)
|
||||
if index > 0 and index <= #gamemgr.games then
|
||||
return gamemgr.games[index]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.update_gamelist()
|
||||
gamemgr.games = engine.get_games()
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function gamemgr.gamelist()
|
||||
local retval = ""
|
||||
if #gamemgr.games > 0 then
|
||||
retval = retval .. gamemgr.games[1].id
|
||||
|
||||
for i=2,#gamemgr.games,1 do
|
||||
retval = retval .. "," .. gamemgr.games[i].name
|
||||
end
|
||||
end
|
||||
return retval
|
||||
end
|
||||
126
builtin/item.lua
@@ -34,8 +34,45 @@ function minetest.get_pointed_thing_position(pointed_thing, above)
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.dir_to_facedir(dir)
|
||||
if math.abs(dir.x) > math.abs(dir.z) then
|
||||
function minetest.dir_to_facedir(dir, is6d)
|
||||
--account for y if requested
|
||||
if is6d and math.abs(dir.y) > math.abs(dir.x) and math.abs(dir.y) > math.abs(dir.z) then
|
||||
|
||||
--from above
|
||||
if dir.y < 0 then
|
||||
if math.abs(dir.x) > math.abs(dir.z) then
|
||||
if dir.x < 0 then
|
||||
return 19
|
||||
else
|
||||
return 13
|
||||
end
|
||||
else
|
||||
if dir.z < 0 then
|
||||
return 10
|
||||
else
|
||||
return 4
|
||||
end
|
||||
end
|
||||
|
||||
--from below
|
||||
else
|
||||
if math.abs(dir.x) > math.abs(dir.z) then
|
||||
if dir.x < 0 then
|
||||
return 15
|
||||
else
|
||||
return 17
|
||||
end
|
||||
else
|
||||
if dir.z < 0 then
|
||||
return 6
|
||||
else
|
||||
return 8
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--otherwise, place horizontally
|
||||
elseif math.abs(dir.x) > math.abs(dir.z) then
|
||||
if dir.x < 0 then
|
||||
return 3
|
||||
else
|
||||
@@ -50,6 +87,27 @@ function minetest.dir_to_facedir(dir)
|
||||
end
|
||||
end
|
||||
|
||||
function minetest.facedir_to_dir(facedir)
|
||||
--a table of possible dirs
|
||||
return ({{x=0, y=0, z=1},
|
||||
{x=1, y=0, z=0},
|
||||
{x=0, y=0, z=-1},
|
||||
{x=-1, y=0, z=0},
|
||||
{x=0, y=-1, z=0},
|
||||
{x=0, y=1, z=0}})
|
||||
|
||||
--indexed into by a table of correlating facedirs
|
||||
[({[0]=1, 2, 3, 4,
|
||||
5, 2, 6, 4,
|
||||
6, 2, 5, 4,
|
||||
1, 5, 3, 6,
|
||||
1, 6, 3, 5,
|
||||
1, 4, 3, 2})
|
||||
|
||||
--indexed into by the facedir in question
|
||||
[facedir]]
|
||||
end
|
||||
|
||||
function minetest.dir_to_wallmounted(dir)
|
||||
if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then
|
||||
if dir.y < 0 then
|
||||
@@ -121,11 +179,11 @@ function minetest.get_node_drops(nodename, toolname)
|
||||
return got_items
|
||||
end
|
||||
|
||||
function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
function minetest.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
local item = itemstack:peek_item()
|
||||
local def = itemstack:get_definition()
|
||||
if def.type ~= "node" or pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
local under = pointed_thing.under
|
||||
@@ -136,7 +194,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
if not oldnode_under or not oldnode_above then
|
||||
minetest.log("info", placer:get_player_name() .. " tried to place"
|
||||
.. " node in unloaded position " .. minetest.pos_to_string(above))
|
||||
return itemstack
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
local olddef_under = ItemStack({name=oldnode_under.name}):get_definition()
|
||||
@@ -148,7 +206,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
minetest.log("info", placer:get_player_name() .. " tried to place"
|
||||
.. " node in invalid position " .. minetest.pos_to_string(above)
|
||||
.. ", replacing " .. oldnode_above.name)
|
||||
return itemstack
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
-- Place above pointed node
|
||||
@@ -160,14 +218,23 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
place_to = {x = under.x, y = under.y, z = under.z}
|
||||
end
|
||||
|
||||
if minetest.is_protected(place_to, placer:get_player_name()) then
|
||||
minetest.log("action", placer:get_player_name()
|
||||
.. " tried to place " .. def.name
|
||||
.. " at protected position "
|
||||
.. minetest.pos_to_string(place_to))
|
||||
minetest.record_protection_violation(place_to, placer:get_player_name())
|
||||
return itemstack
|
||||
end
|
||||
|
||||
minetest.log("action", placer:get_player_name() .. " places node "
|
||||
.. def.name .. " at " .. minetest.pos_to_string(place_to))
|
||||
|
||||
local oldnode = minetest.get_node(place_to)
|
||||
local newnode = {name = def.name, param1 = 0, param2 = 0}
|
||||
local newnode = {name = def.name, param1 = 0, param2 = param2}
|
||||
|
||||
-- Calculate direction for wall mounted stuff like torches and signs
|
||||
if def.paramtype2 == 'wallmounted' then
|
||||
if def.paramtype2 == 'wallmounted' and not param2 then
|
||||
local dir = {
|
||||
x = under.x - above.x,
|
||||
y = under.y - above.y,
|
||||
@@ -175,7 +242,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
}
|
||||
newnode.param2 = minetest.dir_to_wallmounted(dir)
|
||||
-- Calculate the direction for furnaces and chests and stuff
|
||||
elseif def.paramtype2 == 'facedir' then
|
||||
elseif def.paramtype2 == 'facedir' and not param2 then
|
||||
local placer_pos = placer:getpos()
|
||||
if placer_pos then
|
||||
local dir = {
|
||||
@@ -193,7 +260,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
not check_attached_node(place_to, newnode) then
|
||||
minetest.log("action", "attached node " .. def.name ..
|
||||
" can not be placed at " .. minetest.pos_to_string(place_to))
|
||||
return itemstack
|
||||
return itemstack, false
|
||||
end
|
||||
|
||||
-- Add node and update
|
||||
@@ -225,7 +292,7 @@ function minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
if take_item then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
return itemstack, true
|
||||
end
|
||||
|
||||
function minetest.item_place_object(itemstack, placer, pointed_thing)
|
||||
@@ -237,19 +304,19 @@ function minetest.item_place_object(itemstack, placer, pointed_thing)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function minetest.item_place(itemstack, placer, pointed_thing)
|
||||
function minetest.item_place(itemstack, placer, pointed_thing, param2)
|
||||
-- Call on_rightclick if the pointed node defines it
|
||||
if pointed_thing.type == "node" and placer and
|
||||
not placer:get_player_control().sneak then
|
||||
local n = minetest.get_node(pointed_thing.under)
|
||||
local nn = n.name
|
||||
if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then
|
||||
return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n, placer, itemstack) or itemstack
|
||||
return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n, placer, itemstack) or itemstack, false
|
||||
end
|
||||
end
|
||||
|
||||
if itemstack:get_definition().type == "node" then
|
||||
return minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
return minetest.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
@@ -311,28 +378,40 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||
end
|
||||
|
||||
function minetest.node_dig(pos, node, digger)
|
||||
minetest.debug("node_dig")
|
||||
|
||||
local def = ItemStack({name=node.name}):get_definition()
|
||||
-- Check if def ~= 0 because we always want to be able to remove unknown nodes
|
||||
if #def ~= 0 and not def.diggable or (def.can_dig and not def.can_dig(pos,digger)) then
|
||||
minetest.debug("not diggable")
|
||||
if not def.diggable or (def.can_dig and not def.can_dig(pos,digger)) then
|
||||
minetest.log("info", digger:get_player_name() .. " tried to dig "
|
||||
.. node.name .. " which is not diggable "
|
||||
.. minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.is_protected(pos, digger:get_player_name()) then
|
||||
minetest.log("action", digger:get_player_name()
|
||||
.. " tried to dig " .. node.name
|
||||
.. " at protected position "
|
||||
.. minetest.pos_to_string(pos))
|
||||
minetest.record_protection_violation(pos, digger:get_player_name())
|
||||
return
|
||||
end
|
||||
|
||||
minetest.log('action', digger:get_player_name() .. " digs "
|
||||
.. node.name .. " at " .. minetest.pos_to_string(pos))
|
||||
|
||||
local wielded = digger:get_wielded_item()
|
||||
local drops = minetest.get_node_drops(node.name, wielded:get_name())
|
||||
|
||||
-- Wear out tool
|
||||
|
||||
local wdef = wielded:get_definition()
|
||||
local tp = wielded:get_tool_capabilities()
|
||||
local dp = minetest.get_dig_params(def.groups, tp)
|
||||
wielded:add_wear(dp.wear)
|
||||
if wdef and wdef.after_use then
|
||||
wielded = wdef.after_use(wielded, digger, node, dp) or wielded
|
||||
else
|
||||
-- Wear out tool
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
wielded:add_wear(dp.wear)
|
||||
end
|
||||
end
|
||||
digger:set_wielded_item(wielded)
|
||||
|
||||
-- Handle drops
|
||||
@@ -422,7 +501,7 @@ minetest.nodedef_default = {
|
||||
post_effect_color = {a=0, r=0, g=0, b=0},
|
||||
paramtype = "none",
|
||||
paramtype2 = "none",
|
||||
is_ground_content = false,
|
||||
is_ground_content = true,
|
||||
sunlight_propagates = false,
|
||||
walkable = true,
|
||||
pointable = true,
|
||||
@@ -433,6 +512,7 @@ minetest.nodedef_default = {
|
||||
liquid_alternative_flowing = "",
|
||||
liquid_alternative_source = "",
|
||||
liquid_viscosity = 0,
|
||||
drowning = 0,
|
||||
light_source = 0,
|
||||
damage_per_second = 0,
|
||||
selection_box = {type="regular"},
|
||||
|
||||
@@ -12,6 +12,7 @@ minetest.register_entity("__builtin:item", {
|
||||
initial_properties = {
|
||||
hp_max = 1,
|
||||
physical = true,
|
||||
collide_with_objects = false,
|
||||
collisionbox = {-0.17,-0.17,-0.17, 0.17,0.17,0.17},
|
||||
visual = "sprite",
|
||||
visual_size = {x=0.5, y=0.5},
|
||||
|
||||
1328
builtin/mainmenu.lua
Normal file
@@ -40,15 +40,24 @@ function minetest.check_player_privs(name, privs)
|
||||
return true, ""
|
||||
end
|
||||
|
||||
local player_list = {}
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
player_list[player:get_player_name()] = player
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
player_list[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
function minetest.get_connected_players()
|
||||
-- This could be optimized a bit, but leave that for later
|
||||
local list = {}
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius({x=0,y=0,z=0}, 1000000)) do
|
||||
if obj:is_player() then
|
||||
table.insert(list, obj)
|
||||
local temp_table = {}
|
||||
for index, value in pairs(player_list) do
|
||||
if value:is_player_connected() then
|
||||
table.insert(temp_table, value)
|
||||
end
|
||||
end
|
||||
return list
|
||||
return temp_table
|
||||
end
|
||||
|
||||
function minetest.hash_node_position(pos)
|
||||
@@ -99,10 +108,14 @@ function minetest.setting_get_pos(name)
|
||||
return minetest.string_to_pos(value)
|
||||
end
|
||||
|
||||
function minetest.formspec_escape(str)
|
||||
str = string.gsub(str, "\\", "\\\\")
|
||||
str = string.gsub(str, "%[", "\\[")
|
||||
str = string.gsub(str, "%]", "\\]")
|
||||
return str
|
||||
-- To be overriden by protection mods
|
||||
function minetest.is_protected(pos, name)
|
||||
return false
|
||||
end
|
||||
|
||||
function minetest.record_protection_violation(pos, name)
|
||||
for _, func in pairs(minetest.registered_on_protection_violation) do
|
||||
func(pos, name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
-- Minetest: builtin/misc_helpers.lua
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function basic_dump2(o)
|
||||
if type(o) == "number" then
|
||||
return tostring(o)
|
||||
@@ -19,6 +20,7 @@ function basic_dump2(o)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function dump2(o, name, dumped)
|
||||
name = name or "_"
|
||||
dumped = dumped or {}
|
||||
@@ -44,6 +46,7 @@ function dump2(o, name, dumped)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function dump(o, dumped)
|
||||
dumped = dumped or {}
|
||||
if type(o) == "number" then
|
||||
@@ -57,7 +60,7 @@ function dump(o, dumped)
|
||||
dumped[o] = true
|
||||
local t = {}
|
||||
for k,v in pairs(o) do
|
||||
t[#t+1] = "" .. k .. " = " .. dump(v, dumped)
|
||||
t[#t+1] = "[" .. dump(k, dumped) .. "] = " .. dump(v, dumped)
|
||||
end
|
||||
return "{" .. table.concat(t, ", ") .. "}"
|
||||
elseif type(o) == "boolean" then
|
||||
@@ -74,6 +77,7 @@ function dump(o, dumped)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function string:split(sep)
|
||||
local sep, fields = sep or ",", {}
|
||||
local pattern = string.format("([^%s]+)", sep)
|
||||
@@ -81,14 +85,319 @@ function string:split(sep)
|
||||
return fields
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function file_exists(filename)
|
||||
local f = io.open(filename, "r")
|
||||
if f==nil then
|
||||
return false
|
||||
else
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function string:trim()
|
||||
return (self:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
assert(string.trim("\n \t\tfoo bar\t ") == "foo bar")
|
||||
|
||||
function minetest.pos_to_string(pos)
|
||||
return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
|
||||
--------------------------------------------------------------------------------
|
||||
function math.hypot(x, y)
|
||||
local t
|
||||
x = math.abs(x)
|
||||
y = math.abs(y)
|
||||
t = math.min(x, y)
|
||||
x = math.max(x, y)
|
||||
if x == 0 then return 0 end
|
||||
t = t / x
|
||||
return x * math.sqrt(1 + t * t)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function explode_textlist_event(text)
|
||||
|
||||
local retval = {}
|
||||
retval.typ = "INV"
|
||||
|
||||
local parts = text:split(":")
|
||||
|
||||
if #parts == 2 then
|
||||
retval.typ = parts[1]:trim()
|
||||
retval.index= tonumber(parts[2]:trim())
|
||||
|
||||
if type(retval.index) ~= "number" then
|
||||
retval.typ = "INV"
|
||||
end
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function get_last_folder(text,count)
|
||||
local parts = text:split(DIR_DELIM)
|
||||
|
||||
if count == nil then
|
||||
return parts[#parts]
|
||||
end
|
||||
|
||||
local retval = ""
|
||||
for i=1,count,1 do
|
||||
retval = retval .. parts[#parts - (count-i)] .. DIR_DELIM
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function cleanup_path(temppath)
|
||||
|
||||
local parts = temppath:split("-")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath .. "_"
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
parts = temppath:split(".")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath .. "_"
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
parts = temppath:split("'")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath .. ""
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
parts = temppath:split(" ")
|
||||
temppath = ""
|
||||
for i=1,#parts,1 do
|
||||
if temppath ~= "" then
|
||||
temppath = temppath
|
||||
end
|
||||
temppath = temppath .. parts[i]
|
||||
end
|
||||
|
||||
return temppath
|
||||
end
|
||||
|
||||
local tbl = engine or minetest
|
||||
function tbl.formspec_escape(text)
|
||||
if text ~= nil then
|
||||
text = string.gsub(text,"\\","\\\\")
|
||||
text = string.gsub(text,"%]","\\]")
|
||||
text = string.gsub(text,"%[","\\[")
|
||||
text = string.gsub(text,";","\\;")
|
||||
text = string.gsub(text,",","\\,")
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
|
||||
function tbl.splittext(text,charlimit)
|
||||
local retval = {}
|
||||
|
||||
local current_idx = 1
|
||||
|
||||
local start,stop = string.find(text," ",current_idx)
|
||||
local nl_start,nl_stop = string.find(text,"\n",current_idx)
|
||||
local gotnewline = false
|
||||
if nl_start ~= nil and (start == nil or nl_start < start) then
|
||||
start = nl_start
|
||||
stop = nl_stop
|
||||
gotnewline = true
|
||||
end
|
||||
local last_line = ""
|
||||
while start ~= nil do
|
||||
if string.len(last_line) + (stop-start) > charlimit then
|
||||
table.insert(retval,last_line)
|
||||
last_line = ""
|
||||
end
|
||||
|
||||
if last_line ~= "" then
|
||||
last_line = last_line .. " "
|
||||
end
|
||||
|
||||
last_line = last_line .. string.sub(text,current_idx,stop -1)
|
||||
|
||||
if gotnewline then
|
||||
table.insert(retval,last_line)
|
||||
last_line = ""
|
||||
gotnewline = false
|
||||
end
|
||||
current_idx = stop+1
|
||||
|
||||
start,stop = string.find(text," ",current_idx)
|
||||
nl_start,nl_stop = string.find(text,"\n",current_idx)
|
||||
|
||||
if nl_start ~= nil and (start == nil or nl_start < start) then
|
||||
start = nl_start
|
||||
stop = nl_stop
|
||||
gotnewline = true
|
||||
end
|
||||
end
|
||||
|
||||
--add last part of text
|
||||
if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
|
||||
table.insert(retval,last_line)
|
||||
table.insert(retval,string.sub(text,current_idx))
|
||||
else
|
||||
last_line = last_line .. " " .. string.sub(text,current_idx)
|
||||
table.insert(retval,last_line)
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
if minetest then
|
||||
local dirs1 = { 9, 18, 7, 12 }
|
||||
local dirs2 = { 20, 23, 22, 21 }
|
||||
|
||||
function minetest.rotate_and_place(itemstack, placer, pointed_thing, infinitestacks, orient_flags)
|
||||
orient_flags = orient_flags or {}
|
||||
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if not minetest.registered_nodes[node.name]
|
||||
or not minetest.registered_nodes[node.name].on_rightclick then
|
||||
|
||||
local above = pointed_thing.above
|
||||
local under = pointed_thing.under
|
||||
local pitch = placer:get_look_pitch()
|
||||
local pname = minetest.get_node(under).name
|
||||
local node = minetest.get_node(above)
|
||||
local fdir = minetest.dir_to_facedir(placer:get_look_dir())
|
||||
local wield_name = itemstack:get_name()
|
||||
local reg_node = minetest.registered_nodes[pname]
|
||||
|
||||
if not reg_node or not reg_node.on_rightclick then
|
||||
|
||||
local iswall = (above.x ~= under.x) or (above.z ~= under.z)
|
||||
local isceiling = (above.x == under.x) and (above.z == under.z)
|
||||
and (pitch > 0)
|
||||
local pos1 = above
|
||||
|
||||
if reg_node and reg_node.buildable_to then
|
||||
pos1 = under
|
||||
iswall = false
|
||||
end
|
||||
|
||||
reg_node = minetest.registered_nodes[minetest.get_node(pos1).name]
|
||||
if not reg_node or not reg_node.buildable_to then
|
||||
return
|
||||
end
|
||||
|
||||
if orient_flags.force_floor then
|
||||
iswall = false
|
||||
isceiling = false
|
||||
elseif orient_flags.force_ceiling then
|
||||
iswall = false
|
||||
isceiling = true
|
||||
elseif orient_flags.force_wall then
|
||||
iswall = true
|
||||
isceiling = false
|
||||
elseif orient_flags.invert_wall then
|
||||
iswall = not iswall
|
||||
end
|
||||
|
||||
if iswall then
|
||||
minetest.add_node(pos1, {name = wield_name, param2 = dirs1[fdir+1] })
|
||||
elseif isceiling then
|
||||
if orient_flags.force_facedir then
|
||||
minetest.add_node(pos1, {name = wield_name, param2 = 20 })
|
||||
else
|
||||
minetest.add_node(pos1, {name = wield_name, param2 = dirs2[fdir+1] })
|
||||
end
|
||||
else -- place right side up
|
||||
if orient_flags.force_facedir then
|
||||
minetest.add_node(pos1, {name = wield_name, param2 = 0 })
|
||||
else
|
||||
minetest.add_node(pos1, {name = wield_name, param2 = fdir })
|
||||
end
|
||||
end
|
||||
|
||||
if not infinitestacks then
|
||||
itemstack:take_item()
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
else
|
||||
minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--Wrapper for rotate_and_place() to check for sneak and assume Creative mode
|
||||
--implies infinite stacks when performing a 6d rotation.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
minetest.rotate_node = function(itemstack, placer, pointed_thing)
|
||||
minetest.rotate_and_place(itemstack, placer, pointed_thing,
|
||||
minetest.setting_getbool("creative_mode"),
|
||||
{invert_wall = placer:get_player_control().sneak})
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- mainmenu only functions
|
||||
--------------------------------------------------------------------------------
|
||||
if engine ~= nil then
|
||||
engine.get_game = function(index)
|
||||
local games = game.get_games()
|
||||
|
||||
if index > 0 and index <= #games then
|
||||
return games[index]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function fgettext(text, ...)
|
||||
text = engine.gettext(text)
|
||||
local arg = {n=select('#', ...), ...}
|
||||
if arg.n >= 1 then
|
||||
-- Insert positional parameters ($1, $2, ...)
|
||||
result = ''
|
||||
pos = 1
|
||||
while pos <= text:len() do
|
||||
newpos = text:find('[$]', pos)
|
||||
if newpos == nil then
|
||||
result = result .. text:sub(pos)
|
||||
pos = text:len() + 1
|
||||
else
|
||||
paramindex = tonumber(text:sub(newpos+1, newpos+1))
|
||||
result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
|
||||
pos = newpos + 2
|
||||
end
|
||||
end
|
||||
text = result
|
||||
end
|
||||
return engine.formspec_escape(text)
|
||||
end
|
||||
end
|
||||
--------------------------------------------------------------------------------
|
||||
-- core only fct
|
||||
--------------------------------------------------------------------------------
|
||||
if minetest ~= nil then
|
||||
--------------------------------------------------------------------------------
|
||||
function minetest.pos_to_string(pos)
|
||||
return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -24,17 +24,15 @@ minetest.registered_aliases = {}
|
||||
|
||||
-- For tables that are indexed by item name:
|
||||
-- If table[X] does not exist, default to table[minetest.registered_aliases[X]]
|
||||
local function set_alias_metatable(table)
|
||||
setmetatable(table, {
|
||||
__index = function(name)
|
||||
return rawget(table, minetest.registered_aliases[name])
|
||||
end
|
||||
})
|
||||
end
|
||||
set_alias_metatable(minetest.registered_items)
|
||||
set_alias_metatable(minetest.registered_nodes)
|
||||
set_alias_metatable(minetest.registered_craftitems)
|
||||
set_alias_metatable(minetest.registered_tools)
|
||||
local alias_metatable = {
|
||||
__index = function(t, name)
|
||||
return rawget(t, minetest.registered_aliases[name])
|
||||
end
|
||||
}
|
||||
setmetatable(minetest.registered_items, alias_metatable)
|
||||
setmetatable(minetest.registered_nodes, alias_metatable)
|
||||
setmetatable(minetest.registered_craftitems, alias_metatable)
|
||||
setmetatable(minetest.registered_tools, alias_metatable)
|
||||
|
||||
-- These item names may not be used because they would interfere
|
||||
-- with legacy itemstrings
|
||||
@@ -106,6 +104,11 @@ function minetest.register_item(name, itemdef)
|
||||
-- Use the nodebox as selection box if it's not set manually
|
||||
if itemdef.drawtype == "nodebox" and not itemdef.selection_box then
|
||||
itemdef.selection_box = itemdef.node_box
|
||||
elseif itemdef.drawtype == "fencelike" and not itemdef.selection_box then
|
||||
itemdef.selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
|
||||
}
|
||||
end
|
||||
setmetatable(itemdef, {__index = minetest.nodedef_default})
|
||||
minetest.registered_nodes[itemdef.name] = itemdef
|
||||
@@ -223,6 +226,27 @@ function minetest.register_alias(name, convert_to)
|
||||
end
|
||||
end
|
||||
|
||||
local register_biome_raw = minetest.register_biome
|
||||
minetest.registered_biomes = {}
|
||||
function minetest.register_biome(biome)
|
||||
minetest.registered_biomes[biome.name] = biome
|
||||
register_biome_raw(biome)
|
||||
end
|
||||
|
||||
function minetest.on_craft(itemstack, player, old_craft_list, craft_inv)
|
||||
for _, func in ipairs(minetest.registered_on_crafts) do
|
||||
itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function minetest.craft_predict(itemstack, player, old_craft_list, craft_inv)
|
||||
for _, func in ipairs(minetest.registered_craft_predicts) do
|
||||
itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Alias the forbidden item names to "" so they can't be
|
||||
-- created via itemstrings (e.g. /give)
|
||||
local name
|
||||
@@ -249,6 +273,7 @@ minetest.register_item(":unknown", {
|
||||
on_place = minetest.item_place,
|
||||
on_drop = minetest.item_drop,
|
||||
groups = {not_in_creative_inventory=1},
|
||||
diggable = true,
|
||||
})
|
||||
|
||||
minetest.register_node(":air", {
|
||||
@@ -289,6 +314,45 @@ minetest.register_item(":", {
|
||||
groups = {not_in_creative_inventory=1},
|
||||
})
|
||||
|
||||
|
||||
function minetest.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 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
|
||||
|
||||
--
|
||||
-- Callback registration
|
||||
--
|
||||
@@ -307,6 +371,7 @@ end
|
||||
|
||||
minetest.registered_on_chat_messages, minetest.register_on_chat_message = make_registration()
|
||||
minetest.registered_globalsteps, minetest.register_globalstep = make_registration()
|
||||
minetest.registered_on_mapgen_inits, minetest.register_on_mapgen_init = make_registration()
|
||||
minetest.registered_on_shutdown, minetest.register_on_shutdown = make_registration()
|
||||
minetest.registered_on_punchnodes, minetest.register_on_punchnode = make_registration()
|
||||
minetest.registered_on_placenodes, minetest.register_on_placenode = make_registration()
|
||||
@@ -315,7 +380,12 @@ minetest.registered_on_generateds, minetest.register_on_generated = make_registr
|
||||
minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registration()
|
||||
minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration()
|
||||
minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration()
|
||||
minetest.registered_on_prejoinplayers, minetest.register_on_prejoinplayer = make_registration()
|
||||
minetest.registered_on_joinplayers, minetest.register_on_joinplayer = make_registration()
|
||||
minetest.registered_on_leaveplayers, minetest.register_on_leaveplayer = make_registration()
|
||||
minetest.registered_on_player_receive_fields, minetest.register_on_player_receive_fields = make_registration_reverse()
|
||||
minetest.registered_on_cheats, minetest.register_on_cheat = make_registration()
|
||||
minetest.registered_on_crafts, minetest.register_on_craft = make_registration()
|
||||
minetest.registered_craft_predicts, minetest.register_craft_predict = make_registration()
|
||||
minetest.registered_on_protection_violation, minetest.register_on_protection_violation = make_registration()
|
||||
|
||||
|
||||
80
builtin/mm_menubar.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
--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.
|
||||
|
||||
menubar = {}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function menubar.handle_buttons(fields)
|
||||
for i=1,#menubar.buttons,1 do
|
||||
if fields[menubar.buttons[i].btn_name] ~= nil then
|
||||
menu.last_game = menubar.buttons[i].index
|
||||
engine.setting_set("main_menu_last_game_idx",menu.last_game)
|
||||
menu.update_gametype()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function menubar.refresh()
|
||||
|
||||
menubar.formspec = "box[-0.3,5.625;12.4,1.2;#000000]" ..
|
||||
"box[-0.3,5.6;12.4,0.05;#FFFFFF]"
|
||||
menubar.buttons = {}
|
||||
|
||||
local button_base = -0.08
|
||||
|
||||
local maxbuttons = #gamemgr.games
|
||||
|
||||
if maxbuttons > 11 then
|
||||
maxbuttons = 11
|
||||
end
|
||||
|
||||
for i=1,maxbuttons,1 do
|
||||
|
||||
local btn_name = "menubar_btn_" .. gamemgr.games[i].id
|
||||
local buttonpos = button_base + (i-1) * 1.1
|
||||
if gamemgr.games[i].menuicon_path ~= nil and
|
||||
gamemgr.games[i].menuicon_path ~= "" then
|
||||
|
||||
menubar.formspec = menubar.formspec ..
|
||||
"image_button[" .. buttonpos .. ",5.72;1.165,1.175;" ..
|
||||
engine.formspec_escape(gamemgr.games[i].menuicon_path) .. ";" ..
|
||||
btn_name .. ";;true;false]"
|
||||
else
|
||||
|
||||
local part1 = gamemgr.games[i].id:sub(1,5)
|
||||
local part2 = gamemgr.games[i].id:sub(6,10)
|
||||
local part3 = gamemgr.games[i].id:sub(11)
|
||||
|
||||
local text = part1 .. "\n" .. part2
|
||||
if part3 ~= nil and
|
||||
part3 ~= "" then
|
||||
text = text .. "\n" .. part3
|
||||
end
|
||||
menubar.formspec = menubar.formspec ..
|
||||
"image_button[" .. buttonpos .. ",5.72;1.165,1.175;;" ..btn_name ..
|
||||
";" .. text .. ";true;true]"
|
||||
end
|
||||
|
||||
local toadd = {
|
||||
btn_name = btn_name,
|
||||
index = i,
|
||||
}
|
||||
|
||||
table.insert(menubar.buttons,toadd)
|
||||
end
|
||||
end
|
||||
146
builtin/mm_textures.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
--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.
|
||||
|
||||
|
||||
mm_texture = {}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_texture.init()
|
||||
mm_texture.defaulttexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
|
||||
DIR_DELIM .. "pack" .. DIR_DELIM
|
||||
mm_texture.basetexturedir = mm_texture.defaulttexturedir
|
||||
|
||||
mm_texture.texturepack = engine.setting_get("texture_path")
|
||||
|
||||
mm_texture.gameid = nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_texture.update(tab,gamedetails)
|
||||
if tab ~= "singleplayer" then
|
||||
mm_texture.reset()
|
||||
return
|
||||
end
|
||||
|
||||
if gamedetails == nil then
|
||||
return
|
||||
end
|
||||
|
||||
mm_texture.update_game(gamedetails)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_texture.reset()
|
||||
mm_texture.gameid = nil
|
||||
local have_bg = false
|
||||
local have_overlay = mm_texture.set_generic("overlay")
|
||||
|
||||
if not have_overlay then
|
||||
have_bg = mm_texture.set_generic("background")
|
||||
end
|
||||
|
||||
mm_texture.clear("header")
|
||||
mm_texture.clear("footer")
|
||||
engine.set_clouds(false)
|
||||
|
||||
mm_texture.set_generic("footer")
|
||||
mm_texture.set_generic("header")
|
||||
|
||||
if not have_bg and
|
||||
engine.setting_getbool("enable_clouds") then
|
||||
engine.set_clouds(true)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_texture.update_game(gamedetails)
|
||||
if mm_texture.gameid == gamedetails.id then
|
||||
return
|
||||
end
|
||||
|
||||
local have_bg = false
|
||||
local have_overlay = mm_texture.set_game("overlay",gamedetails)
|
||||
|
||||
if not have_overlay then
|
||||
have_bg = mm_texture.set_game("background",gamedetails)
|
||||
end
|
||||
|
||||
mm_texture.clear("header")
|
||||
mm_texture.clear("footer")
|
||||
engine.set_clouds(false)
|
||||
|
||||
if not have_bg and
|
||||
engine.setting_getbool("enable_clouds") then
|
||||
engine.set_clouds(true)
|
||||
end
|
||||
|
||||
mm_texture.set_game("footer",gamedetails)
|
||||
mm_texture.set_game("header",gamedetails)
|
||||
|
||||
mm_texture.gameid = gamedetails.id
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_texture.clear(identifier)
|
||||
engine.set_background(identifier,"")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_texture.set_generic(identifier)
|
||||
--try texture pack first
|
||||
if mm_texture.texturepack ~= nil then
|
||||
local path = mm_texture.texturepack .. DIR_DELIM .."menu_" ..
|
||||
identifier .. ".png"
|
||||
if engine.set_background(identifier,path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if mm_texture.defaulttexturedir ~= nil then
|
||||
local path = mm_texture.defaulttexturedir .. DIR_DELIM .."menu_" ..
|
||||
identifier .. ".png"
|
||||
if engine.set_background(identifier,path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function mm_texture.set_game(identifier,gamedetails)
|
||||
|
||||
if gamedetails == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
if mm_texture.texturepack ~= nil then
|
||||
local path = mm_texture.texturepack .. DIR_DELIM ..
|
||||
gamedetails.id .. "_menu_" .. identifier .. ".png"
|
||||
if engine.set_background(identifier,path) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local path = gamedetails.path .. DIR_DELIM .."menu" ..
|
||||
DIR_DELIM .. identifier .. ".png"
|
||||
if engine.set_background(identifier,path) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
1130
builtin/modmgr.lua
Normal file
615
builtin/modstore.lua
Normal file
@@ -0,0 +1,615 @@
|
||||
--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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--modstore implementation
|
||||
modstore = {}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] init
|
||||
function modstore.init()
|
||||
modstore.tabnames = {}
|
||||
|
||||
table.insert(modstore.tabnames,"dialog_modstore_unsorted")
|
||||
table.insert(modstore.tabnames,"dialog_modstore_search")
|
||||
|
||||
modstore.modsperpage = 5
|
||||
|
||||
modstore.basetexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
|
||||
DIR_DELIM .. "pack" .. DIR_DELIM
|
||||
|
||||
modstore.lastmodtitle = ""
|
||||
modstore.last_search = ""
|
||||
|
||||
modstore.searchlist = filterlist.create(
|
||||
function()
|
||||
if modstore.modlist_unsorted ~= nil and
|
||||
modstore.modlist_unsorted.data ~= nil then
|
||||
return modstore.modlist_unsorted.data
|
||||
end
|
||||
return {}
|
||||
end,
|
||||
function(element,modid)
|
||||
if element.id == modid then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end, --compare fct
|
||||
nil, --uid match fct
|
||||
function(element,substring)
|
||||
if substring == nil or
|
||||
substring == "" then
|
||||
return false
|
||||
end
|
||||
substring = substring:upper()
|
||||
|
||||
if element.title ~= nil and
|
||||
element.title:upper():find(substring) ~= nil then
|
||||
return true
|
||||
end
|
||||
|
||||
if element.details ~= nil and
|
||||
element.details.author ~= nil and
|
||||
element.details.author:upper():find(substring) ~= nil then
|
||||
return true
|
||||
end
|
||||
|
||||
if element.details ~= nil and
|
||||
element.details.description ~= nil and
|
||||
element.details.description:upper():find(substring) ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end --filter fct
|
||||
)
|
||||
|
||||
modstore.current_list = nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] nametoindex
|
||||
function modstore.nametoindex(name)
|
||||
|
||||
for i=1,#modstore.tabnames,1 do
|
||||
if modstore.tabnames[i] == name then
|
||||
return i
|
||||
end
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] getsuccessfuldialog
|
||||
function modstore.getsuccessfuldialog()
|
||||
local retval = ""
|
||||
retval = retval .. "size[6,2]"
|
||||
if modstore.lastmodentry ~= nil then
|
||||
retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]"
|
||||
retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]"
|
||||
|
||||
|
||||
retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]"
|
||||
retval = retval .. "label[3,0.75;" .. engine.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]"
|
||||
|
||||
end
|
||||
retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]"
|
||||
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] gettab
|
||||
function modstore.gettab(tabname)
|
||||
local retval = ""
|
||||
|
||||
local is_modstore_tab = false
|
||||
|
||||
if tabname == "dialog_modstore_unsorted" then
|
||||
modstore.modsperpage = 5
|
||||
retval = modstore.getmodlist(modstore.modlist_unsorted)
|
||||
is_modstore_tab = true
|
||||
end
|
||||
|
||||
if tabname == "dialog_modstore_search" then
|
||||
retval = modstore.getsearchpage()
|
||||
is_modstore_tab = true
|
||||
end
|
||||
|
||||
if is_modstore_tab then
|
||||
return modstore.tabheader(tabname) .. retval
|
||||
end
|
||||
|
||||
if tabname == "modstore_mod_installed" then
|
||||
return modstore.getsuccessfuldialog()
|
||||
end
|
||||
|
||||
if tabname == "modstore_downloading" then
|
||||
return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") ..
|
||||
" " .. modstore.lastmodtitle .. " " ..
|
||||
fgettext("please wait...") .. "]"
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] tabheader
|
||||
function modstore.tabheader(tabname)
|
||||
local retval = "size[12,10.25]"
|
||||
retval = retval .. "tabheader[-0.3,-0.99;modstore_tab;" ..
|
||||
"Unsorted,Search;" ..
|
||||
modstore.nametoindex(tabname) .. ";true;false]" ..
|
||||
"button[4,9.9;4,0.5;btn_modstore_close;" ..
|
||||
fgettext("Close modstore") .. "]"
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] handle_buttons
|
||||
function modstore.handle_buttons(current_tab,fields)
|
||||
|
||||
if fields["modstore_tab"] then
|
||||
local index = tonumber(fields["modstore_tab"])
|
||||
|
||||
if index > 0 and
|
||||
index <= #modstore.tabnames then
|
||||
if modstore.tabnames[index] == "dialog_modstore_search" then
|
||||
filterlist.set_filtercriteria(modstore.searchlist,modstore.last_search)
|
||||
filterlist.refresh(modstore.searchlist)
|
||||
modstore.modsperpage = 4
|
||||
modstore.currentlist = {
|
||||
page = 0,
|
||||
pagecount =
|
||||
math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
|
||||
data = filterlist.get_list(modstore.searchlist),
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
current_tab = modstore.tabnames[index],
|
||||
is_dialog = true,
|
||||
show_buttons = false
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if fields["btn_modstore_page_up"] then
|
||||
if modstore.current_list ~= nil and modstore.current_list.page > 0 then
|
||||
modstore.current_list.page = modstore.current_list.page - 1
|
||||
end
|
||||
end
|
||||
|
||||
if fields["btn_modstore_page_down"] then
|
||||
if modstore.current_list ~= nil and
|
||||
modstore.current_list.page <modstore.current_list.pagecount-1 then
|
||||
modstore.current_list.page = modstore.current_list.page +1
|
||||
end
|
||||
end
|
||||
|
||||
if fields["btn_hidden_close_download"] ~= nil then
|
||||
if fields["btn_hidden_close_download"].successfull then
|
||||
modstore.lastmodentry = fields["btn_hidden_close_download"]
|
||||
return {
|
||||
current_tab = "modstore_mod_installed",
|
||||
is_dialog = true,
|
||||
show_buttons = false
|
||||
}
|
||||
else
|
||||
modstore.lastmodtitle = ""
|
||||
return {
|
||||
current_tab = modstore.tabnames[1],
|
||||
is_dialog = true,
|
||||
show_buttons = false
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if fields["btn_confirm_mod_successfull"] then
|
||||
modstore.lastmodentry = nil
|
||||
modstore.lastmodtitle = ""
|
||||
return {
|
||||
current_tab = modstore.tabnames[1],
|
||||
is_dialog = true,
|
||||
show_buttons = false
|
||||
}
|
||||
end
|
||||
|
||||
if fields["btn_modstore_search"] or
|
||||
(fields["key_enter"] and fields["te_modstore_search"] ~= nil) then
|
||||
modstore.last_search = fields["te_modstore_search"]
|
||||
filterlist.set_filtercriteria(modstore.searchlist,fields["te_modstore_search"])
|
||||
filterlist.refresh(modstore.searchlist)
|
||||
modstore.currentlist = {
|
||||
page = 0,
|
||||
pagecount = math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
|
||||
data = filterlist.get_list(modstore.searchlist),
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
if fields["btn_modstore_close"] then
|
||||
return {
|
||||
is_dialog = false,
|
||||
show_buttons = true,
|
||||
current_tab = engine.setting_get("main_menu_tab")
|
||||
}
|
||||
end
|
||||
|
||||
for key,value in pairs(fields) do
|
||||
local foundat = key:find("btn_install_mod_")
|
||||
if ( foundat == 1) then
|
||||
local modid = tonumber(key:sub(17))
|
||||
for i=1,#modstore.modlist_unsorted.data,1 do
|
||||
if modstore.modlist_unsorted.data[i].id == modid then
|
||||
local moddetails = modstore.modlist_unsorted.data[i].details
|
||||
|
||||
if modstore.lastmodtitle ~= "" then
|
||||
modstore.lastmodtitle = modstore.lastmodtitle .. ", "
|
||||
end
|
||||
|
||||
modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title
|
||||
|
||||
engine.handle_async(
|
||||
function(param)
|
||||
|
||||
local fullurl = engine.setting_get("modstore_download_url") ..
|
||||
param.moddetails.download_url
|
||||
|
||||
if param.version ~= nil then
|
||||
local found = false
|
||||
for i=1,#param.moddetails.versions, 1 do
|
||||
if param.moddetails.versions[i].date:sub(1,10) == param.version then
|
||||
fullurl = engine.setting_get("modstore_download_url") ..
|
||||
param.moddetails.versions[i].download_url
|
||||
found = true
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
return {
|
||||
moddetails = param.moddetails,
|
||||
successfull = false
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if engine.download_file(fullurl,param.filename) then
|
||||
return {
|
||||
texturename = param.texturename,
|
||||
moddetails = param.moddetails,
|
||||
filename = param.filename,
|
||||
successfull = true
|
||||
}
|
||||
else
|
||||
return {
|
||||
modtitle = param.title,
|
||||
successfull = false
|
||||
}
|
||||
end
|
||||
end,
|
||||
{
|
||||
moddetails = moddetails,
|
||||
version = fields["dd_version" .. modid],
|
||||
filename = os.tempfolder() .. "_MODNAME_" .. moddetails.basename .. ".zip",
|
||||
texturename = modstore.modlist_unsorted.data[i].texturename
|
||||
},
|
||||
function(result)
|
||||
if result.successfull then
|
||||
modmgr.installmod(result.filename,result.moddetails.basename)
|
||||
os.remove(result.filename)
|
||||
else
|
||||
gamedata.errormessage = "Failed to download " .. result.moddetails.title
|
||||
end
|
||||
|
||||
if gamedata.errormessage == nil then
|
||||
engine.button_handler({btn_hidden_close_download=result})
|
||||
else
|
||||
engine.button_handler({btn_hidden_close_download={successfull=false}})
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return {
|
||||
current_tab = "modstore_downloading",
|
||||
is_dialog = true,
|
||||
show_buttons = false,
|
||||
ignore_menu_quit = true
|
||||
}
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] update_modlist
|
||||
function modstore.update_modlist()
|
||||
modstore.modlist_unsorted = {}
|
||||
modstore.modlist_unsorted.data = {}
|
||||
modstore.modlist_unsorted.pagecount = 1
|
||||
modstore.modlist_unsorted.page = 0
|
||||
|
||||
engine.handle_async(
|
||||
function(param)
|
||||
return engine.get_modstore_list()
|
||||
end,
|
||||
nil,
|
||||
function(result)
|
||||
if result ~= nil then
|
||||
modstore.modlist_unsorted = {}
|
||||
modstore.modlist_unsorted.data = result
|
||||
|
||||
if modstore.modlist_unsorted.data ~= nil then
|
||||
modstore.modlist_unsorted.pagecount =
|
||||
math.ceil((#modstore.modlist_unsorted.data / modstore.modsperpage))
|
||||
else
|
||||
modstore.modlist_unsorted.data = {}
|
||||
modstore.modlist_unsorted.pagecount = 1
|
||||
end
|
||||
modstore.modlist_unsorted.page = 0
|
||||
modstore.fetchdetails()
|
||||
engine.event_handler("Refresh")
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] fetchdetails
|
||||
function modstore.fetchdetails()
|
||||
|
||||
for i=1,#modstore.modlist_unsorted.data,1 do
|
||||
engine.handle_async(
|
||||
function(param)
|
||||
param.details = engine.get_modstore_details(tostring(param.modid))
|
||||
return param
|
||||
end,
|
||||
{
|
||||
modid=modstore.modlist_unsorted.data[i].id,
|
||||
listindex=i
|
||||
},
|
||||
function(result)
|
||||
if result ~= nil and
|
||||
modstore.modlist_unsorted ~= nil
|
||||
and modstore.modlist_unsorted.data ~= nil and
|
||||
modstore.modlist_unsorted.data[result.listindex] ~= nil and
|
||||
modstore.modlist_unsorted.data[result.listindex].id ~= nil then
|
||||
|
||||
modstore.modlist_unsorted.data[result.listindex].details = result.details
|
||||
engine.event_handler("Refresh")
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#modstore] getscreenshot
|
||||
function modstore.getscreenshot(ypos,listentry)
|
||||
|
||||
if listentry.details ~= nil and
|
||||
(listentry.details.screenshot_url == nil or
|
||||
listentry.details.screenshot_url == "") then
|
||||
|
||||
if listentry.texturename == nil then
|
||||
listentry.texturename = modstore.basetexturedir .. "no_screenshot.png"
|
||||
end
|
||||
|
||||
return "image[0,".. ypos .. ";3,2;" ..
|
||||
engine.formspec_escape(listentry.texturename) .. "]"
|
||||
end
|
||||
|
||||
if listentry.details ~= nil and
|
||||
listentry.texturename == nil then
|
||||
--make sure we don't download multiple times
|
||||
listentry.texturename = "in progress"
|
||||
|
||||
--prepare url and filename
|
||||
local fullurl = engine.setting_get("modstore_download_url") ..
|
||||
listentry.details.screenshot_url
|
||||
local filename = os.tempfolder() .. "_MID_" .. listentry.id
|
||||
|
||||
--trigger download
|
||||
engine.handle_async(
|
||||
--first param is downloadfct
|
||||
function(param)
|
||||
param.successfull = engine.download_file(param.fullurl,param.filename)
|
||||
return param
|
||||
end,
|
||||
--second parameter is data passed to async job
|
||||
{
|
||||
fullurl = fullurl,
|
||||
filename = filename,
|
||||
modid = listentry.id
|
||||
},
|
||||
--integrate result to raw list
|
||||
function(result)
|
||||
if result.successfull then
|
||||
local found = false
|
||||
for i=1,#modstore.modlist_unsorted.data,1 do
|
||||
if modstore.modlist_unsorted.data[i].id == result.modid then
|
||||
found = true
|
||||
modstore.modlist_unsorted.data[i].texturename = result.filename
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
engine.event_handler("Refresh")
|
||||
else
|
||||
engine.log("error","got screenshot but didn't find matching mod: " .. result.modid)
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
if listentry.texturename ~= nil and
|
||||
listentry.texturename ~= "in progress" then
|
||||
return "image[0,".. ypos .. ";3,2;" ..
|
||||
engine.formspec_escape(listentry.texturename) .. "]"
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--@function [parent=#modstore] getshortmodinfo
|
||||
function modstore.getshortmodinfo(ypos,listentry,details)
|
||||
local retval = ""
|
||||
|
||||
retval = retval .. "box[0," .. ypos .. ";11.4,1.75;#FFFFFF]"
|
||||
|
||||
--screenshot
|
||||
retval = retval .. modstore.getscreenshot(ypos,listentry)
|
||||
|
||||
--title + author
|
||||
retval = retval .."label[2.75," .. ypos .. ";" ..
|
||||
engine.formspec_escape(details.title) .. " (" .. details.author .. ")]"
|
||||
|
||||
--description
|
||||
local descriptiony = ypos + 0.5
|
||||
retval = retval .. "textarea[3," .. descriptiony .. ";6.5,1.55;;" ..
|
||||
engine.formspec_escape(details.description) .. ";]"
|
||||
|
||||
--rating
|
||||
local ratingy = ypos
|
||||
retval = retval .."label[7," .. ratingy .. ";" ..
|
||||
fgettext("Rating") .. ":]"
|
||||
retval = retval .. "label[8.7," .. ratingy .. ";" .. details.rating .."]"
|
||||
|
||||
--versions (IMPORTANT has to be defined AFTER rating)
|
||||
if details.versions ~= nil and
|
||||
#details.versions > 1 then
|
||||
local versiony = ypos + 0.05
|
||||
retval = retval .. "dropdown[9.1," .. versiony .. ";2.48,0.25;dd_version" .. details.id .. ";"
|
||||
local versions = ""
|
||||
for i=1,#details.versions , 1 do
|
||||
if versions ~= "" then
|
||||
versions = versions .. ","
|
||||
end
|
||||
|
||||
versions = versions .. details.versions[i].date:sub(1,10)
|
||||
end
|
||||
retval = retval .. versions .. ";1]"
|
||||
end
|
||||
|
||||
if details.basename then
|
||||
--install button
|
||||
local buttony = ypos + 1.2
|
||||
retval = retval .."button[9.1," .. buttony .. ";2.5,0.5;btn_install_mod_" .. details.id .. ";"
|
||||
|
||||
if modmgr.mod_exists(details.basename) then
|
||||
retval = retval .. fgettext("re-Install") .."]"
|
||||
else
|
||||
retval = retval .. fgettext("Install") .."]"
|
||||
end
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--@function [parent=#modstore] getmodlist
|
||||
function modstore.getmodlist(list,yoffset)
|
||||
|
||||
modstore.current_list = list
|
||||
|
||||
if #list.data == 0 then
|
||||
return ""
|
||||
end
|
||||
|
||||
if yoffset == nil then
|
||||
yoffset = 0
|
||||
end
|
||||
|
||||
local scrollbar = ""
|
||||
scrollbar = scrollbar .. "label[0.1,9.5;"
|
||||
.. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
|
||||
scrollbar = scrollbar .. "box[11.6," .. (yoffset + 0.35) .. ";0.28,"
|
||||
.. (8.6 - yoffset) .. ";#000000]"
|
||||
local scrollbarpos = (yoffset + 0.75) +
|
||||
((7.7 -yoffset)/(list.pagecount-1)) * list.page
|
||||
scrollbar = scrollbar .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;#32CD32]"
|
||||
scrollbar = scrollbar .. "button[11.6," .. (yoffset + (0.3))
|
||||
.. ";0.5,0.5;btn_modstore_page_up;^]"
|
||||
scrollbar = scrollbar .. "button[11.6," .. 9.0
|
||||
.. ";0.5,0.5;btn_modstore_page_down;v]"
|
||||
|
||||
local retval = ""
|
||||
|
||||
local endmod = (list.page * modstore.modsperpage) + modstore.modsperpage
|
||||
|
||||
if (endmod > #list.data) then
|
||||
endmod = #list.data
|
||||
end
|
||||
|
||||
for i=(list.page * modstore.modsperpage) +1, endmod, 1 do
|
||||
--getmoddetails
|
||||
local details = list.data[i].details
|
||||
|
||||
if details == nil then
|
||||
details = {}
|
||||
details.title = list.data[i].title
|
||||
details.author = ""
|
||||
details.rating = -1
|
||||
details.description = ""
|
||||
end
|
||||
|
||||
if details ~= nil then
|
||||
local screenshot_ypos =
|
||||
yoffset +(i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
|
||||
|
||||
retval = retval .. modstore.getshortmodinfo(screenshot_ypos,
|
||||
list.data[i],
|
||||
details)
|
||||
end
|
||||
end
|
||||
|
||||
return retval .. scrollbar
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--@function [parent=#modstore] getsearchpage
|
||||
function modstore.getsearchpage()
|
||||
local retval = ""
|
||||
local search = ""
|
||||
|
||||
if modstore.last_search ~= nil then
|
||||
search = modstore.last_search
|
||||
end
|
||||
|
||||
retval = retval ..
|
||||
"button[9.5,0.2;2.5,0.5;btn_modstore_search;".. fgettext("Search") .. "]" ..
|
||||
"field[0.5,0.5;9,0.5;te_modstore_search;;" .. search .. "]"
|
||||
|
||||
|
||||
--show 4 mods only
|
||||
modstore.modsperpage = 4
|
||||
retval = retval ..
|
||||
modstore.getmodlist(
|
||||
modstore.currentlist,
|
||||
1.75)
|
||||
|
||||
return retval;
|
||||
end
|
||||
|
||||
@@ -178,7 +178,7 @@ function minetest.deserialize(sdata)
|
||||
if okay then
|
||||
return results
|
||||
end
|
||||
print('error:'.. results)
|
||||
minetest.log('error', 'minetest.deserialize(): '.. results)
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
146
builtin/vector.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
vector = {}
|
||||
|
||||
local function assert_vector(v)
|
||||
assert(type(v) == "table" and v.x and v.y and v.z, "Invalid vector")
|
||||
end
|
||||
|
||||
function vector.new(a, b, c)
|
||||
if type(a) == "table" then
|
||||
assert(a.x and a.y and a.z, "Invalid vector passed to vector.new()")
|
||||
return {x=a.x, y=a.y, z=a.z}
|
||||
elseif a then
|
||||
assert(b and c, "Invalid arguments for vector.new()")
|
||||
return {x=a, y=b, z=c}
|
||||
end
|
||||
return {x=0, y=0, z=0}
|
||||
end
|
||||
|
||||
function vector.equals(a, b)
|
||||
assert_vector(a)
|
||||
assert_vector(b)
|
||||
return a.x == b.x and
|
||||
a.y == b.y and
|
||||
a.z == b.z
|
||||
end
|
||||
|
||||
function vector.length(v)
|
||||
assert_vector(v)
|
||||
return math.hypot(v.x, math.hypot(v.y, v.z))
|
||||
end
|
||||
|
||||
function vector.normalize(v)
|
||||
assert_vector(v)
|
||||
local len = vector.length(v)
|
||||
if len == 0 then
|
||||
return {x=0, y=0, z=0}
|
||||
else
|
||||
return vector.divide(v, len)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.round(v)
|
||||
assert_vector(v)
|
||||
return {
|
||||
x = math.floor(v.x + 0.5),
|
||||
y = math.floor(v.y + 0.5),
|
||||
z = math.floor(v.z + 0.5)
|
||||
}
|
||||
end
|
||||
|
||||
function vector.distance(a, b)
|
||||
assert_vector(a)
|
||||
assert_vector(b)
|
||||
local x = a.x - b.x
|
||||
local y = a.y - b.y
|
||||
local z = a.z - b.z
|
||||
return math.hypot(x, math.hypot(y, z))
|
||||
end
|
||||
|
||||
function vector.direction(pos1, pos2)
|
||||
assert_vector(pos1)
|
||||
assert_vector(pos2)
|
||||
local x_raw = pos2.x - pos1.x
|
||||
local y_raw = pos2.y - pos1.y
|
||||
local z_raw = pos2.z - pos1.z
|
||||
local x_abs = math.abs(x_raw)
|
||||
local y_abs = math.abs(y_raw)
|
||||
local z_abs = math.abs(z_raw)
|
||||
if x_abs >= y_abs and
|
||||
x_abs >= z_abs then
|
||||
y_raw = y_raw * (1 / x_abs)
|
||||
z_raw = z_raw * (1 / x_abs)
|
||||
x_raw = x_raw / x_abs
|
||||
end
|
||||
if y_abs >= x_abs and
|
||||
y_abs >= z_abs then
|
||||
x_raw = x_raw * (1 / y_abs)
|
||||
z_raw = z_raw * (1 / y_abs)
|
||||
y_raw = y_raw / y_abs
|
||||
end
|
||||
if z_abs >= y_abs and
|
||||
z_abs >= x_abs then
|
||||
x_raw = x_raw * (1 / z_abs)
|
||||
y_raw = y_raw * (1 / z_abs)
|
||||
z_raw = z_raw / z_abs
|
||||
end
|
||||
return {x=x_raw, y=y_raw, z=z_raw}
|
||||
end
|
||||
|
||||
|
||||
function vector.add(a, b)
|
||||
assert_vector(a)
|
||||
if type(b) == "table" then
|
||||
assert_vector(b)
|
||||
return {x = a.x + b.x,
|
||||
y = a.y + b.y,
|
||||
z = a.z + b.z}
|
||||
else
|
||||
return {x = a.x + b,
|
||||
y = a.y + b,
|
||||
z = a.z + b}
|
||||
end
|
||||
end
|
||||
|
||||
function vector.subtract(a, b)
|
||||
assert_vector(a)
|
||||
if type(b) == "table" then
|
||||
assert_vector(b)
|
||||
return {x = a.x - b.x,
|
||||
y = a.y - b.y,
|
||||
z = a.z - b.z}
|
||||
else
|
||||
return {x = a.x - b,
|
||||
y = a.y - b,
|
||||
z = a.z - b}
|
||||
end
|
||||
end
|
||||
|
||||
function vector.multiply(a, b)
|
||||
assert_vector(a)
|
||||
if type(b) == "table" then
|
||||
assert_vector(b)
|
||||
return {x = a.x * b.x,
|
||||
y = a.y * b.y,
|
||||
z = a.z * b.z}
|
||||
else
|
||||
return {x = a.x * b,
|
||||
y = a.y * b,
|
||||
z = a.z * b}
|
||||
end
|
||||
end
|
||||
|
||||
function vector.divide(a, b)
|
||||
assert_vector(a)
|
||||
if type(b) == "table" then
|
||||
assert_vector(b)
|
||||
return {x = a.x / b.x,
|
||||
y = a.y / b.y,
|
||||
z = a.z / b.z}
|
||||
else
|
||||
return {x = a.x / b,
|
||||
y = a.y / b,
|
||||
z = a.z / b}
|
||||
end
|
||||
end
|
||||
|
||||
103
builtin/voxelarea.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
VoxelArea = {
|
||||
MinEdge = {x=1, y=1, z=1},
|
||||
MaxEdge = {x=0, y=0, z=0},
|
||||
ystride = 0,
|
||||
zstride = 0,
|
||||
}
|
||||
|
||||
function VoxelArea:new(o)
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
|
||||
local e = o:getExtent()
|
||||
o.ystride = e.x
|
||||
o.zstride = e.x * e.y
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
function VoxelArea:getExtent()
|
||||
return {
|
||||
x = self.MaxEdge.x - self.MinEdge.x + 1,
|
||||
y = self.MaxEdge.y - self.MinEdge.y + 1,
|
||||
z = self.MaxEdge.z - self.MinEdge.z + 1,
|
||||
}
|
||||
end
|
||||
|
||||
function VoxelArea:getVolume()
|
||||
local e = self:getExtent()
|
||||
return e.x * e.y * e.z
|
||||
end
|
||||
|
||||
function VoxelArea:index(x, y, z)
|
||||
local i = (z - self.MinEdge.z) * self.zstride +
|
||||
(y - self.MinEdge.y) * self.ystride +
|
||||
(x - self.MinEdge.x) + 1
|
||||
return math.floor(i)
|
||||
end
|
||||
|
||||
function VoxelArea:indexp(p)
|
||||
local i = (p.z - self.MinEdge.z) * self.zstride +
|
||||
(p.y - self.MinEdge.y) * self.ystride +
|
||||
(p.x - self.MinEdge.x) + 1
|
||||
return math.floor(i)
|
||||
end
|
||||
|
||||
function VoxelArea:position(i)
|
||||
local p = {}
|
||||
|
||||
i = i - 1
|
||||
|
||||
p.z = math.floor(i / self.zstride) + self.MinEdge.z
|
||||
i = i % self.zstride
|
||||
|
||||
p.y = math.floor(i / self.ystride) + self.MinEdge.y
|
||||
i = i % self.ystride
|
||||
|
||||
p.x = math.floor(i) + self.MinEdge.x
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
function VoxelArea:contains(x, y, z)
|
||||
return (x >= self.MinEdge.x) and (x <= self.MaxEdge.x) and
|
||||
(y >= self.MinEdge.y) and (y <= self.MaxEdge.y) and
|
||||
(z >= self.MinEdge.z) and (z <= self.MaxEdge.z)
|
||||
end
|
||||
|
||||
function VoxelArea:containsp(p)
|
||||
return (p.x >= self.MinEdge.x) and (p.x <= self.MaxEdge.x) and
|
||||
(p.y >= self.MinEdge.y) and (p.y <= self.MaxEdge.y) and
|
||||
(p.z >= self.MinEdge.z) and (p.z <= self.MaxEdge.z)
|
||||
end
|
||||
|
||||
function VoxelArea:containsi(i)
|
||||
return (i >= 1) and (i <= self:getVolume())
|
||||
end
|
||||
|
||||
function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz)
|
||||
local i = self:index(minx, miny, minz) - 1
|
||||
local last = self:index(maxx, maxy, maxz)
|
||||
local ystride = self.ystride
|
||||
local zstride = self.zstride
|
||||
local yoff = (last+1) % ystride
|
||||
local zoff = (last+1) % zstride
|
||||
local ystridediff = (i - last) % ystride
|
||||
local zstridediff = (i - last) % zstride
|
||||
return function()
|
||||
i = i + 1
|
||||
if i % zstride == zoff then
|
||||
i = i + zstridediff
|
||||
elseif i % ystride == yoff then
|
||||
i = i + ystridediff
|
||||
end
|
||||
if i <= last then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function VoxelArea:iterp(minp, maxp)
|
||||
return self:iter(minp.x, minp.y, minp.z, maxp.x, maxp.y, maxp.z)
|
||||
end
|
||||
71
client/shaders/alpha_shader/opengl_fragment.glsl
Normal file
@@ -0,0 +1,71 @@
|
||||
uniform sampler2D baseTexture;
|
||||
uniform sampler2D normalTexture;
|
||||
uniform sampler2D useNormalmap;
|
||||
|
||||
uniform vec4 skyBgColor;
|
||||
uniform float fogDistance;
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
varying vec3 tsEyeVec;
|
||||
#endif
|
||||
|
||||
const float e = 2.718281828459;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec3 color;
|
||||
vec2 uv = gl_TexCoord[0].st;
|
||||
|
||||
#ifdef USE_NORMALMAPS
|
||||
float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
float height;
|
||||
vec2 tsEye = vec2(tsEyeVec.x,-tsEyeVec.y);
|
||||
|
||||
if (use_normalmap > 0.0) {
|
||||
float map_height = texture2D(normalTexture, uv).a;
|
||||
if (map_height < 1.0){
|
||||
float height = PARALLAX_OCCLUSION_SCALE * map_height - PARALLAX_OCCLUSION_BIAS;
|
||||
uv = uv + height * tsEye;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BUMPMAPPING
|
||||
if (use_normalmap > 0.0) {
|
||||
vec3 base = texture2D(baseTexture, uv).rgb;
|
||||
vec3 vVec = normalize(eyeVec);
|
||||
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
|
||||
vec3 R = reflect(-vVec, bump);
|
||||
vec3 lVec = normalize(vVec);
|
||||
float diffuse = max(dot(lVec, bump), 0.0);
|
||||
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
|
||||
color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse;
|
||||
} else {
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
}
|
||||
#else
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
#endif
|
||||
|
||||
float alpha = texture2D(baseTexture, uv).a;
|
||||
vec4 col = vec4(color.r, color.g, color.b, alpha);
|
||||
col *= gl_Color;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / e;
|
||||
col.g = 1.0 - exp(1.0 - col.g) / e;
|
||||
col.b = 1.0 - exp(1.0 - col.b) / e;
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
col = mix(col, skyBgColor, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
|
||||
}
|
||||
102
client/shaders/alpha_shader/opengl_vertex.glsl
Normal file
@@ -0,0 +1,102 @@
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
varying vec3 tsEyeVec;
|
||||
#endif
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = mWorldViewProj * gl_Vertex;
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
vec3 normal,tangent,binormal;
|
||||
normal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
|
||||
if (gl_Normal.x > 0.5) {
|
||||
// 1.0, 0.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, -1.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
} else if (gl_Normal.x < -0.5) {
|
||||
// -1.0, 0.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
} else if (gl_Normal.y > 0.5) {
|
||||
// 0.0, 1.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
|
||||
} else if (gl_Normal.y < -0.5) {
|
||||
// 0.0, -1.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
|
||||
} else if (gl_Normal.z > 0.5) {
|
||||
// 0.0, 0.0, 1.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
} else if (gl_Normal.z < -0.5) {
|
||||
// 0.0, 0.0, -1.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3(-1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
}
|
||||
|
||||
mat3 tbnMatrix = mat3( tangent.x, binormal.x, normal.x,
|
||||
tangent.y, binormal.y, normal.y,
|
||||
tangent.z, binormal.z, normal.z);
|
||||
|
||||
tsEyeVec = normalize(eyeVec * tbnMatrix);
|
||||
#endif
|
||||
|
||||
vec4 color;
|
||||
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
float day = gl_Color.r;
|
||||
float night = gl_Color.g;
|
||||
float light_source = gl_Color.b;
|
||||
|
||||
/*color.r = mix(night, day, dayNightRatio);
|
||||
color.g = color.r;
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 2.5; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
b += (day - night) / 13.0;
|
||||
rg -= (day - night) / 13.0;
|
||||
|
||||
// Emphase blue a bit in darker places
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
|
||||
|
||||
// Artificial light is yellow-ish
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = clamp(rg,0.0,1.0);
|
||||
color.g = clamp(rg,0.0,1.0);
|
||||
color.b = clamp(b,0.0,1.0);
|
||||
|
||||
// Make sides and bottom darker than the top
|
||||
color = color * color; // SRGB -> Linear
|
||||
if(gl_Normal.y <= 0.5)
|
||||
color *= 0.6;
|
||||
//color *= 0.7;
|
||||
color = sqrt(color); // Linear -> SRGB
|
||||
|
||||
color.a = gl_Color.a;
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
}
|
||||
54
client/shaders/leaves_shader/opengl_fragment.glsl
Normal file
@@ -0,0 +1,54 @@
|
||||
uniform sampler2D baseTexture;
|
||||
uniform sampler2D normalTexture;
|
||||
uniform sampler2D useNormalmap;
|
||||
|
||||
uniform vec4 skyBgColor;
|
||||
uniform float fogDistance;
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
const float e = 2.718281828459;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec3 color;
|
||||
vec2 uv = gl_TexCoord[0].st;
|
||||
|
||||
#ifdef USE_NORMALMAPS
|
||||
float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BUMPMAPPING
|
||||
if (use_normalmap > 0.0) {
|
||||
vec3 base = texture2D(baseTexture, uv).rgb;
|
||||
vec3 vVec = normalize(eyeVec);
|
||||
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
|
||||
vec3 R = reflect(-vVec, bump);
|
||||
vec3 lVec = normalize(vVec);
|
||||
float diffuse = max(dot(lVec, bump), 0.0);
|
||||
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
|
||||
color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse;
|
||||
} else {
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
}
|
||||
#else
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
#endif
|
||||
|
||||
float alpha = texture2D(baseTexture, uv).a;
|
||||
vec4 col = vec4(color.r, color.g, color.b, alpha);
|
||||
col *= gl_Color;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / e;
|
||||
col.g = 1.0 - exp(1.0 - col.g) / e;
|
||||
col.b = 1.0 - exp(1.0 - col.b) / e;
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
col = mix(col, skyBgColor, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
|
||||
}
|
||||
87
client/shaders/leaves_shader/opengl_vertex.glsl
Normal file
@@ -0,0 +1,87 @@
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
uniform float animationTimer;
|
||||
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
#ifdef ENABLE_WAVING_LEAVES
|
||||
float smoothCurve( float x ) {
|
||||
return x * x *( 3.0 - 2.0 * x );
|
||||
}
|
||||
float triangleWave( float x ) {
|
||||
return abs( fract( x + 0.5 ) * 2.0 - 1.0 );
|
||||
}
|
||||
float smoothTriangleWave( float x ) {
|
||||
return smoothCurve( triangleWave( x ) ) * 2.0 - 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
#ifdef ENABLE_WAVING_LEAVES
|
||||
vec4 pos = gl_Vertex;
|
||||
vec4 pos2 = mTransWorld*gl_Vertex;
|
||||
pos.x += (smoothTriangleWave(animationTimer*10.0 + pos2.x * 0.01 + pos2.z * 0.01) * 2.0 - 1.0) * 0.4;
|
||||
pos.y += (smoothTriangleWave(animationTimer*15.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.2;
|
||||
pos.z += (smoothTriangleWave(animationTimer*10.0 + pos2.x * -0.01 + pos2.z * -0.01) * 2.0 - 1.0) * 0.4;
|
||||
gl_Position = mWorldViewProj * pos;
|
||||
#else
|
||||
gl_Position = mWorldViewProj * gl_Vertex;
|
||||
#endif
|
||||
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
|
||||
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
|
||||
|
||||
vec4 color;
|
||||
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
float day = gl_Color.r;
|
||||
float night = gl_Color.g;
|
||||
float light_source = gl_Color.b;
|
||||
|
||||
/*color.r = mix(night, day, dayNightRatio);
|
||||
color.g = color.r;
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 2.5; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
b += (day - night) / 13.0;
|
||||
rg -= (day - night) / 13.0;
|
||||
|
||||
// Emphase blue a bit in darker places
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
|
||||
|
||||
// Artificial light is yellow-ish
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = clamp(rg,0.0,1.0);
|
||||
color.g = clamp(rg,0.0,1.0);
|
||||
color.b = clamp(b,0.0,1.0);
|
||||
|
||||
// Make sides and bottom darker than the top
|
||||
color = color * color; // SRGB -> Linear
|
||||
if(gl_Normal.y <= 0.5)
|
||||
color *= 0.6;
|
||||
//color *= 0.7;
|
||||
color = sqrt(color); // Linear -> SRGB
|
||||
|
||||
color.a = gl_Color.a;
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
}
|
||||
54
client/shaders/liquids_shader/opengl_fragment.glsl
Normal file
@@ -0,0 +1,54 @@
|
||||
uniform sampler2D baseTexture;
|
||||
uniform sampler2D normalTexture;
|
||||
uniform sampler2D useNormalmap;
|
||||
|
||||
uniform vec4 skyBgColor;
|
||||
uniform float fogDistance;
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
const float e = 2.718281828459;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec3 color;
|
||||
vec2 uv = gl_TexCoord[0].st;
|
||||
|
||||
#ifdef USE_NORMALMAPS
|
||||
float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BUMPMAPPING
|
||||
if (use_normalmap > 0.0) {
|
||||
vec3 base = texture2D(baseTexture, uv).rgb;
|
||||
vec3 vVec = normalize(eyeVec);
|
||||
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
|
||||
vec3 R = reflect(-vVec, bump);
|
||||
vec3 lVec = normalize(vVec);
|
||||
float diffuse = max(dot(vec3(-1.0, -0.4, 0.5), bump), 0.0);
|
||||
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
|
||||
color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse;
|
||||
} else {
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
}
|
||||
#else
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
#endif
|
||||
|
||||
float alpha = gl_Color.a;
|
||||
vec4 col = vec4(color.r, color.g, color.b, alpha);
|
||||
col *= gl_Color;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / e;
|
||||
col.g = 1.0 - exp(1.0 - col.g) / e;
|
||||
col.b = 1.0 - exp(1.0 - col.b) / e;
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
alpha = mix(alpha, 0.0, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
|
||||
}
|
||||
@@ -1,15 +1,27 @@
|
||||
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
uniform float animationTimer;
|
||||
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
#ifdef ENABLE_WAVING_WATER
|
||||
vec4 pos2 = gl_Vertex;
|
||||
pos2.y -= 2.0;
|
||||
pos2.y -= sin (pos2.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) * WATER_WAVE_HEIGHT
|
||||
+ sin ((pos2.z/WATER_WAVE_LENGTH + animationTimer * WATER_WAVE_SPEED * WATER_WAVE_LENGTH) / 7.0) * WATER_WAVE_HEIGHT;
|
||||
gl_Position = mWorldViewProj * pos2;
|
||||
#else
|
||||
gl_Position = mWorldViewProj * gl_Vertex;
|
||||
#endif
|
||||
|
||||
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
|
||||
vec4 color;
|
||||
@@ -24,7 +36,7 @@ void main(void)
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 1.0; // Make light sources brighter
|
||||
rg += light_source * 2.5; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
@@ -39,13 +51,13 @@ void main(void)
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = rg;
|
||||
color.g = rg;
|
||||
color.b = b;
|
||||
|
||||
color.r = clamp(rg,0.0,1.0);
|
||||
color.g = clamp(rg,0.0,1.0);
|
||||
color.b = clamp(b,0.0,1.0);
|
||||
color.a = gl_Color.a;
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
}
|
||||
1
client/shaders/plants_shader/base.txt
Normal file
@@ -0,0 +1 @@
|
||||
trans_alphach_ref
|
||||
54
client/shaders/plants_shader/opengl_fragment.glsl
Normal file
@@ -0,0 +1,54 @@
|
||||
uniform sampler2D baseTexture;
|
||||
uniform sampler2D normalTexture;
|
||||
uniform sampler2D useNormalmap;
|
||||
|
||||
uniform vec4 skyBgColor;
|
||||
uniform float fogDistance;
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
const float e = 2.718281828459;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec3 color;
|
||||
vec2 uv = gl_TexCoord[0].st;
|
||||
|
||||
#ifdef USE_NORMALMAPS
|
||||
float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BUMPMAPPING
|
||||
if (use_normalmap > 0.0) {
|
||||
vec3 base = texture2D(baseTexture, uv).rgb;
|
||||
vec3 vVec = normalize(eyeVec);
|
||||
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
|
||||
vec3 R = reflect(-vVec, bump);
|
||||
vec3 lVec = normalize(vVec);
|
||||
float diffuse = max(dot(lVec, bump), 0.0);
|
||||
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
|
||||
color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse;
|
||||
} else {
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
}
|
||||
#else
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
#endif
|
||||
|
||||
float alpha = texture2D(baseTexture, uv).a;
|
||||
vec4 col = vec4(color.r, color.g, color.b, alpha);
|
||||
col *= gl_Color;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / e;
|
||||
col.g = 1.0 - exp(1.0 - col.g) / e;
|
||||
col.b = 1.0 - exp(1.0 - col.b) / e;
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
col = mix(col, skyBgColor, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
|
||||
}
|
||||
@@ -1,16 +1,45 @@
|
||||
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
uniform float animationTimer;
|
||||
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
#ifdef ENABLE_WAVING_PLANTS
|
||||
float smoothCurve( float x ) {
|
||||
return x * x *( 3.0 - 2.0 * x );
|
||||
}
|
||||
float triangleWave( float x ) {
|
||||
return abs( fract( x + 0.5 ) * 2.0 - 1.0 );
|
||||
}
|
||||
float smoothTriangleWave( float x ) {
|
||||
return smoothCurve( triangleWave( x ) ) * 2.0 - 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
#ifdef ENABLE_WAVING_PLANTS
|
||||
vec4 pos = gl_Vertex;
|
||||
vec4 pos2 = mTransWorld * gl_Vertex;
|
||||
if (gl_TexCoord[0].y < 0.05) {
|
||||
pos.x += (smoothTriangleWave(animationTimer * 20.0 + pos2.x * 0.1 + pos2.z * 0.1) * 2.0 - 1.0) * 0.8;
|
||||
pos.y -= (smoothTriangleWave(animationTimer * 10.0 + pos2.x * -0.5 + pos2.z * -0.5) * 2.0 - 1.0) * 0.4;
|
||||
}
|
||||
gl_Position = mWorldViewProj * pos;
|
||||
#else
|
||||
gl_Position = mWorldViewProj * gl_Vertex;
|
||||
#endif
|
||||
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
|
||||
|
||||
vec4 color;
|
||||
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
@@ -24,7 +53,7 @@ void main(void)
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 1.0; // Make light sources brighter
|
||||
rg += light_source * 2.5; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
@@ -39,9 +68,9 @@ void main(void)
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = rg;
|
||||
color.g = rg;
|
||||
color.b = b;
|
||||
color.r = clamp(rg,0.0,1.0);
|
||||
color.g = clamp(rg,0.0,1.0);
|
||||
color.b = clamp(b,0.0,1.0);
|
||||
|
||||
// Make sides and bottom darker than the top
|
||||
color = color * color; // SRGB -> Linear
|
||||
@@ -54,5 +83,4 @@ void main(void)
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
}
|
||||
1
client/shaders/solids_shader/base.txt
Normal file
@@ -0,0 +1 @@
|
||||
trans_alphach_ref
|
||||
90
client/shaders/solids_shader/opengl_fragment.glsl
Normal file
@@ -0,0 +1,90 @@
|
||||
uniform sampler2D baseTexture;
|
||||
uniform sampler2D normalTexture;
|
||||
uniform sampler2D useNormalmap;
|
||||
|
||||
uniform vec4 skyBgColor;
|
||||
uniform float fogDistance;
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
varying vec3 tsEyeVec;
|
||||
#endif
|
||||
|
||||
const float e = 2.718281828459;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec3 color;
|
||||
vec2 uv = gl_TexCoord[0].st;
|
||||
|
||||
#ifdef USE_NORMALMAPS
|
||||
float use_normalmap = texture2D(useNormalmap,vec2(1.0,1.0)).r;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
float height;
|
||||
vec2 tsEye = vec2(tsEyeVec.x,-tsEyeVec.y);
|
||||
|
||||
if (use_normalmap > 0.0) {
|
||||
float map_height = texture2D(normalTexture, uv).a;
|
||||
if (map_height < 1.0){
|
||||
float height = PARALLAX_OCCLUSION_SCALE * map_height - PARALLAX_OCCLUSION_BIAS;
|
||||
uv = uv + height * tsEye;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Steep parallax code, for future use
|
||||
if ((parallaxMappingMode == 2.0) && (use_normalmap > 0.0)) {
|
||||
const float numSteps = 40.0;
|
||||
float height = 1.0;
|
||||
float step = 1.0 / numSteps;
|
||||
vec4 NB = texture2D(normalTexture, uv);
|
||||
vec2 delta = tsEye * parallaxMappingScale / numSteps;
|
||||
for (float i = 0.0; i < numSteps; i++) {
|
||||
if (NB.a < height) {
|
||||
height -= step;
|
||||
uv += delta;
|
||||
NB = texture2D(normalTexture, uv);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef ENABLE_BUMPMAPPING
|
||||
if (use_normalmap > 0.0) {
|
||||
vec3 base = texture2D(baseTexture, uv).rgb;
|
||||
vec3 vVec = normalize(eyeVec);
|
||||
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
|
||||
vec3 R = reflect(-vVec, bump);
|
||||
vec3 lVec = normalize(vVec);
|
||||
float diffuse = max(dot(lVec, bump), 0.0);
|
||||
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
|
||||
color = mix (base,diffuse*base,1.0) + 0.1 * specular * diffuse;
|
||||
} else {
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
}
|
||||
#else
|
||||
color = texture2D(baseTexture, uv).rgb;
|
||||
#endif
|
||||
|
||||
float alpha = texture2D(baseTexture, uv).a;
|
||||
vec4 col = vec4(color.r, color.g, color.b, alpha);
|
||||
col *= gl_Color;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / e;
|
||||
col.g = 1.0 - exp(1.0 - col.g) / e;
|
||||
col.b = 1.0 - exp(1.0 - col.b) / e;
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
col = mix(col, skyBgColor, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
|
||||
}
|
||||
102
client/shaders/solids_shader/opengl_vertex.glsl
Normal file
@@ -0,0 +1,102 @@
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
|
||||
uniform vec3 eyePosition;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 eyeVec;
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
varying vec3 tsEyeVec;
|
||||
#endif
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = mWorldViewProj * gl_Vertex;
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
|
||||
|
||||
#ifdef ENABLE_PARALLAX_OCCLUSION
|
||||
vec3 normal,tangent,binormal;
|
||||
normal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
|
||||
if (gl_Normal.x > 0.5) {
|
||||
// 1.0, 0.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, -1.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
} else if (gl_Normal.x < -0.5) {
|
||||
// -1.0, 0.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
} else if (gl_Normal.y > 0.5) {
|
||||
// 0.0, 1.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
|
||||
} else if (gl_Normal.y < -0.5) {
|
||||
// 0.0, -1.0, 0.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, 0.0, 1.0));
|
||||
} else if (gl_Normal.z > 0.5) {
|
||||
// 0.0, 0.0, 1.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3( 1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
} else if (gl_Normal.z < -0.5) {
|
||||
// 0.0, 0.0, -1.0
|
||||
tangent = normalize(gl_NormalMatrix * vec3(-1.0, 0.0, 0.0));
|
||||
binormal = normalize(gl_NormalMatrix * vec3( 0.0, -1.0, 0.0));
|
||||
}
|
||||
|
||||
mat3 tbnMatrix = mat3( tangent.x, binormal.x, normal.x,
|
||||
tangent.y, binormal.y, normal.y,
|
||||
tangent.z, binormal.z, normal.z);
|
||||
|
||||
tsEyeVec = normalize(eyeVec * tbnMatrix);
|
||||
#endif
|
||||
|
||||
vec4 color;
|
||||
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
float day = gl_Color.r;
|
||||
float night = gl_Color.g;
|
||||
float light_source = gl_Color.b;
|
||||
|
||||
/*color.r = mix(night, day, dayNightRatio);
|
||||
color.g = color.r;
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 2.5; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
b += (day - night) / 13.0;
|
||||
rg -= (day - night) / 13.0;
|
||||
|
||||
// Emphase blue a bit in darker places
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
|
||||
|
||||
// Artificial light is yellow-ish
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = clamp(rg,0.0,1.0);
|
||||
color.g = clamp(rg,0.0,1.0);
|
||||
color.b = clamp(b,0.0,1.0);
|
||||
|
||||
// Make sides and bottom darker than the top
|
||||
color = color * color; // SRGB -> Linear
|
||||
if(gl_Normal.y <= 0.5)
|
||||
color *= 0.6;
|
||||
//color *= 0.7;
|
||||
color = sqrt(color); // Linear -> SRGB
|
||||
|
||||
color.a = gl_Color.a;
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
uniform sampler2D myTexture;
|
||||
uniform vec4 skyBgColor;
|
||||
uniform float fogDistance;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
//vec4 col = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||
float a = col.a;
|
||||
col *= gl_Color;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
col = mix(col, skyBgColor, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, a);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
uniform sampler2D myTexture;
|
||||
uniform float fogDistance;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||
col *= gl_Color;
|
||||
float a = gl_Color.a;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
a = mix(a, 0.0, d);
|
||||
}
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, a);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mInvWorld;
|
||||
uniform mat4 mTransWorld;
|
||||
uniform float dayNightRatio;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = mWorldViewProj * gl_Vertex;
|
||||
|
||||
vPosition = (mWorldViewProj * gl_Vertex).xyz;
|
||||
|
||||
vec4 color;
|
||||
//color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
float day = gl_Color.r;
|
||||
float night = gl_Color.g;
|
||||
float light_source = gl_Color.b;
|
||||
|
||||
/*color.r = mix(night, day, dayNightRatio);
|
||||
color.g = color.r;
|
||||
color.b = color.r;*/
|
||||
|
||||
float rg = mix(night, day, dayNightRatio);
|
||||
rg += light_source * 1.0; // Make light sources brighter
|
||||
float b = rg;
|
||||
|
||||
// Moonlight is blue
|
||||
b += (day - night) / 13.0;
|
||||
rg -= (day - night) / 13.0;
|
||||
|
||||
// Emphase blue a bit in darker places
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
|
||||
|
||||
// Artificial light is yellow-ish
|
||||
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
|
||||
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
|
||||
|
||||
color.r = rg;
|
||||
color.g = rg;
|
||||
color.b = b;
|
||||
|
||||
color.a = gl_Color.a;
|
||||
|
||||
gl_FrontColor = gl_BackColor = color;
|
||||
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
uniform sampler2D myTexture;
|
||||
uniform float fogDistance;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
|
||||
col *= gl_Color;
|
||||
float a = col.a;
|
||||
col = col * col; // SRGB -> Linear
|
||||
col *= 1.8;
|
||||
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
|
||||
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
|
||||
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
|
||||
col = sqrt(col); // Linear -> SRGB
|
||||
|
||||
if(fogDistance != 0.0){
|
||||
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
|
||||
a = mix(a, 0.0, d);
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(col.r, col.g, col.b, a);
|
||||
}
|
||||
@@ -20,6 +20,10 @@ if( UNIX )
|
||||
else( UNIX )
|
||||
FIND_PATH(CURL_INCLUDE_DIR NAMES curl/curl.h) # Look for the header file.
|
||||
FIND_LIBRARY(CURL_LIBRARY NAMES curl) # Look for the library.
|
||||
FIND_FILE(CURL_DLL NAMES libcurl.dll
|
||||
PATHS
|
||||
"c:/windows/system32"
|
||||
DOC "Path of the cURL dll (for installation)")
|
||||
INCLUDE(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set CURL_FOUND to TRUE if
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL DEFAULT_MSG CURL_LIBRARY CURL_INCLUDE_DIR) # all listed variables are TRUE
|
||||
endif( UNIX )
|
||||
@@ -40,3 +44,4 @@ endif ( WIN32 )
|
||||
|
||||
MESSAGE(STATUS "CURL_INCLUDE_DIR = ${CURL_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "CURL_LIBRARY = ${CURL_LIBRARY}")
|
||||
MESSAGE(STATUS "CURL_DLL = ${CURL_DLL}")
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Look for jthread, use our own if not found
|
||||
|
||||
FIND_PATH(JTHREAD_INCLUDE_DIR jthread.h)
|
||||
|
||||
FIND_LIBRARY(JTHREAD_LIBRARY NAMES jthread)
|
||||
|
||||
IF(JTHREAD_LIBRARY AND JTHREAD_INCLUDE_DIR)
|
||||
SET( JTHREAD_FOUND TRUE )
|
||||
ENDIF(JTHREAD_LIBRARY AND JTHREAD_INCLUDE_DIR)
|
||||
|
||||
IF(JTHREAD_FOUND)
|
||||
MESSAGE(STATUS "Found system jthread header file in ${JTHREAD_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "Found system jthread library ${JTHREAD_LIBRARY}")
|
||||
ELSE(JTHREAD_FOUND)
|
||||
SET(JTHREAD_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/jthread)
|
||||
SET(JTHREAD_LIBRARY jthread)
|
||||
MESSAGE(STATUS "Using project jthread library")
|
||||
ENDIF(JTHREAD_FOUND)
|
||||
20
cmake/Modules/GenerateVersion.cmake
Normal file
@@ -0,0 +1,20 @@
|
||||
# Always run during 'make'
|
||||
|
||||
if(VERSION_EXTRA)
|
||||
set(VERSION_GITHASH "${VERSION_STRING}")
|
||||
else(VERSION_EXTRA)
|
||||
execute_process(COMMAND git describe --always --tag --dirty
|
||||
WORKING_DIRECTORY "${GENERATE_VERSION_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE VERSION_GITHASH OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
|
||||
if(VERSION_GITHASH)
|
||||
message(STATUS "*** Detected git version ${VERSION_GITHASH} ***")
|
||||
else()
|
||||
set(VERSION_GITHASH "${VERSION_STRING}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
${GENERATE_VERSION_SOURCE_DIR}/cmake_config_githash.h.in
|
||||
${GENERATE_VERSION_BINARY_DIR}/cmake_config_githash.h)
|
||||
339
doc/gpl-2.0.txt
@@ -1,339 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU 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.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
502
doc/lgpl-2.1.txt
Normal file
@@ -0,0 +1,502 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library 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 library 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 library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
601
doc/lua_api.txt
@@ -1,4 +1,4 @@
|
||||
Minetest Lua Modding API Reference 0.4.7
|
||||
Minetest Lua Modding API Reference 0.4.9
|
||||
========================================
|
||||
More information at http://www.minetest.net/
|
||||
Developer Wiki: http://dev.minetest.net/
|
||||
@@ -100,6 +100,8 @@ Mod directory structure
|
||||
mods
|
||||
|-- modname
|
||||
| |-- depends.txt
|
||||
| |-- screenshot.png
|
||||
| |-- description.txt
|
||||
| |-- init.lua
|
||||
| |-- textures
|
||||
| | |-- modname_stuff.png
|
||||
@@ -121,12 +123,11 @@ depends.txt:
|
||||
to a single modname. Their meaning is that if the specified mod
|
||||
is missing, that does not prevent this mod from being loaded.
|
||||
|
||||
optdepends.txt:
|
||||
An alternative way of specifying optional dependencies.
|
||||
Like depends.txt, a single line contains a single modname.
|
||||
screenshot.png:
|
||||
A screenshot shown in modmanager within mainmenu.
|
||||
|
||||
NOTE: This file exists for compatibility purposes only and
|
||||
support for it will be removed from the engine by the end of 2013.
|
||||
description.txt:
|
||||
File containing desctiption to be shown within mainmenu.
|
||||
|
||||
init.lua:
|
||||
The main Lua script. Running this script should register everything it
|
||||
@@ -322,6 +323,8 @@ param2 is reserved for the engine when any of these are used:
|
||||
facedir modulo 4 = axisdir
|
||||
0 = y+ 1 = z+ 2 = z- 3 = x+ 4 = x- 5 = y-
|
||||
facedir's two less significant bits are rotation around the axis
|
||||
paramtype2 == "leveled"
|
||||
^ The drawn node level is read from param2, like flowingliquid
|
||||
|
||||
Nodes can also contain extra data. See "Node Metadata".
|
||||
|
||||
@@ -353,7 +356,7 @@ Node selection boxes are defined using "node boxes"
|
||||
|
||||
The "nodebox" node drawtype allows defining visual of nodes consisting of
|
||||
arbitrary number of boxes. It allows defining stuff like stairs. Only the
|
||||
"fixed" box type is supported for these.
|
||||
"fixed" and "leveled" box type is supported for these.
|
||||
^ Please note that this is still experimental, and may be incompatibly
|
||||
changed in the future.
|
||||
|
||||
@@ -381,6 +384,8 @@ A box is defined as:
|
||||
A box of a regular node would look like:
|
||||
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
|
||||
type = "leveled" is same as "fixed", but y2 will be automaticaly setted to level from param2
|
||||
|
||||
Ore types
|
||||
---------------
|
||||
These tell in what manner the ore is generated.
|
||||
@@ -410,6 +415,50 @@ Currently supported flags: absheight
|
||||
Also produce this same ore between the height range of -height_max and -height_min.
|
||||
Useful for having ore in sky realms without having to duplicate ore entries.
|
||||
|
||||
Decoration types
|
||||
-------------------
|
||||
The varying types of decorations that can be placed.
|
||||
The default value is simple, and is currently the only type supported.
|
||||
|
||||
- simple
|
||||
Creates a 1xHx1 column of a specified node (or a random node from a list, if a decoration
|
||||
list is specified). Can specify a certain node it must spawn next to, such as water or lava,
|
||||
for example. Can also generate a decoration of random height between a specified lower and
|
||||
upper bound. This type of decoration is intended for placement of grass, flowers, cacti,
|
||||
papyrus, and so on.
|
||||
- schematic
|
||||
Copies a box of MapNodes from a specified schematic file (or raw description). Can specify a
|
||||
probability of a node randomly appearing when placed. This decoration type is intended to be used
|
||||
for multi-node sized discrete structures, such as trees, cave spikes, rocks, and so on.
|
||||
|
||||
Schematic specifier
|
||||
--------------------
|
||||
A schematic specifier identifies a schematic by either a filename to a Minetest Schematic file (.mts)
|
||||
or through raw data supplied through Lua, in the form of a table. This table must specify two fields:
|
||||
- The 'size' field is a 3d vector containing the dimensions of the provided schematic.
|
||||
- The 'data' field is a flat table of MapNodes making up the schematic, in the order of [z [y [x]]].
|
||||
Important: The default value for param1 in MapNodes here is 255, which represents "always place".
|
||||
|
||||
In the bulk MapNode data, param1, instead of the typical light values, instead represents the
|
||||
probability of that node appearing in the structure.
|
||||
When passed to minetest.create_schematic, probability is an integer value ranging from 0 to 255:
|
||||
- A probability value of 0 means that node will never appear (0% chance).
|
||||
- A probability value of 255 means the node will always appear (100% chance).
|
||||
- If the probability value p is greater than 0, then there is a (p / 256 * 100)% chance that node
|
||||
will appear when the schematic is placed on the map.
|
||||
|
||||
Important note: Node aliases cannot be used for a raw schematic provided when registering as a decoration.
|
||||
|
||||
Schematic attributes
|
||||
---------------------
|
||||
Currently supported flags: place_center_x, place_center_y, place_center_z
|
||||
- place_center_x
|
||||
Placement of this decoration is centered along the X axis.
|
||||
- place_center_y
|
||||
Placement of this decoration is centered along the Y axis.
|
||||
- place_center_z
|
||||
Placement of this decoration is centered along the Z axis.
|
||||
|
||||
HUD element types
|
||||
-------------------
|
||||
The position field is used for all element types.
|
||||
@@ -430,8 +479,10 @@ Note: Future revisions to the HUD API may be incompatible; the HUD API is still
|
||||
|
||||
- image
|
||||
Displays an image on the HUD.
|
||||
- scale: The scale of the image, with 1 being the original texture size.
|
||||
Only the X coordinate scale is used.
|
||||
- scale: The scale of the image, with 1 being the original texture size.
|
||||
Only the X coordinate scale is used (positive values)
|
||||
Negative values represent that percentage of the screen it
|
||||
should take; e.g. x=-100 means 100% (width)
|
||||
- text: The name of the texture that is displayed.
|
||||
- alignment: The alignment of the image.
|
||||
- offset: offset in pixels from position.
|
||||
@@ -461,8 +512,7 @@ Representations of simple things
|
||||
--------------------------------
|
||||
Position/vector:
|
||||
{x=num, y=num, z=num}
|
||||
Currently the API does not provide any helper functions for addition,
|
||||
subtraction and whatever; you can define those that you need yourself.
|
||||
For helper functions see "Vector helpers".
|
||||
|
||||
pointed_thing:
|
||||
{type="nothing"}
|
||||
@@ -824,6 +874,22 @@ list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]
|
||||
list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]
|
||||
^ Show an inventory list
|
||||
|
||||
listcolors[<slot_bg_normal>;<slot_bg_hover>]
|
||||
^ Sets background color of slots in HEX-Color format
|
||||
^ Sets background color of slots on mouse hovering
|
||||
|
||||
listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>]
|
||||
^ Sets background color of slots in HEX-Color format
|
||||
^ Sets background color of slots on mouse hovering
|
||||
^ Sets color of slots border
|
||||
|
||||
listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>;<tooltip_bgcolor>;<tooltip_fontcolor>]
|
||||
^ Sets background color of slots in HEX-Color format
|
||||
^ Sets background color of slots on mouse hovering
|
||||
^ Sets color of slots border
|
||||
^ Sets background color of tooltips
|
||||
^ Sets font color of tooltips
|
||||
|
||||
image[<X>,<Y>;<W>,<H>;<texture name>]
|
||||
^ Show an image
|
||||
^ Position and size units are inventory slots
|
||||
@@ -832,11 +898,30 @@ item_image[<X>,<Y>;<W>,<H>;<item name>]
|
||||
^ Show an inventory image of registered item/node
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
bgcolor[<color>;<fullscreen>]
|
||||
^ Sets background color of formspec in HEX-Color format
|
||||
^ If true the background color is drawn fullscreen (does not effect the size of the formspec)
|
||||
|
||||
background[<X>,<Y>;<W>,<H>;<texture name>]
|
||||
^ Use a background. Inventory rectangles are not drawn then.
|
||||
^ Position and size units are inventory slots
|
||||
^ Example for formspec 8x4 in 16x resolution: image shall be sized 8*16px x 4*16px
|
||||
|
||||
background[<X>,<Y>;<W>,<H>;<texture name>;<auto_clip>]
|
||||
^ Use a background. Inventory rectangles are not drawn then.
|
||||
^ Position and size units are inventory slots
|
||||
^ Example for formspec 8x4 in 16x resolution: image shall be sized 8*16px x 4*16px
|
||||
^ If true the background is clipped to formspec size (x and y are used as offset values, w and h are ignored)
|
||||
|
||||
pwdfield[<X>,<Y>;<W>,<H>;<name>;<label>]
|
||||
^ Textual password style field; will be sent to server when a button is clicked
|
||||
^ x and y position the field relative to the top left of the menu
|
||||
^ w and h are the size of the field
|
||||
^ fields are a set height, but will be vertically centred on h
|
||||
^ Position and size units are inventory slots
|
||||
^ name is the name of the field as returned in fields to on_receive_fields
|
||||
^ label, if not blank, will be text printed on the top left above the field
|
||||
|
||||
field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
|
||||
^ Textual field; will be sent to server when a button is clicked
|
||||
^ x and y position the field relative to the top left of the menu
|
||||
@@ -864,6 +949,12 @@ label[<X>,<Y>;<label>]
|
||||
^ label is the text on the label
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
vertlabel[<X>,<Y>;<label>]
|
||||
^ Textual label drawn verticaly
|
||||
^ x and y work as per field
|
||||
^ label is the text on the label
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
button[<X>,<Y>;<W>,<H>;<name>;<label>]
|
||||
^ Clickable button. When clicked, fields will be sent.
|
||||
^ x, y and name work as per field
|
||||
@@ -873,9 +964,24 @@ button[<X>,<Y>;<W>,<H>;<name>;<label>]
|
||||
|
||||
image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]
|
||||
^ x, y, w, h, and name work as per button
|
||||
^ image is the filename of an image
|
||||
^ texture name is the filename of an image
|
||||
^ Position and size units are inventory slots
|
||||
|
||||
image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>;<noclip>;<drawborder>]
|
||||
^ x, y, w, h, and name work as per button
|
||||
^ texture name is the filename of an image
|
||||
^ Position and size units are inventory slots
|
||||
^ noclip true meand imagebutton doesn't need to be within specified formsize
|
||||
^ drawborder draw button bodrer or not
|
||||
|
||||
image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>;<noclip>;<drawborder>;<pressed texture name>]
|
||||
^ x, y, w, h, and name work as per button
|
||||
^ texture name is the filename of an image
|
||||
^ Position and size units are inventory slots
|
||||
^ noclip true meand imagebutton doesn't need to be within specified formsize
|
||||
^ drawborder draw button bodrer or not
|
||||
^ pressed texture name is the filename of an image on pressed state
|
||||
|
||||
item_image_button[<X>,<Y>;<W>,<H>;<item name>;<name>;<label>]
|
||||
^ x, y, w, h, name and label work as per button
|
||||
^ item name is the registered name of an item/node,
|
||||
@@ -888,6 +994,58 @@ button_exit[<X>,<Y>;<W>,<H>;<name>;<label>]
|
||||
image_button_exit[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]
|
||||
^ When clicked, fields will be sent and the form will quit.
|
||||
|
||||
textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>]
|
||||
^Scrollabel itemlist showing arbitrary text elements
|
||||
^ x and y position the itemlist relative to the top left of the menu
|
||||
^ w and h are the size of the itemlist
|
||||
^ name fieldname sent to server on doubleclick value is current selected element
|
||||
^ listelements can be prepended by #color in hexadecimal format RRGGBB (only),
|
||||
^ if you want a listelement to start with # write ##
|
||||
|
||||
textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>;<selected idx>;<transparent>]
|
||||
^Scrollabel itemlist showing arbitrary text elements
|
||||
^ x and y position the itemlist relative to the top left of the menu
|
||||
^ w and h are the size of the itemlist
|
||||
^ name fieldname sent to server on doubleclick value is current selected element
|
||||
^ listelements can be prepended by #RRGGBB (only) in hexadecimal format
|
||||
^ if you want a listelement to start with # write ##
|
||||
^ index to be selected within textlist
|
||||
^ true/false draw transparent background
|
||||
|
||||
tabheader[<X>,<Y>;<name>;<caption 1>,<caption 2>,...,<caption n>;<current_tab>;<transparent>;<draw_border>]
|
||||
^ show a tabHEADER at specific position (ignores formsize)
|
||||
^ x and y position the itemlist relative to the top left of the menu
|
||||
^ name fieldname data is transfered to lua
|
||||
^ caption 1... name shown on top of tab
|
||||
^ current_tab index of selected tab 1...
|
||||
^ transparent (optional) show transparent
|
||||
^ draw_border (optional) draw border
|
||||
|
||||
box[<X>,<Y>;<W>,<H>;<color>]
|
||||
^ simple colored semitransparent box
|
||||
^ x and y position the box relative to the top left of the menu
|
||||
^ w and h are the size of box
|
||||
^ color in HEX-Color format
|
||||
|
||||
dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]
|
||||
^ show a dropdown field
|
||||
^ x and y position of dropdown
|
||||
^ width of dropdown
|
||||
^ fieldname data is transfered to lua
|
||||
^ items to be shown in dropdown
|
||||
^ index of currently selected dropdown item
|
||||
^ color in hexadecimal format RRGGBB (only)
|
||||
|
||||
checkbox[<X>,<Y>;<name>;<label>;<selected>]
|
||||
^ show a checkbox
|
||||
^ x and y position of checkbox
|
||||
^ name fieldname data is transfered to lua
|
||||
^ label to be shown left of checkbox
|
||||
^ selected (optional) true/false
|
||||
|
||||
Note: do NOT use a element name starting with "key_" those names are reserved to
|
||||
pass key press events to formspec!
|
||||
|
||||
Inventory location:
|
||||
|
||||
- "context": Selected node metadata (deprecated: "current_name")
|
||||
@@ -896,12 +1054,42 @@ Inventory location:
|
||||
- "nodemeta:<X>,<Y>,<Z>": Any node metadata
|
||||
- "detached:<name>": A detached inventory
|
||||
|
||||
HEX-Color
|
||||
---------
|
||||
#RGB
|
||||
^ defines a color in hexadecimal format
|
||||
#RGBA
|
||||
^ defines a color in hexadecimal format and alpha channel
|
||||
#RRGGBB
|
||||
^ defines a color in hexadecimal format
|
||||
#RRGGBBAA
|
||||
^ defines a color in hexadecimal format and alpha channel
|
||||
|
||||
Vector helpers
|
||||
---------------
|
||||
vector.new([x[, y, z]]) -> vector
|
||||
^ x is a table or the x position.
|
||||
vector.direction(p1, p2) -> vector
|
||||
vector.distance(p1, p2) -> number
|
||||
vector.length(v) -> number
|
||||
vector.normalize(v) -> vector
|
||||
vector.round(v) -> vector
|
||||
vector.equals(v1, v2) -> bool
|
||||
For the folowing x can be either a vector or a number.
|
||||
vector.add(v, x) -> vector
|
||||
vector.subtract(v, x) -> vector
|
||||
vector.multiply(v, x) -> vector
|
||||
vector.divide(v, x) -> vector
|
||||
|
||||
Helper functions
|
||||
-----------------
|
||||
dump2(obj, name="_", dumped={})
|
||||
^ Return object serialized as a string, handles reference loops
|
||||
dump(obj, dumped={})
|
||||
^ Return object serialized as a string
|
||||
math.hypot(x, y)
|
||||
^ Get the hypotenuse of a triangle with legs x and y.
|
||||
Usefull for distance calculation.
|
||||
string:split(separator)
|
||||
^ eg. string:split("a,b", ",") == {"a","b"}
|
||||
string:trim()
|
||||
@@ -911,7 +1099,9 @@ minetest.pos_to_string({x=X,y=Y,z=Z}) -> "(X,Y,Z)"
|
||||
minetest.string_to_pos(string) -> position
|
||||
^ Same but in reverse
|
||||
minetest.formspec_escape(string) -> string
|
||||
^ escapes characters like [, ], and \ that can not be used in formspecs
|
||||
^ escapes characters [ ] \ , ; that can not be used in formspecs
|
||||
minetest.is_yes(arg)
|
||||
^ returns whether arg can be interpreted as yes
|
||||
|
||||
minetest namespace reference
|
||||
-----------------------------
|
||||
@@ -946,10 +1136,11 @@ minetest.register_craftitem(name, item definition)
|
||||
minetest.register_alias(name, convert_to)
|
||||
minetest.register_craft(recipe)
|
||||
minetest.register_ore(ore definition)
|
||||
minetest.register_decoration(decoration definition)
|
||||
|
||||
Global callback registration functions: (Call these only at load time)
|
||||
minetest.register_globalstep(func(dtime))
|
||||
^ Called every server step, usually interval of 0.05s
|
||||
^ Called every server step, usually interval of 0.1s
|
||||
minetest.register_on_shutdown(func())
|
||||
^ Called before server shutdown
|
||||
^ WARNING: If the server terminates abnormally (i.e. crashes), the registered
|
||||
@@ -977,16 +1168,41 @@ minetest.register_on_respawnplayer(func(ObjectRef))
|
||||
^ Called when player is to be respawned
|
||||
^ Called _before_ repositioning of player occurs
|
||||
^ return true in func to disable regular player placement
|
||||
minetest.register_on_prejoinplayer(func(name, ip))
|
||||
^ Called before a player joins the game
|
||||
^ If it returns a string, the player is disconnected with that string as reason
|
||||
minetest.register_on_joinplayer(func(ObjectRef))
|
||||
^ Called when a player joins the game
|
||||
minetest.register_on_leaveplayer(func(ObjectRef))
|
||||
^ Called when a player leaves the game
|
||||
minetest.register_on_cheat(func(ObjectRef, cheat))
|
||||
^ Called when a player cheats
|
||||
^ cheat: {type="moved_too_fast"/"interacted_too_far"/"finished_unknown_dig"/"dug_unbreakable"/"dug_too_fast"}
|
||||
minetest.register_on_chat_message(func(name, message))
|
||||
^ Called always when a player says something
|
||||
minetest.register_on_player_receive_fields(func(player, formname, fields))
|
||||
^ Called when a button is pressed in player's inventory form
|
||||
^ Newest functions are called first
|
||||
^ If function returns true, remaining functions are not called
|
||||
minetest.register_on_mapgen_init(func(MapgenParams))
|
||||
^ Called just before the map generator is initialized but before the environment is initialized
|
||||
^ MapgenParams consists of a table with the fields mgname, seed, water_level, and flags
|
||||
minetest.register_on_craft(func(itemstack, player, old_craft_grid, craft_inv))
|
||||
^ Called when player crafts something
|
||||
^ itemstack is the output
|
||||
^ old_craft_grid contains the recipe (Note: the one in the inventory is cleared)
|
||||
^ craft_inv is the inventory with the crafting grid
|
||||
^ Return either an ItemStack, to replace the output, or nil, to not modify it
|
||||
minetest.register_craft_predict(func(itemstack, player, old_craft_grid, craft_inv))
|
||||
^ The same as before, except that it is called before the player crafts, to make
|
||||
^ craft prediction, and it should not change anything.
|
||||
minetest.register_on_protection_violation(func(pos, name))
|
||||
^ Called by builtin and mods when a player violates protection at a position
|
||||
(eg, digs a node or punches a protected entity).
|
||||
^ The registered functions can be called using minetest.record_protection_violation
|
||||
^ The provided function should check that the position is protected by the mod
|
||||
calling this function before it prints a message, if it does, to allow for
|
||||
multiple protection mods.
|
||||
|
||||
Other registration functions:
|
||||
minetest.register_chatcommand(cmd, chatcommand definition)
|
||||
@@ -1002,10 +1218,10 @@ minetest.register_authentication_handler(handler)
|
||||
Setting-related:
|
||||
minetest.setting_set(name, value)
|
||||
minetest.setting_get(name) -> string or nil
|
||||
minetest.setting_setbool(name, value)
|
||||
minetest.setting_getbool(name) -> boolean value or nil
|
||||
minetest.setting_get_pos(name) -> position or nil
|
||||
minetest.setting_save() -> nil, save all settings to config file
|
||||
minetest.add_to_creative_inventory(itemstring)
|
||||
|
||||
Authentication:
|
||||
minetest.notify_authentication_modified(name)
|
||||
@@ -1035,6 +1251,8 @@ Environment access:
|
||||
minetest.set_node(pos, node)
|
||||
minetest.add_node(pos, node): alias set_node(pos, node)
|
||||
^ Set node at position (node = {name="foo", param1=0, param2=0})
|
||||
minetest.swap_node(pos, node)
|
||||
^ Set node at position, but don't remove metadata
|
||||
minetest.remove_node(pos)
|
||||
^ Equivalent to set_node(pos, "air")
|
||||
minetest.get_node(pos)
|
||||
@@ -1062,16 +1280,34 @@ minetest.get_player_by_name(name) -- Get an ObjectRef to a player
|
||||
minetest.get_objects_inside_radius(pos, radius)
|
||||
minetest.set_timeofday(val): val: 0...1; 0 = midnight, 0.5 = midday
|
||||
minetest.get_timeofday()
|
||||
minetest.get_gametime(): returns the time, in seconds, since the world was created
|
||||
minetest.find_node_near(pos, radius, nodenames) -> pos or nil
|
||||
^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
|
||||
minetest.find_nodes_in_area(minp, maxp, nodenames) -> list of positions
|
||||
^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
|
||||
minetest.get_perlin(seeddiff, octaves, persistence, scale)
|
||||
^ Return world-specific perlin noise (int(worldseed)+seeddiff)
|
||||
minetest.get_voxel_manip()
|
||||
^ Return voxel manipulator object
|
||||
minetest.set_gen_notify(flags)
|
||||
^ Set the types of on-generate notifications that should be collected
|
||||
^ flags is a comma-delimited combination of:
|
||||
^ dungeon, temple, cave_begin, cave_end, large_cave_begin, large_cave_end
|
||||
minetest.get_mapgen_object(objectname)
|
||||
^ Return requested mapgen object if available (see Mapgen objects)
|
||||
minetest.set_mapgen_params(MapgenParams)
|
||||
^ Set map generation parameters
|
||||
^ Function cannot be called after the registration period; only initialization and on_mapgen_init
|
||||
^ Takes a table as an argument with the fields mgname, seed, water_level, flags, and flagmask.
|
||||
^ Leave field unset to leave that parameter unchanged
|
||||
^ flagmask field must be set to all mapgen flags that are being modified
|
||||
^ flags contains only the flags that are being set
|
||||
^ flags and flagmask are in the same format and have the same options as 'mgflags' in minetest.conf
|
||||
minetest.clear_objects()
|
||||
^ clear all objects in the environments
|
||||
minetest.line_of_sight(pos1,pos2,stepsize) ->true/false
|
||||
^ checkif there is a direct line of sight between pos1 and pos2
|
||||
minetest.line_of_sight(pos1, pos2, stepsize) -> true/false, pos
|
||||
^ Check if there is a direct line of sight between pos1 and pos2
|
||||
^ Returns the position of the blocking node when false
|
||||
^ pos1 First position
|
||||
^ pos2 Second position
|
||||
^ stepsize smaller gives more accurate results but requires more computing
|
||||
@@ -1087,6 +1323,20 @@ minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)
|
||||
^ algorithm: A*_noprefetch(default), A*, Dijkstra
|
||||
minetest.spawn_tree (pos, {treedef})
|
||||
^ spawns L-System tree at given pos with definition in treedef table
|
||||
minetest.transforming_liquid_add(pos)
|
||||
^ add node to liquid update queue
|
||||
minetest.get_node_max_level(pos)
|
||||
^ get max available level for leveled node
|
||||
minetest.get_node_level(pos)
|
||||
^ get level of leveled node (water, snow)
|
||||
minetest.set_node_level(pos, level)
|
||||
^ set level of leveled node, default level = 1, if totallevel > maxlevel returns rest (total-max).
|
||||
minetest.add_node_level(pos, level)
|
||||
^ increase level of leveled node by level, default level = 1, if totallevel > maxlevel returns rest (total-max). can be negative for decreasing
|
||||
minetest.get_heat(pos)
|
||||
^ heat at pos
|
||||
minetest.get_humidity(pos)
|
||||
^ humidity at pos
|
||||
|
||||
Inventory:
|
||||
minetest.get_inventory(location) -> InvRef
|
||||
@@ -1107,8 +1357,10 @@ minetest.inventorycube(img1, img2, img3)
|
||||
^ Returns a string for making an image of a cube (useful as an item image)
|
||||
minetest.get_pointed_thing_position(pointed_thing, above)
|
||||
^ Get position of a pointed_thing (that you can get from somewhere)
|
||||
minetest.dir_to_facedir(dir)
|
||||
^ Convert a vector to a facedir value, used in param2 for paramtype2="facedir"
|
||||
minetest.dir_to_facedir(dir, is6d)
|
||||
^ Convert a vector to a facedir value, used in param2 for paramtype2="facedir"; passing something non-nil/false for the optional second parameter causes it to take the y component into account
|
||||
minetest.facedir_to_dir(facedir)
|
||||
^ Convert a facedir back into a vector aimed directly out the "back" of a node
|
||||
minetest.dir_to_wallmounted(dir)
|
||||
^ Convert a vector to a wallmounted value, used for paramtype2="wallmounted"
|
||||
minetest.get_node_drops(nodename, toolname)
|
||||
@@ -1154,8 +1406,8 @@ minetest.handle_node_drops(pos, drops, digger)
|
||||
^ Can be overridden to get different functionality (eg. dropping items on
|
||||
ground)
|
||||
|
||||
Rollbacks:
|
||||
minetest.rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
|
||||
Rollback:
|
||||
minetest.rollback_get_node_actions(pos, range, seconds, limit) -> {{actor, pos, time, oldnode, newnode}, ...}
|
||||
^ Find who has done something to a node, or near a node
|
||||
^ actor: "player:<name>", also "liquid".
|
||||
minetest.rollback_revert_actions_by(actor, seconds) -> bool, log messages
|
||||
@@ -1164,14 +1416,18 @@ minetest.rollback_revert_actions_by(actor, seconds) -> bool, log messages
|
||||
|
||||
Defaults for the on_* item definition functions:
|
||||
(These return the leftover itemstack)
|
||||
minetest.item_place_node(itemstack, placer, pointed_thing)
|
||||
minetest.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
^ Place item as a node
|
||||
^ param2 overrides facedir and wallmounted param2
|
||||
^ returns itemstack, success
|
||||
minetest.item_place_object(itemstack, placer, pointed_thing)
|
||||
^ Place item as-is
|
||||
minetest.item_place(itemstack, placer, pointed_thing)
|
||||
minetest.item_place(itemstack, placer, pointed_thing, param2)
|
||||
^ Use one of the above based on what the item is.
|
||||
^ Calls on_rightclick of pointed_thing.under if defined instead
|
||||
^ Note: is not called when wielded item overrides on_place
|
||||
^ param2 overrides facedir and wallmounted param2
|
||||
^ returns itemstack, success
|
||||
minetest.item_drop(itemstack, dropper, pos)
|
||||
^ Drop the item
|
||||
minetest.item_eat(hp_change, replace_with_item)
|
||||
@@ -1236,6 +1492,27 @@ minetest.delete_particlespawner(id, player)
|
||||
^ If playername is specified, only deletes on the player's client,
|
||||
^ otherwise on all clients
|
||||
|
||||
Schematics:
|
||||
minetest.create_schematic(p1, p2, probability_list, filename, slice_prob_list)
|
||||
^ Create a schematic from the volume of map specified by the box formed by p1 and p2.
|
||||
^ Apply the specified probability values to the specified nodes in probability_list.
|
||||
^ probability_list is an array of tables containing two fields, pos and prob.
|
||||
^ pos is the 3d vector specifying the absolute coordinates of the node being modified,
|
||||
^ and prob is the integer value from 0 to 255 of the probability (see: Schematic specifier).
|
||||
^ If there are two or more entries with the same pos value, the last occuring in the array is used.
|
||||
^ If pos is not inside the box formed by p1 and p2, it is ignored.
|
||||
^ If probability_list is nil, no probabilities are applied.
|
||||
^ Slice probability works in the same manner, except takes a field called ypos instead which indicates
|
||||
^ the y position of the slice with a probability applied.
|
||||
^ If slice probability list is nil, no slice probabilities are applied.
|
||||
^ Saves schematic in the Minetest Schematic format to filename.
|
||||
|
||||
minetest.place_schematic(pos, schematic, rotation, replacements)
|
||||
^ Place the schematic specified by schematic (see: Schematic specifier) at pos.
|
||||
^ Rotation can be "0", "90", "180", "270", or "random".
|
||||
^ If the rotation parameter is omitted, the schematic is not rotated.
|
||||
^ replacements = {{"oldname", "convert_to"}, ...}
|
||||
|
||||
Random:
|
||||
minetest.get_connected_players() -> list of ObjectRefs
|
||||
minetest.hash_node_position({x=,y=,z=}) -> 48-bit integer
|
||||
@@ -1244,6 +1521,25 @@ minetest.get_item_group(name, group) -> rating
|
||||
^ Get rating of a group of an item. (0 = not in group)
|
||||
minetest.get_node_group(name, group) -> rating
|
||||
^ Deprecated: An alias for the former.
|
||||
minetest.get_content_id(name) -> integer
|
||||
^ Gets the internal content ID of name
|
||||
minetest.get_name_from_content_id(content_id) -> string
|
||||
^ Gets the name of the content with that content ID
|
||||
minetest.parse_json(string[, nullvalue]) -> something
|
||||
^ Convert a string containing JSON data into the Lua equivalent
|
||||
^ nullvalue: returned in place of the JSON null; defaults to nil
|
||||
^ On success returns a table, a string, a number, a boolean or nullvalue
|
||||
^ On failure outputs an error message and returns nil
|
||||
^ Example: parse_json("[10, {\"a\":false}]") -> {10, {a = false}}
|
||||
minetest.write_json(data[, styled]) -> string or nil and error message
|
||||
^ Convert a Lua table into a JSON string
|
||||
^ styled: Outputs in a human-readable format if this is set, defaults to false
|
||||
^ Un-serializable things like functions and userdata are saved as null.
|
||||
^ Warning: JSON is more strict than the Lua table format.
|
||||
1. You can only use strings and positive integers of at least one as keys.
|
||||
2. You can not mix string and integer keys.
|
||||
This is due to the fact that Javascript has two distinct array and object values.
|
||||
^ Example: write_json({10, {a = false}}) -> "[10, {\"a\": false}]"
|
||||
minetest.serialize(table) -> string
|
||||
^ Convert a table containing tables, strings, numbers, booleans and nils
|
||||
into string form readable by minetest.deserialize
|
||||
@@ -1255,6 +1551,44 @@ minetest.deserialize(string) -> table
|
||||
^ Example: deserialize('return { ["foo"] = "bar" }') -> {foo='bar'}
|
||||
^ Example: deserialize('print("foo")') -> nil (function call fails)
|
||||
^ error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)
|
||||
minetest.is_protected(pos, name) -> bool
|
||||
^ This function should be overriden by protection mods and should be used to
|
||||
check if a player can interact at a position.
|
||||
^ This function should call the old version of itself if the position is not
|
||||
protected by the mod.
|
||||
^ Example:
|
||||
local old_is_protected = minetest.is_protected
|
||||
function minetest.is_protected(pos, name)
|
||||
if mymod:position_protected_from(pos, name) then
|
||||
return true
|
||||
end
|
||||
return old_is_protected(pos, name)
|
||||
end
|
||||
minetest.record_protection_violation(pos, name)
|
||||
^ This function calls functions registered with
|
||||
minetest.register_on_protection_violation.
|
||||
minetest.rotate_and_place(itemstack, placer, pointed_thing, infinitestacks, orient_flags)
|
||||
^ Attempt to predict the desired orientation of the facedir-capable node
|
||||
defined by itemstack, and place it accordingly (on-wall, on the floor, or
|
||||
hanging from the ceiling). Stacks are handled normally if the infinitestacks
|
||||
field is false or omitted (else, the itemstack is not changed). orient_flags
|
||||
is an optional table containing extra tweaks to the placement code:
|
||||
invert_wall: if true, place wall-orientation on the ground and ground-
|
||||
orientation on the wall.
|
||||
force_wall: if true, always place the node in wall orientation.
|
||||
force_ceiling: if true, always place on the ceiling.
|
||||
force_floor: if true, always place the node on the floor.
|
||||
|
||||
The above four options are mutually-exclusive; the last in the list takes
|
||||
precedence over the first.
|
||||
|
||||
force_facedir: if true, forcably reset the facedir to north when placing on
|
||||
the floor or ceiling
|
||||
|
||||
minetest.rotate_node(itemstack, placer, pointed_thing)
|
||||
^ calls rotate_and_place() with infinitestacks set according to the state of
|
||||
the creative mode setting, and checks for "sneak" to set the invert_wall
|
||||
parameter.
|
||||
|
||||
Global objects:
|
||||
minetest.env - EnvRef of the server environment and world.
|
||||
@@ -1280,15 +1614,6 @@ minetest.object_refs
|
||||
minetest.luaentities
|
||||
^ List of lua entities, indexed by active object id
|
||||
|
||||
Deprecated but defined for backwards compatibility:
|
||||
minetest.digprop_constanttime(time)
|
||||
minetest.digprop_stonelike(toughness)
|
||||
minetest.digprop_dirtlike(toughness)
|
||||
minetest.digprop_gravellike(toughness)
|
||||
minetest.digprop_woodlike(toughness)
|
||||
minetest.digprop_leaveslike(toughness)
|
||||
minetest.digprop_glasslike(toughness)
|
||||
|
||||
Class reference
|
||||
----------------
|
||||
NodeMetaRef: Node metadata - reference extra data and functionality stored
|
||||
@@ -1379,6 +1704,11 @@ Player-only: (no-op for other objects)
|
||||
- get_look_yaw(): yaw in radians (wraps around pretty randomly as of now)
|
||||
- set_look_pitch(radians): sets look pitch
|
||||
- set_look_yaw(radians): sets look yaw
|
||||
- get_breath() : returns players breath
|
||||
- set_breath(value) : sets players breath
|
||||
values: 0 player is drowning,
|
||||
1-10 number of bubbles remain,
|
||||
11 bubbles bar is not shown
|
||||
- set_inventory_formspec(formspec)
|
||||
^ Redefine player's inventory form
|
||||
^ Should usually be called in on_joinplayer
|
||||
@@ -1387,10 +1717,13 @@ Player-only: (no-op for other objects)
|
||||
{jump=bool,right=bool,left=bool,LMB=bool,RMB=bool,sneak=bool,aux1=bool,down=bool,up=bool}
|
||||
- get_player_control_bits(): returns integer with bit packed player pressed keys
|
||||
bit nr/meaning: 0/up ,1/down ,2/left ,3/right ,4/jump ,5/aux1 ,6/sneak ,7/LMB ,8/RMB
|
||||
- set_physics_override(speed, jump, gravity)
|
||||
modifies per-player walking speed, jump height, and gravity.
|
||||
Values default to 1 and act as offsets to the physics settings
|
||||
in minetest.conf. nil will keep the current setting.
|
||||
- set_physics_override({
|
||||
speed = 1.0, -- multiplier to default value
|
||||
jump = 1.0, -- multiplier to default value
|
||||
gravity = 1.0, -- multiplier to default value
|
||||
sneak = true, -- whether player can sneak
|
||||
sneak_glitch = true, -- whether player can use the sneak glitch
|
||||
})
|
||||
- hud_add(hud definition): add a HUD element described by HUD def, returns ID number on success
|
||||
- hud_remove(id): remove the HUD element of the specified id
|
||||
- hud_change(id, stat, value): change a value of a previously added HUD element
|
||||
@@ -1402,12 +1735,17 @@ Player-only: (no-op for other objects)
|
||||
^ if a flag is nil, the flag is not modified
|
||||
- hud_set_hotbar_itemcount(count): sets number of items in builtin hotbar
|
||||
^ count: number of items, must be between 1 and 23
|
||||
- hud_set_hotbar_image(texturename)
|
||||
^ sets background image for hotbar
|
||||
- hud_set_hotbar_selected_image(texturename)
|
||||
^ sets image for selected item of hotbar
|
||||
|
||||
InvRef: Reference to an inventory
|
||||
methods:
|
||||
- is_empty(listname): return true if list is empty
|
||||
- get_size(listname): get size of a list
|
||||
- set_size(listname, size): set size of a list
|
||||
^ returns false on error (e.g. invalid listname or listsize)
|
||||
- get_width(listname): get width of a list
|
||||
- set_width(listname, width): set width of list; currently used for crafting
|
||||
- get_stack(listname, i): get a copy of stack index i in list
|
||||
@@ -1429,9 +1767,13 @@ ItemStack: A stack of items.
|
||||
methods:
|
||||
- is_empty(): return true if stack is empty
|
||||
- get_name(): returns item name (e.g. "default:stone")
|
||||
- set_name(itemname)
|
||||
- get_count(): returns number of items on the stack
|
||||
- set_count(count)
|
||||
- get_wear(): returns tool wear (0-65535), 0 for non-tools
|
||||
- set_wear(wear)
|
||||
- get_metadata(): returns metadata (a string attached to an item stack)
|
||||
- set_metadata(metadata)
|
||||
- clear(): removes all items from the stack, making it empty
|
||||
- replace(item): replace the contents of this stack (item can also
|
||||
be an itemstring or table)
|
||||
@@ -1469,6 +1811,108 @@ methods:
|
||||
- get2d(pos) -> 2d noise value at pos={x=,y=}
|
||||
- get3d(pos) -> 3d noise value at pos={x=,y=,z=}
|
||||
|
||||
PerlinNoiseMap: A fast, bulk perlin noise generator
|
||||
- Can be created via PerlinNoiseMap(noiseparams, size)
|
||||
- Also minetest.get_perlin_map(noiseparams, size)
|
||||
methods:
|
||||
- get2dMap(pos) -> <size.x>X<size.y> 2d array of 2d noise values starting at pos={x=,y=}
|
||||
- get3dMap(pos) -> <size.x>X<size.y>X<size.z> 3d array of 3d noise values starting at pos={x=,y=,z=}
|
||||
- get2dMap_flat(pos) -> Flat <size.x * size.y> element array of 2d noise values starting at pos={x=,y=}
|
||||
- get3dMap_flat(pos) -> Same as get2dMap_flat, but 3d noise
|
||||
|
||||
VoxelManip: An interface to the MapVoxelManipulator for Lua
|
||||
- Can be created via VoxelManip()
|
||||
- Also minetest.get_voxel_manip()
|
||||
methods:
|
||||
- read_from_map(p1, p2): Reads a chunk of map from the map containing the region formed by p1 and p2.
|
||||
^ returns actual emerged pmin, actual emerged pmax
|
||||
- write_to_map(): Writes the data loaded from the VoxelManip back to the map.
|
||||
^ important: data must be set using VoxelManip:set_data before calling this
|
||||
- get_data(): Gets the data read into the VoxelManip object
|
||||
^ returns raw node data is in the form of an array of node content ids
|
||||
- set_data(data): Sets the data contents of the VoxelManip object
|
||||
- update_map(): Update map after writing chunk back to map.
|
||||
^ To be used only by VoxelManip objects created by the mod itself; not a VoxelManip that was
|
||||
^ retrieved from minetest.get_mapgen_object
|
||||
- set_lighting(light, p1, p2): Set the lighting within the VoxelManip to a uniform value
|
||||
^ light is a table, {day=<0...15>, night=<0...15>}
|
||||
^ To be used only by a VoxelManip object from minetest.get_mapgen_object
|
||||
^ (p1, p2) is the area in which lighting is set; defaults to the whole area if left out
|
||||
- get_light_data(): Gets the light data read into the VoxelManip object
|
||||
^ Returns an array (indicies 1 to volume) of integers ranging from 0 to 255
|
||||
^ Each value is the bitwise combination of day and night light values (0..15 each)
|
||||
^ light = day + (night * 16)
|
||||
- set_light_data(light_data): Sets the param1 (light) contents of each node in the VoxelManip
|
||||
^ expects lighting data in the same format that get_light_data() returns
|
||||
- calc_lighting(p1, p2): Calculate lighting within the VoxelManip
|
||||
^ To be used only by a VoxelManip object from minetest.get_mapgen_object
|
||||
^ (p1, p2) is the area in which lighting is set; defaults to the whole area if left out
|
||||
- update_liquids(): Update liquid flow
|
||||
|
||||
VoxelArea: A helper class for voxel areas
|
||||
- Can be created via VoxelArea:new{MinEdge=pmin, MaxEdge=pmax}
|
||||
- Coordinates are *inclusive*, like most other things in Minetest
|
||||
methods:
|
||||
- getExtent(): returns a 3d vector containing the size of the area formed by MinEdge and MaxEdge
|
||||
- getVolume(): returns the volume of the area formed by MinEdge and MaxEdge
|
||||
- index(x, y, z): returns the index of an absolute position in a flat array starting at 1
|
||||
^ useful for things like VoxelManip, raw Schematic specifiers, PerlinNoiseMap:get2d/3dMap, and so on
|
||||
- indexp(p): same as above, except takes a vector
|
||||
- position(i): returns the absolute position vector corresponding to index i
|
||||
- contains(x, y, z): check if (x,y,z) is inside area formed by MinEdge and MaxEdge
|
||||
- containsp(p): same as above, except takes a vector
|
||||
- containsi(i): same as above, except takes an index
|
||||
- iter(minx, miny, minz, maxx, maxy, maxz): returns an iterator that returns indices
|
||||
^ from (minx,miny,minz) to (maxx,maxy,maxz) in the order of [z [y [x]]]
|
||||
- iterp(minp, maxp): same as above, except takes a vector
|
||||
|
||||
Settings: An interface to read config files in the format of minetest.conf
|
||||
- Can be created via Settings(filename)
|
||||
methods:
|
||||
- get(key) -> value
|
||||
- get_bool(key) -> boolean
|
||||
- set(key, value)
|
||||
- remove(key) -> success
|
||||
- get_names() -> {key1,...}
|
||||
- write() -> success
|
||||
^ write changes to file
|
||||
- to_table() -> {[key1]=value1,...}
|
||||
|
||||
Mapgen objects
|
||||
---------------
|
||||
A mapgen object is a construct used in map generation. Mapgen objects can be used by an on_generate
|
||||
callback to speed up operations by avoiding unnecessary recalculations; these can be retrieved using the
|
||||
minetest.get_mapgen_object() function. If the requested Mapgen object is unavailable, or
|
||||
get_mapgen_object() was called outside of an on_generate() callback, nil is returned.
|
||||
|
||||
The following Mapgen objects are currently available:
|
||||
|
||||
- voxelmanip
|
||||
This returns three values; the VoxelManip object to be used, minimum and maximum emerged position, in that
|
||||
order. All mapgens support this object.
|
||||
|
||||
- heightmap
|
||||
Returns an array containing the y coordinates of the ground levels of nodes in the most recently
|
||||
generated chunk by the current mapgen.
|
||||
|
||||
- biomemap
|
||||
Returns an array containing the biome IDs of nodes in the most recently generated chunk by the
|
||||
current mapgen.
|
||||
|
||||
- heatmap
|
||||
Returns an array containing the temperature values of nodes in the most recently generated chunk by
|
||||
the current mapgen.
|
||||
|
||||
- humiditymap
|
||||
Returns an array containing the humidity values of nodes in the most recently generated chunk by the
|
||||
current mapgen.
|
||||
|
||||
- gennotify
|
||||
Returns a table mapping requested generation notification types to arrays of positions at which the
|
||||
corresponding generated structures are located at within the current chunk. To set the capture of positions
|
||||
of interest to be recorded on generate, use minetest.set_gen_notify().
|
||||
Possible fields of the table returned are: dungeon, temple, cave_begin, cave_end, large_cave_begin, large_cave_end
|
||||
|
||||
Registered entities
|
||||
--------------------
|
||||
- Functions receive a "luaentity" as self:
|
||||
@@ -1479,7 +1923,7 @@ Registered entities
|
||||
- on_activate(self, staticdata)
|
||||
^ Called when the object is instantiated.
|
||||
- on_step(self, dtime)
|
||||
^ Called on every server tick (dtime is usually 0.05 seconds)
|
||||
^ Called on every server tick (dtime is usually 0.1 seconds)
|
||||
- on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
^ Called when somebody punches the object.
|
||||
^ Note that you probably want to handle most punches using the
|
||||
@@ -1563,6 +2007,7 @@ Object Properties
|
||||
{
|
||||
hp_max = 1,
|
||||
physical = true,
|
||||
collide_with_objects = true, -- collide with other objects if physical=true
|
||||
weight = 5,
|
||||
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
|
||||
visual = "cube"/"sprite"/"upright_sprite"/"mesh",
|
||||
@@ -1575,6 +2020,9 @@ Object Properties
|
||||
is_visible = true,
|
||||
makes_footstep_sound = false,
|
||||
automatic_rotate = false,
|
||||
stepheight = 0,
|
||||
automatic_face_movement_dir = 0.0,
|
||||
^ automatically set yaw to movement direction; offset in degrees; false to disable
|
||||
}
|
||||
|
||||
Entity definition (register_entity)
|
||||
@@ -1619,6 +2067,7 @@ Item definition (register_node, register_craftitem, register_tool)
|
||||
wield_image = "",
|
||||
wield_scale = {x=1,y=1,z=1},
|
||||
stack_max = 99,
|
||||
range = 4.0,
|
||||
liquids_pointable = false,
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
@@ -1654,6 +2103,15 @@ Item definition (register_node, register_craftitem, register_tool)
|
||||
eg. itemstack:take_item(); return itemstack
|
||||
^ Otherwise, the function is free to do what it wants.
|
||||
^ The default functions handle regular use cases.
|
||||
after_use = func(itemstack, user, node, digparams),
|
||||
^ default: nil
|
||||
^ If defined, should return an itemstack and will be called instead of
|
||||
wearing out the tool. If returns nil, does nothing.
|
||||
If after_use doesn't exist, it is the same as:
|
||||
function(itemstack, user, node, digparams)
|
||||
itemstack:add_wear(digparams.wear)
|
||||
return itemstack
|
||||
end
|
||||
}
|
||||
|
||||
Tile definition:
|
||||
@@ -1673,6 +2131,10 @@ Node definition (register_node)
|
||||
|
||||
drawtype = "normal", -- See "Node drawtypes"
|
||||
visual_scale = 1.0,
|
||||
^ Supported for drawtypes "plantlike", "signlike", "torchlike".
|
||||
^ For plantlike, the image will start at the bottom of the node; for the
|
||||
^ other drawtypes, the image will be centered on the node.
|
||||
^ Note that positioning for "torchlike" may still change.
|
||||
tiles = {tile definition 1, def2, def3, def4, def5, def6},
|
||||
^ Textures of node; +Y, -Y, +X, -X, +Z, -Z (old field name: tile_images)
|
||||
^ List can be shortened to needed length
|
||||
@@ -1696,8 +2158,11 @@ Node definition (register_node)
|
||||
liquid_alternative_flowing = "", -- Flowing version of source liquid
|
||||
liquid_alternative_source = "", -- Source version of flowing liquid
|
||||
liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7)
|
||||
liquid_renewable = true, -- Can new liquid source be created by placing
|
||||
two or more sources nearly?
|
||||
liquid_renewable = true, -- Can new liquid source be created by placing two or more sources nearby?
|
||||
freezemelt = "", -- water for snow/ice, ice/snow for water
|
||||
leveled = 0, -- Block contain level in param2. value - default level, used for snow. Dont forget use "leveled" type nodebox
|
||||
liquid_range = 8, -- number of flowing nodes arround source (max. 8)
|
||||
drowning = 0, -- Player will take this amount of damage if no bubbles are left
|
||||
light_source = 0, -- Amount of light emitted by node
|
||||
damage_per_second = 0, -- If player is inside node, this damage is caused
|
||||
node_box = {type="regular"}, -- See "Node boxes"
|
||||
@@ -1835,9 +2300,10 @@ Recipe for register_craft (furnace fuel)
|
||||
|
||||
Ore definition (register_ore)
|
||||
{
|
||||
ore_type = "scatter" -- See "Ore types"
|
||||
ore_type = "scatter", -- See "Ore types"
|
||||
ore = "default:stone_with_coal",
|
||||
wherein = "default:stone",
|
||||
^ a list of nodenames is supported too
|
||||
clust_scarcity = 8*8*8,
|
||||
^ Ore has a 1 out of clust_scarcity chance of spawning in a node
|
||||
^ This value should be *MUCH* higher than your intuition might tell you!
|
||||
@@ -1857,6 +2323,61 @@ Ore definition (register_ore)
|
||||
^ Needed for sheet ore_type. Omit from scatter ore_type for a uniform ore distribution
|
||||
}
|
||||
|
||||
Decoration definition (register_decoration)
|
||||
{
|
||||
deco_type = "simple", -- See "Decoration types"
|
||||
place_on = "default:dirt_with_grass",
|
||||
^ Node that decoration can be placed on
|
||||
sidelen = 8,
|
||||
^ Size of divisions made in the chunk being generated.
|
||||
^ If the chunk size is not evenly divisible by sidelen, sidelen is made equal to the chunk size.
|
||||
fill_ratio = 0.02,
|
||||
^ Ratio of the area to be uniformly filled by the decoration.
|
||||
^ Used only if noise_params is not specified.
|
||||
noise_params = {offset=0, scale=.45, spread={x=100, y=100, z=100}, seed=354, octaves=3, persist=0.7},
|
||||
^ NoiseParams structure describing the perlin noise used for decoration distribution.
|
||||
^ The result of this is multiplied by the 2d area of the division being decorated.
|
||||
biomes = {"Oceanside", "Hills", "Plains"},
|
||||
^ List of biomes in which this decoration occurs. Occurs in all biomes if this is omitted,
|
||||
^ and ignored if the Mapgen being used does not support biomes.
|
||||
|
||||
----- Simple-type parameters
|
||||
decoration = "default:grass",
|
||||
^ The node name used as the decoration.
|
||||
^ If instead a list of strings, a randomly selected node from the list is placed as the decoration.
|
||||
height = 1,
|
||||
^ Number of nodes high the decoration is made.
|
||||
^ If height_max is not 0, this is the lower bound of the randomly selected height.
|
||||
height_max = 0,
|
||||
^ Number of nodes the decoration can be at maximum.
|
||||
^ If absent, the parameter 'height' is used as a constant.
|
||||
spawn_by = "default:water",
|
||||
^ Node that the decoration only spawns next to, in a 1-node square radius.
|
||||
num_spawn_by = 1,
|
||||
^ Number of spawn_by nodes that must be surrounding the decoration position to occur.
|
||||
^ If absent or -1, decorations occur next to any nodes.
|
||||
|
||||
----- Schematic-type parameters
|
||||
schematic = "foobar.mts",
|
||||
^ If schematic is a string, it is the filepath relative to the current working directory of the
|
||||
^ specified Minetest schematic file.
|
||||
^ - OR -, could instead be a table containing two fields, size and data:
|
||||
schematic = {
|
||||
size = {x=4, y=6, z=4},
|
||||
data = {
|
||||
{name="cobble", param1=255, param2=0},
|
||||
{name="dirt_with_grass", param1=255, param2=0},
|
||||
...
|
||||
}
|
||||
},
|
||||
^ See 'Schematic specifier' for details.
|
||||
replacements = {{"oldname", "convert_to"}, ...},
|
||||
flags = "place_center_x, place_center_z",
|
||||
^ Flags for schematic decorations. See 'Schematic attributes'.
|
||||
rotation = "90" --rotate schematic 90 degrees on placement
|
||||
^ Rotation can be "0", "90", "180", "270", or "random".
|
||||
}
|
||||
|
||||
Chatcommand definition (register_chatcommand)
|
||||
{
|
||||
params = "<name> <privilege>", -- short parameter description
|
||||
|
||||
207
doc/menu_lua_api.txt
Normal file
@@ -0,0 +1,207 @@
|
||||
Minetest Lua Mainmenu API Reference 0.4.9
|
||||
========================================
|
||||
|
||||
Introduction
|
||||
-------------
|
||||
The main menu is defined as a formspec by Lua in builtin/mainmenu.lua
|
||||
Description of formspec language to show your menu is in lua_api.txt
|
||||
|
||||
Callbacks
|
||||
---------
|
||||
engine.buttonhandler(fields): called when a button is pressed.
|
||||
^ fields = {name1 = value1, name2 = value2, ...}
|
||||
engine.event_handler(event)
|
||||
^ event: "MenuQuit", "KeyEnter", "ExitButton" or "EditBoxEnter"
|
||||
|
||||
Gamedata
|
||||
--------
|
||||
The "gamedata" table is read when calling engine.start(). It should contain:
|
||||
{
|
||||
playername = <name>,
|
||||
password = <password>,
|
||||
address = <IP/adress>,
|
||||
port = <port>,
|
||||
selected_world = <index>, -- 0 for client mode
|
||||
singleplayer = <true/false>,
|
||||
}
|
||||
|
||||
Functions
|
||||
---------
|
||||
engine.start()
|
||||
engine.close()
|
||||
|
||||
Filesystem:
|
||||
engine.get_scriptdir()
|
||||
^ returns directory of script
|
||||
engine.get_modpath() (possible in async calls)
|
||||
^ returns path to global modpath
|
||||
engine.get_modstore_details(modid) (possible in async calls)
|
||||
^ modid numeric id of mod in modstore
|
||||
^ returns {
|
||||
id = <numeric id of mod in modstore>,
|
||||
title = <human readable title>,
|
||||
basename = <basename for mod>,
|
||||
description = <description of mod>,
|
||||
author = <author of mod>,
|
||||
download_url= <best match download url>,
|
||||
license = <short description of license>,
|
||||
rating = <float value of current rating>
|
||||
}
|
||||
engine.get_modstore_list() (possible in async calls)
|
||||
^ returns {
|
||||
[1] = {
|
||||
id = <numeric id of mod in modstore>,
|
||||
title = <human readable title>,
|
||||
basename = <basename for mod>
|
||||
}
|
||||
}
|
||||
engine.get_gamepath() (possible in async calls)
|
||||
^ returns path to global gamepath
|
||||
engine.get_texturepath() (possible in async calls)
|
||||
^ returns path to default textures
|
||||
engine.get_dirlist(path,onlydirs) (possible in async calls)
|
||||
^ path to get subdirs from
|
||||
^ onlydirs should result contain only dirs?
|
||||
^ returns list of folders within path
|
||||
engine.create_dir(absolute_path) (possible in async calls)
|
||||
^ absolute_path to directory to create (needs to be absolute)
|
||||
^ returns true/false
|
||||
engine.delete_dir(absolute_path) (possible in async calls)
|
||||
^ absolute_path to directory to delete (needs to be absolute)
|
||||
^ returns true/false
|
||||
engine.copy_dir(source,destination,keep_soure) (possible in async calls)
|
||||
^ source folder
|
||||
^ destination folder
|
||||
^ keep_source DEFAULT true --> if set to false source is deleted after copying
|
||||
^ returns true/false
|
||||
engine.extract_zip(zipfile,destination) [unzip within path required]
|
||||
^ zipfile to extract
|
||||
^ destination folder to extract to
|
||||
^ returns true/false
|
||||
engine.download_file(url,target) (possible in async calls)
|
||||
^ url to download
|
||||
^ target to store to
|
||||
^ returns true/false
|
||||
engine.get_version() (possible in async calls)
|
||||
^ returns current minetest version
|
||||
engine.sound_play(spec, looped) -> handle
|
||||
^ spec = SimpleSoundSpec (see lua-api.txt)
|
||||
^ looped = bool
|
||||
engine.sound_stop(handle)
|
||||
|
||||
GUI:
|
||||
engine.update_formspec(formspec)
|
||||
- engine.set_background(type, texturepath)
|
||||
^ type: "background", "overlay", "header" or "footer"
|
||||
engine.set_clouds(<true/false>)
|
||||
engine.set_topleft_text(text)
|
||||
|
||||
Games:
|
||||
engine.get_game(index)
|
||||
^ returns {
|
||||
id = <id>,
|
||||
path = <full path to game>,
|
||||
gamemods_path = <path>,
|
||||
name = <name of game>,
|
||||
menuicon_path = <full path to menuicon>,
|
||||
DEPRECATED:
|
||||
addon_mods_paths = {[1] = <path>,},
|
||||
}
|
||||
engine.get_games() -> table of all games in upper format (possible in async calls)
|
||||
|
||||
Favorites:
|
||||
engine.get_favorites(location) -> list of favorites (possible in async calls)
|
||||
^ location: "local" or "online"
|
||||
^ returns {
|
||||
[1] = {
|
||||
clients = <number of clients/nil>,
|
||||
clients_max = <maximum number of clients/nil>,
|
||||
version = <server version/nil>,
|
||||
password = <true/nil>,
|
||||
creative = <true/nil>,
|
||||
damage = <true/nil>,
|
||||
pvp = <true/nil>,
|
||||
description = <server description/nil>,
|
||||
name = <server name/nil>,
|
||||
address = <address of server/nil>,
|
||||
port = <port>
|
||||
},
|
||||
}
|
||||
engine.delete_favorite(id, location) -> success
|
||||
|
||||
Logging:
|
||||
engine.debug(line) (possible in async calls)
|
||||
^ Always printed to stderr and logfile (print() is redirected here)
|
||||
engine.log(line) (possible in async calls)
|
||||
engine.log(loglevel, line) (possible in async calls)
|
||||
^ loglevel one of "error", "action", "info", "verbose"
|
||||
|
||||
Settings:
|
||||
engine.setting_set(name, value)
|
||||
engine.setting_get(name) -> string or nil (possible in async calls)
|
||||
engine.setting_setbool(name, value)
|
||||
engine.setting_getbool(name) -> bool or nil (possible in async calls)
|
||||
engine.setting_save() -> nil, save all settings to config file
|
||||
|
||||
Worlds:
|
||||
engine.get_worlds() -> list of worlds (possible in async calls)
|
||||
^ returns {
|
||||
[1] = {
|
||||
path = <full path to world>,
|
||||
name = <name of world>,
|
||||
gameid = <gameid of world>,
|
||||
},
|
||||
}
|
||||
engine.create_world(worldname, gameid)
|
||||
engine.delete_world(index)
|
||||
|
||||
|
||||
UI:
|
||||
engine.get_textlist_index(textlistname) -> index
|
||||
engine.show_keys_menu()
|
||||
engine.file_open_dialog(formname,caption)
|
||||
^ shows a file open dialog
|
||||
^ formname is base name of dialog response returned in fields
|
||||
^ -if dialog was accepted "_accepted"
|
||||
^^ will be added to fieldname containing the path
|
||||
^ -if dialog was canceled "_cancelled"
|
||||
^ will be added to fieldname value is set to formname itself
|
||||
^ returns nil or selected file/folder
|
||||
|
||||
Helpers:
|
||||
engine.formspec_escape(string) -> string
|
||||
^ escapes characters [ ] \ , ; that can not be used in formspecs
|
||||
engine.gettext(string) -> string
|
||||
^ look up the translation of a string in the gettext message catalog
|
||||
fgettext(string, ...) -> string
|
||||
^ call engine.gettext(string), replace "$1"..."$9" with the given
|
||||
^ extra arguments, call engine.formspec_escape and return the result
|
||||
engine.parse_json(string[, nullvalue]) -> something (possible in async calls)
|
||||
^ see minetest.parse_json (lua_api.txt)
|
||||
dump(obj, dumped={})
|
||||
^ Return object serialized as a string
|
||||
string:split(separator)
|
||||
^ eg. string:split("a,b", ",") == {"a","b"}
|
||||
string:trim()
|
||||
^ eg. string.trim("\n \t\tfoo bar\t ") == "foo bar"
|
||||
minetest.is_yes(arg) (possible in async calls)
|
||||
^ returns whether arg can be interpreted as yes
|
||||
|
||||
Async:
|
||||
engine.handle_async(async_job,parameters,finished)
|
||||
^ execute a function asynchronously
|
||||
^ async_job is a function receiving one parameter and returning one parameter
|
||||
^ parameters parameter table passed to async_job
|
||||
^ finished function to be called once async_job has finished
|
||||
^ the result of async_job is passed to this function
|
||||
|
||||
Limitations of Async operations
|
||||
-No access to global lua variables, don't even try
|
||||
-Limited set of available functions
|
||||
e.g. No access to functions modifying menu like engine.start,engine.close,
|
||||
engine.file_open_dialog
|
||||
|
||||
|
||||
Class reference
|
||||
----------------
|
||||
Settings: see lua_api.txt
|
||||
@@ -1,5 +1,5 @@
|
||||
.\" Minetest man page
|
||||
.TH minetest 6 "11 March 2012" "" ""
|
||||
.TH minetest 6 "10 September 2013" "" ""
|
||||
|
||||
.SH NAME
|
||||
minetest \- Multiplayer infinite-world block sandbox
|
||||
@@ -37,6 +37,9 @@ Disable main menu
|
||||
\-\-help
|
||||
Show allowed options
|
||||
.TP
|
||||
\-\-version
|
||||
Show version information
|
||||
.TP
|
||||
\-\-logfile <value>
|
||||
Set logfile path (debug.txt)
|
||||
.TP
|
||||
@@ -75,6 +78,10 @@ Print enormous amounts of information to console
|
||||
.TP
|
||||
\-\-world <value>
|
||||
Set world path
|
||||
.TP
|
||||
\-\-migrate <value>
|
||||
Migrate from current map backend to another. Possible values are sqlite3
|
||||
and leveldb. Only works when using --server.
|
||||
|
||||
.SH BUGS
|
||||
Please report all bugs to Perttu Ahola <celeron55@gmail.com>.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.\" Minetestserver man page
|
||||
.TH minetestserver 6 "11 March 2012" "" ""
|
||||
.TH minetestserver 6 "10 September 2013" "" ""
|
||||
|
||||
.SH NAME
|
||||
minetestserver \- Minetest server
|
||||
@@ -31,6 +31,9 @@ Set gameid
|
||||
\-\-help
|
||||
Show allowed options
|
||||
.TP
|
||||
\-\-version
|
||||
Show version information
|
||||
.TP
|
||||
\-\-logfile <value>
|
||||
Set logfile path (debug.txt)
|
||||
.TP
|
||||
@@ -51,6 +54,10 @@ Print enormous amounts of information to console
|
||||
.TP
|
||||
\-\-world <value>
|
||||
Set world path
|
||||
.TP
|
||||
\-\-migrate <value>
|
||||
Migrate from current map backend to another. Possible values are sqlite3
|
||||
and leveldb.
|
||||
|
||||
.SH BUGS
|
||||
Please report all bugs to Perttu Ahola <celeron55@gmail.com>.
|
||||
|
||||
BIN
fonts/DroidSansFallbackFull.ttf
Normal file
BIN
fonts/fontdejavusansmono.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
fonts/fontlucida.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 392 B |
|
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 218 B |
|
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 182 B |
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 183 B |
|
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 180 B |
@@ -712,7 +712,6 @@ end
|
||||
minetest.register_node("default:stone", {
|
||||
description = "Stone",
|
||||
tiles ={"default_stone.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3},
|
||||
drop = 'default:cobble',
|
||||
legacy_mineral = true,
|
||||
@@ -722,7 +721,6 @@ minetest.register_node("default:stone", {
|
||||
minetest.register_node("default:stone_with_coal", {
|
||||
description = "Stone with coal",
|
||||
tiles ={"default_stone.png^default_mineral_coal.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3},
|
||||
drop = 'default:coal_lump',
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
@@ -731,7 +729,6 @@ minetest.register_node("default:stone_with_coal", {
|
||||
minetest.register_node("default:stone_with_iron", {
|
||||
description = "Stone with iron",
|
||||
tiles ={"default_stone.png^default_mineral_iron.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3},
|
||||
drop = 'default:iron_lump',
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
@@ -740,7 +737,6 @@ minetest.register_node("default:stone_with_iron", {
|
||||
minetest.register_node("default:dirt_with_grass", {
|
||||
description = "Dirt with grass",
|
||||
tiles ={"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3, soil=1},
|
||||
drop = 'default:dirt',
|
||||
sounds = default.node_sound_dirt_defaults({
|
||||
@@ -751,7 +747,6 @@ minetest.register_node("default:dirt_with_grass", {
|
||||
minetest.register_node("default:dirt_with_grass_footsteps", {
|
||||
description = "Dirt with grass and footsteps",
|
||||
tiles ={"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3, soil=1},
|
||||
drop = 'default:dirt',
|
||||
sounds = default.node_sound_dirt_defaults({
|
||||
@@ -762,7 +757,6 @@ minetest.register_node("default:dirt_with_grass_footsteps", {
|
||||
minetest.register_node("default:dirt", {
|
||||
description = "Dirt",
|
||||
tiles ={"default_dirt.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3, soil=1},
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
})
|
||||
@@ -770,7 +764,6 @@ minetest.register_node("default:dirt", {
|
||||
minetest.register_node("default:sand", {
|
||||
description = "Sand",
|
||||
tiles ={"default_sand.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3, falling_node=1},
|
||||
sounds = default.node_sound_sand_defaults(),
|
||||
})
|
||||
@@ -778,7 +771,6 @@ minetest.register_node("default:sand", {
|
||||
minetest.register_node("default:gravel", {
|
||||
description = "Gravel",
|
||||
tiles ={"default_gravel.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=2, falling_node=1},
|
||||
sounds = default.node_sound_dirt_defaults({
|
||||
footstep = {name="default_gravel_footstep", gain=0.45},
|
||||
@@ -788,7 +780,6 @@ minetest.register_node("default:gravel", {
|
||||
minetest.register_node("default:sandstone", {
|
||||
description = "Sandstone",
|
||||
tiles ={"default_sandstone.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=2,cracky=2},
|
||||
drop = 'default:sand',
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
@@ -797,7 +788,6 @@ minetest.register_node("default:sandstone", {
|
||||
minetest.register_node("default:clay", {
|
||||
description = "Clay",
|
||||
tiles ={"default_clay.png"},
|
||||
is_ground_content = true,
|
||||
groups = {crumbly=3},
|
||||
drop = 'default:clay_lump 4',
|
||||
sounds = default.node_sound_dirt_defaults({
|
||||
@@ -808,7 +798,6 @@ minetest.register_node("default:clay", {
|
||||
minetest.register_node("default:brick", {
|
||||
description = "Brick",
|
||||
tiles ={"default_brick.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3},
|
||||
drop = 'default:clay_brick 4',
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
@@ -817,7 +806,6 @@ minetest.register_node("default:brick", {
|
||||
minetest.register_node("default:tree", {
|
||||
description = "Tree",
|
||||
tiles ={"default_tree_top.png", "default_tree_top.png", "default_tree.png"},
|
||||
is_ground_content = true,
|
||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
@@ -825,7 +813,6 @@ minetest.register_node("default:tree", {
|
||||
minetest.register_node("default:jungletree", {
|
||||
description = "Jungle Tree",
|
||||
tiles ={"default_jungletree_top.png", "default_jungletree_top.png", "default_jungletree.png"},
|
||||
is_ground_content = true,
|
||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=1},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
@@ -849,6 +836,7 @@ minetest.register_node("default:leaves", {
|
||||
visual_scale = 1.3,
|
||||
tiles ={"default_leaves.png"},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
groups = {snappy=3},
|
||||
drop = {
|
||||
max_items = 1,
|
||||
@@ -871,7 +859,6 @@ minetest.register_node("default:leaves", {
|
||||
minetest.register_node("default:cactus", {
|
||||
description = "Cactus",
|
||||
tiles ={"default_cactus_top.png", "default_cactus_top.png", "default_cactus_side.png"},
|
||||
is_ground_content = true,
|
||||
groups = {snappy=2,choppy=3},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
@@ -883,7 +870,6 @@ minetest.register_node("default:papyrus", {
|
||||
inventory_image = "default_papyrus.png",
|
||||
wield_image = "default_papyrus.png",
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
walkable = false,
|
||||
groups = {snappy=3},
|
||||
sounds = default.node_sound_leaves_defaults(),
|
||||
@@ -892,7 +878,6 @@ minetest.register_node("default:papyrus", {
|
||||
minetest.register_node("default:bookshelf", {
|
||||
description = "Bookshelf",
|
||||
tiles ={"default_wood.png", "default_wood.png", "default_bookshelf.png"},
|
||||
is_ground_content = true,
|
||||
groups = {snappy=2,choppy=3,oddly_breakable_by_hand=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
@@ -904,7 +889,6 @@ minetest.register_node("default:glass", {
|
||||
inventory_image = minetest.inventorycube("default_glass.png"),
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = true,
|
||||
groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
@@ -916,7 +900,6 @@ minetest.register_node("default:fence_wood", {
|
||||
inventory_image = "default_fence.png",
|
||||
wield_image = "default_fence.png",
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7},
|
||||
@@ -932,7 +915,6 @@ minetest.register_node("default:rail", {
|
||||
inventory_image = "default_rail.png",
|
||||
wield_image = "default_rail.png",
|
||||
paramtype = "light",
|
||||
is_ground_content = true,
|
||||
walkable = false,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
@@ -949,7 +931,6 @@ minetest.register_node("default:ladder", {
|
||||
wield_image = "default_ladder.png",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
is_ground_content = true,
|
||||
walkable = false,
|
||||
climbable = true,
|
||||
selection_box = {
|
||||
@@ -966,7 +947,6 @@ minetest.register_node("default:ladder", {
|
||||
minetest.register_node("default:wood", {
|
||||
description = "Wood",
|
||||
tiles ={"default_wood.png"},
|
||||
is_ground_content = true,
|
||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
@@ -974,7 +954,6 @@ minetest.register_node("default:wood", {
|
||||
minetest.register_node("default:mese", {
|
||||
description = "Mese",
|
||||
tiles ={"default_mese.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=1,level=2},
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
@@ -982,7 +961,6 @@ minetest.register_node("default:mese", {
|
||||
minetest.register_node("default:cloud", {
|
||||
description = "Cloud",
|
||||
tiles ={"default_cloud.png"},
|
||||
is_ground_content = true,
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
|
||||
@@ -1001,6 +979,7 @@ minetest.register_node("default:water_flowing", {
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
drowning = 1,
|
||||
liquidtype = "flowing",
|
||||
liquid_alternative_flowing = "default:water_flowing",
|
||||
liquid_alternative_source = "default:water_source",
|
||||
@@ -1024,6 +1003,7 @@ minetest.register_node("default:water_source", {
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
drowning = 1,
|
||||
liquidtype = "source",
|
||||
liquid_alternative_flowing = "default:water_flowing",
|
||||
liquid_alternative_source = "default:water_source",
|
||||
@@ -1055,6 +1035,7 @@ minetest.register_node("default:lava_flowing", {
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
drowning = 1,
|
||||
liquidtype = "flowing",
|
||||
liquid_alternative_flowing = "default:lava_flowing",
|
||||
liquid_alternative_source = "default:lava_source",
|
||||
@@ -1082,6 +1063,7 @@ minetest.register_node("default:lava_source", {
|
||||
pointable = false,
|
||||
diggable = false,
|
||||
buildable_to = true,
|
||||
drowning = 1,
|
||||
liquidtype = "source",
|
||||
liquid_alternative_flowing = "default:lava_flowing",
|
||||
liquid_alternative_source = "default:lava_source",
|
||||
@@ -1100,6 +1082,7 @@ minetest.register_node("default:torch", {
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
light_source = LIGHT_MAX-1,
|
||||
selection_box = {
|
||||
@@ -1122,6 +1105,7 @@ minetest.register_node("default:sign_wall", {
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
walkable = false,
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
@@ -1156,6 +1140,7 @@ minetest.register_node("default:chest", {
|
||||
paramtype2 = "facedir",
|
||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
@@ -1188,6 +1173,7 @@ minetest.register_node("default:chest_locked", {
|
||||
paramtype2 = "facedir",
|
||||
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
@@ -1273,6 +1259,7 @@ minetest.register_node("default:furnace", {
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2},
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
@@ -1306,6 +1293,7 @@ minetest.register_node("default:furnace_active", {
|
||||
drop = "default:furnace",
|
||||
groups = {cracky=2},
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
@@ -1330,18 +1318,13 @@ minetest.register_node("default:furnace_active", {
|
||||
end,
|
||||
})
|
||||
|
||||
function hacky_swap_node(pos,name)
|
||||
function swap_node(pos,name)
|
||||
local node = minetest.get_node(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local meta0 = meta:to_table()
|
||||
if node.name == name then
|
||||
return
|
||||
end
|
||||
node.name = name
|
||||
local meta0 = meta:to_table()
|
||||
minetest.set_node(pos,node)
|
||||
meta = minetest.get_meta(pos)
|
||||
meta:from_table(meta0)
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
@@ -1396,7 +1379,7 @@ minetest.register_abm({
|
||||
local percent = math.floor(meta:get_float("fuel_time") /
|
||||
meta:get_float("fuel_totaltime") * 100)
|
||||
meta:set_string("infotext","Furnace active: "..percent.."%")
|
||||
hacky_swap_node(pos,"default:furnace_active")
|
||||
swap_node(pos,"default:furnace_active")
|
||||
meta:set_string("formspec",
|
||||
"size[8,9]"..
|
||||
"image[2,2;1,1;default_furnace_fire_bg.png^[lowpart:"..
|
||||
@@ -1422,7 +1405,7 @@ minetest.register_abm({
|
||||
|
||||
if fuel.time <= 0 then
|
||||
meta:set_string("infotext","Furnace out of fuel")
|
||||
hacky_swap_node(pos,"default:furnace")
|
||||
swap_node(pos,"default:furnace")
|
||||
meta:set_string("formspec", default.furnace_inactive_formspec)
|
||||
return
|
||||
end
|
||||
@@ -1430,7 +1413,7 @@ minetest.register_abm({
|
||||
if cooked.item:is_empty() then
|
||||
if was_active then
|
||||
meta:set_string("infotext","Furnace is empty")
|
||||
hacky_swap_node(pos,"default:furnace")
|
||||
swap_node(pos,"default:furnace")
|
||||
meta:set_string("formspec", default.furnace_inactive_formspec)
|
||||
end
|
||||
return
|
||||
@@ -1448,7 +1431,6 @@ minetest.register_abm({
|
||||
minetest.register_node("default:cobble", {
|
||||
description = "Cobble",
|
||||
tiles ={"default_cobble.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
@@ -1456,7 +1438,6 @@ minetest.register_node("default:cobble", {
|
||||
minetest.register_node("default:mossycobble", {
|
||||
description = "Mossy Cobble",
|
||||
tiles ={"default_mossycobble.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
@@ -1464,7 +1445,6 @@ minetest.register_node("default:mossycobble", {
|
||||
minetest.register_node("default:steelblock", {
|
||||
description = "Steel Block",
|
||||
tiles ={"default_steel_block.png"},
|
||||
is_ground_content = true,
|
||||
groups = {snappy=1,bendy=2},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
@@ -1477,6 +1457,7 @@ minetest.register_node("default:nyancat", {
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2},
|
||||
legacy_facedir_simple = true,
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
|
||||
@@ -1484,6 +1465,7 @@ minetest.register_node("default:nyancat_rainbow", {
|
||||
description = "Nyancat Rainbow",
|
||||
tiles ={"default_nc_rb.png"},
|
||||
inventory_image = "default_nc_rb.png",
|
||||
is_ground_content = false,
|
||||
groups = {cracky=2},
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
@@ -1515,6 +1497,133 @@ minetest.register_node("default:apple", {
|
||||
sounds = default.node_sound_defaults(),
|
||||
})
|
||||
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_ignore = minetest.get_content_id("ignore")
|
||||
local c_tree = minetest.get_content_id("default:tree")
|
||||
local c_leaves = minetest.get_content_id("default:leaves")
|
||||
local c_apple = minetest.get_content_id("default:apple")
|
||||
function default.grow_tree(data, a, pos, is_apple_tree, seed)
|
||||
--[[
|
||||
NOTE: Tree-placing code is currently duplicated in the engine
|
||||
and in games that have saplings; both are deprecated but not
|
||||
replaced yet
|
||||
]]--
|
||||
local pr = PseudoRandom(seed)
|
||||
local th = pr:next(4, 5)
|
||||
local x, y, z = pos.x, pos.y, pos.z
|
||||
for yy = y, y+th-1 do
|
||||
local vi = a:index(x, yy, z)
|
||||
if a:contains(x, yy, z) and (data[vi] == c_air or yy == y) then
|
||||
data[vi] = c_tree
|
||||
end
|
||||
end
|
||||
y = y+th-1 -- (x, y, z) is now last piece of trunk
|
||||
local leaves_a = VoxelArea:new{MinEdge={x=-2, y=-1, z=-2}, MaxEdge={x=2, y=2, z=2}}
|
||||
local leaves_buffer = {}
|
||||
|
||||
-- Force leaves near the trunk
|
||||
local d = 1
|
||||
for xi = -d, d do
|
||||
for yi = -d, d do
|
||||
for zi = -d, d do
|
||||
leaves_buffer[leaves_a:index(xi, yi, zi)] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add leaves randomly
|
||||
for iii = 1, 8 do
|
||||
local d = 1
|
||||
local xx = pr:next(leaves_a.MinEdge.x, leaves_a.MaxEdge.x - d)
|
||||
local yy = pr:next(leaves_a.MinEdge.y, leaves_a.MaxEdge.y - d)
|
||||
local zz = pr:next(leaves_a.MinEdge.z, leaves_a.MaxEdge.z - d)
|
||||
|
||||
for xi = 0, d do
|
||||
for yi = 0, d do
|
||||
for zi = 0, d do
|
||||
leaves_buffer[leaves_a:index(xx+xi, yy+yi, zz+zi)] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add the leaves
|
||||
for xi = leaves_a.MinEdge.x, leaves_a.MaxEdge.x do
|
||||
for yi = leaves_a.MinEdge.y, leaves_a.MaxEdge.y do
|
||||
for zi = leaves_a.MinEdge.z, leaves_a.MaxEdge.z do
|
||||
if a:contains(x+xi, y+yi, z+zi) then
|
||||
local vi = a:index(x+xi, y+yi, z+zi)
|
||||
if data[vi] == c_air or data[vi] == c_ignore then
|
||||
if leaves_buffer[leaves_a:index(xi, yi, zi)] then
|
||||
if is_apple_tree and pr:next(1, 100) <= 10 then
|
||||
data[vi] = c_apple
|
||||
else
|
||||
data[vi] = c_leaves
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"default:sapling"},
|
||||
interval = 10,
|
||||
chance = 50,
|
||||
action = function(pos, node)
|
||||
local is_soil = minetest.registered_nodes[minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name].groups.soil
|
||||
if is_soil == nil or is_soil == 0 then return end
|
||||
print("A sapling grows into a tree at "..minetest.pos_to_string(pos))
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local minp, maxp = vm:read_from_map({x=pos.x-16, y=pos.y, z=pos.z-16}, {x=pos.x+16, y=pos.y+16, z=pos.z+16})
|
||||
local a = VoxelArea:new{MinEdge=minp, MaxEdge=maxp}
|
||||
local data = vm:get_data()
|
||||
default.grow_tree(data, a, pos, math.random(1, 4) == 1, math.random(1,100000))
|
||||
vm:set_data(data)
|
||||
vm:write_to_map(data)
|
||||
vm:update_map()
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"default:dirt"},
|
||||
interval = 2,
|
||||
chance = 200,
|
||||
action = function(pos, node)
|
||||
local above = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local name = minetest.get_node(above).name
|
||||
local nodedef = minetest.registered_nodes[name]
|
||||
if nodedef and (nodedef.sunlight_propagates or nodedef.paramtype == "light")
|
||||
and nodedef.liquidtype == "none"
|
||||
and (minetest.get_node_light(above) or 0) >= 13 then
|
||||
if name == "default:snow" or name == "default:snowblock" then
|
||||
minetest.set_node(pos, {name = "default:dirt_with_snow"})
|
||||
else
|
||||
minetest.set_node(pos, {name = "default:dirt_with_grass"})
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"default:dirt_with_grass"},
|
||||
interval = 2,
|
||||
chance = 20,
|
||||
action = function(pos, node)
|
||||
local above = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
local name = minetest.get_node(above).name
|
||||
local nodedef = minetest.registered_nodes[name]
|
||||
if name ~= "ignore" and nodedef
|
||||
and not ((nodedef.sunlight_propagates or nodedef.paramtype == "light")
|
||||
and nodedef.liquidtype == "none") then
|
||||
minetest.set_node(pos, {name = "default:dirt"})
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
--
|
||||
-- Crafting items
|
||||
--
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
-- Aliases for map generator outputs
|
||||
--
|
||||
|
||||
minetest.register_alias("mapgen_air", "air")
|
||||
minetest.register_alias("mapgen_stone", "default:stone")
|
||||
minetest.register_alias("mapgen_tree", "default:tree")
|
||||
minetest.register_alias("mapgen_leaves", "default:leaves")
|
||||
@@ -22,6 +21,7 @@ minetest.register_alias("mapgen_junglegrass", "default:junglegrass")
|
||||
minetest.register_alias("mapgen_stone_with_coal", "default:stone_with_coal")
|
||||
minetest.register_alias("mapgen_stone_with_iron", "default:stone_with_iron")
|
||||
minetest.register_alias("mapgen_mese", "default:mese")
|
||||
minetest.register_alias("mapgen_stair_cobble", "stairs:stair_cobble")
|
||||
|
||||
--
|
||||
-- Ore generation
|
||||
|
||||
BIN
games/minimal/mods/default/textures/bubble.png
Normal file
|
After Width: | Height: | Size: 273 B |
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 255 B |
|
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 157 B |
|
Before Width: | Height: | Size: 597 B After Width: | Height: | Size: 515 B |
|
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 279 B After Width: | Height: | Size: 144 B |
|
Before Width: | Height: | Size: 236 B After Width: | Height: | Size: 121 B |
|
Before Width: | Height: | Size: 167 B After Width: | Height: | Size: 114 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 151 B After Width: | Height: | Size: 98 B |
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 613 B After Width: | Height: | Size: 318 B |
|
Before Width: | Height: | Size: 249 B After Width: | Height: | Size: 173 B |
|
Before Width: | Height: | Size: 210 B After Width: | Height: | Size: 140 B |
|
Before Width: | Height: | Size: 118 B After Width: | Height: | Size: 83 B |
|
Before Width: | Height: | Size: 933 B After Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 830 B After Width: | Height: | Size: 374 B |
|
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 480 B |
|
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 719 B |
|
Before Width: | Height: | Size: 246 B After Width: | Height: | Size: 159 B |
|
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 283 B |
|
Before Width: | Height: | Size: 236 B After Width: | Height: | Size: 125 B |
|
Before Width: | Height: | Size: 978 B After Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 874 B After Width: | Height: | Size: 782 B |
|
Before Width: | Height: | Size: 856 B After Width: | Height: | Size: 771 B |
|
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 172 B |
|
Before Width: | Height: | Size: 936 B After Width: | Height: | Size: 140 B |
|
Before Width: | Height: | Size: 672 B After Width: | Height: | Size: 237 B |
|
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 205 B |
|
Before Width: | Height: | Size: 395 B After Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 357 B After Width: | Height: | Size: 172 B |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |