forked from Mirrorlandia_minetest/minetest
Compare commits
187 Commits
master
...
stable-0.4
Author | SHA1 | Date | |
---|---|---|---|
|
426b5d3149 | ||
|
dda844be16 | ||
|
899dcbf1ee | ||
|
957c59a678 | ||
|
3d15a6774d | ||
|
3c24f941e0 | ||
|
9d64805ec1 | ||
|
ce4497224f | ||
|
a873a3f4f8 | ||
|
86e29ae586 | ||
|
dd5f03731a | ||
|
5e7faf3f50 | ||
|
8427ae529a | ||
|
2e85254e91 | ||
|
971dea7efd | ||
|
85ce23b165 | ||
|
e66d5e500c | ||
|
ea86ecf015 | ||
|
4a48cd57e8 | ||
|
289c8dfde5 | ||
|
9dfe9be1f3 | ||
|
f5c9c760e3 | ||
|
6dc7177a5d | ||
|
24a2fd4dc4 | ||
|
2515207606 | ||
|
119aa5c919 | ||
|
fb4bfc60de | ||
|
9bbe99b4f8 | ||
|
0ef9c53a8c | ||
|
b5350e27ad | ||
|
ecbb9310de | ||
|
aac35a6e7c | ||
|
04fe8cc0a2 | ||
|
24abdf45b9 | ||
|
263400b3d8 | ||
|
695d02e6bd | ||
|
e2815d27f1 | ||
|
ebfdb21624 | ||
|
0088fa6db4 | ||
|
e660b05523 | ||
|
14d20f5827 | ||
|
0414322d23 | ||
|
a6cfe73cb0 | ||
|
1d06a8ef6c | ||
|
875972ffa6 | ||
|
396daf1be1 | ||
|
fe41725e50 | ||
|
5624cf750f | ||
|
1d7fbd035d | ||
|
a6b9acb7af | ||
|
c40f535df8 | ||
|
79fde0dd52 | ||
|
8aaf526730 | ||
|
c683e050d4 | ||
|
c2e39b9363 | ||
|
f8cc92c190 | ||
|
858c41b842 | ||
|
2a4fbbbff8 | ||
|
6d346a817b | ||
|
529f00a240 | ||
|
7725030067 | ||
|
bb28afcfc3 | ||
|
880a25c921 | ||
|
0268c9d7c9 | ||
|
f72490950a | ||
|
9d3fa874be | ||
|
842eccee19 | ||
|
127b1fa6f8 | ||
|
6b5e2618fb | ||
|
b2099d4277 | ||
|
df0a8574dc | ||
|
6698067256 | ||
|
bb219e1059 | ||
|
b3167d4e57 | ||
|
8a849e893a | ||
|
f9738c1909 | ||
|
6f80e302fd | ||
|
48ebbf0fc6 | ||
|
7d9dbbbf3c | ||
|
7cc1a36b3c | ||
|
3f1094475f | ||
|
f72ac42ca0 | ||
|
8fba3c93d5 | ||
|
a90c314c80 | ||
|
222fab3d20 | ||
|
1cf32b22be | ||
|
6f803b9c89 | ||
|
0fe3e7574d | ||
|
b816c63196 | ||
|
313ca53b36 | ||
|
a65a46b889 | ||
|
0cfe3a810a | ||
|
6808a3d144 | ||
|
4d9bf75d3a | ||
|
416c4535c7 | ||
|
73baeb82ef | ||
|
7b8288d605 | ||
|
2f969196b8 | ||
|
0041bcc73e | ||
|
cc48c95ca7 | ||
|
0129c9a9dd | ||
|
9dc1f2d638 | ||
|
d215198fe8 | ||
|
c56c3d8d6f | ||
|
0034abb560 | ||
|
200e9cc4a2 | ||
|
6b0fb94d60 | ||
|
017815161b | ||
|
ab72100a2c | ||
|
9927076b47 | ||
|
bd8d6f8f2f | ||
|
3a9d500396 | ||
|
01b9da870b | ||
|
e8286e8894 | ||
|
b8f473be21 | ||
|
b1fae4c7be | ||
|
c2a0333901 | ||
|
5b2461c713 | ||
|
e9087d1be7 | ||
|
bb4ef52954 | ||
|
888b99e1b6 | ||
|
2c450ed93f | ||
|
d9c7af109a | ||
|
12562be393 | ||
|
151c19a6be | ||
|
9d40d89d27 | ||
|
037b01eac7 | ||
|
c789c532bb | ||
|
b3ffe675c3 | ||
|
90a9e4e69f | ||
|
e5311a4d56 | ||
|
4be7d8b43a | ||
|
070ab6654a | ||
|
ebf9dda2e6 | ||
|
c352ff71e8 | ||
|
26d0753d87 | ||
|
46ff2e2cef | ||
|
a08a93bc9c | ||
|
6e0557e20c | ||
|
0c91c65a11 | ||
|
849fe19f8c | ||
|
cfa6216694 | ||
|
322e5aaf92 | ||
|
03bc584f57 | ||
|
5f796f7a04 | ||
|
7aa52fe4e1 | ||
|
0664b5f772 | ||
|
14b039f0b4 | ||
|
c399f5a541 | ||
|
f736226c1a | ||
|
e665e75e77 | ||
|
cba783f7fa | ||
|
87b9451820 | ||
|
41b7823057 | ||
|
7968f1ddaa | ||
|
caecdb681c | ||
|
81d56b9491 | ||
|
8077612dcb | ||
|
07fddf1f6c | ||
|
315b00d150 | ||
|
0c0248a19c | ||
|
0429ec4cfd | ||
|
a740a48f62 | ||
|
b12f569fc6 | ||
|
7993a403f2 | ||
|
b0df67d9c0 | ||
|
45ff8569d7 | ||
|
82bfa2ee7b | ||
|
9ef2e5000f | ||
|
678546308e | ||
|
6f688c50ee | ||
|
bb603ff18e | ||
|
4208fdfd22 | ||
|
4875213168 | ||
|
f92540e8ad | ||
|
ec0bf899ed | ||
|
2b635a892c | ||
|
7f6fc148bd | ||
|
878e9f7594 | ||
|
c7249f5983 | ||
|
7f07858209 | ||
|
9e9688fc61 | ||
|
93e5ab367a | ||
|
60fa5807b9 | ||
|
9dbca41385 | ||
|
61588a43dd | ||
|
e62927ed71 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -77,6 +77,7 @@ src/cmake_config_githash.h
|
||||
src/lua/build/
|
||||
locale/
|
||||
.directory
|
||||
.gradle/
|
||||
*.cbp
|
||||
*.layout
|
||||
*.o
|
||||
@ -84,6 +85,8 @@ locale/
|
||||
*.ninja
|
||||
.ninja*
|
||||
*.gch
|
||||
*.iml
|
||||
test_config.h
|
||||
cmake-build-debug/
|
||||
cmake-build-release/
|
||||
|
||||
|
@ -13,13 +13,14 @@ set(PROJECT_NAME_CAPITALIZED "Minetest")
|
||||
# Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 4)
|
||||
set(VERSION_PATCH 16)
|
||||
set(VERSION_PATCH 17)
|
||||
set(VERSION_TWEAK 1)
|
||||
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||
|
||||
# Change to false for releases
|
||||
set(DEVELOPMENT_BUILD FALSE)
|
||||
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_TWEAK}")
|
||||
if(VERSION_EXTRA)
|
||||
set(VERSION_STRING ${VERSION_STRING}-${VERSION_EXTRA})
|
||||
elseif(DEVELOPMENT_BUILD)
|
||||
|
@ -6,7 +6,8 @@ OS := $(shell uname)
|
||||
# GPROF = 1
|
||||
|
||||
# build for build platform
|
||||
APP_PLATFORM = android-9
|
||||
API = 14
|
||||
APP_PLATFORM = android-$(API)
|
||||
|
||||
ANDR_ROOT = $(shell pwd)
|
||||
PROJ_ROOT = $(shell realpath $(ANDR_ROOT)/../..)
|
||||
@ -30,7 +31,7 @@ TARGET_HOST = arm-linux
|
||||
TARGET_ABI = armeabi-v7a
|
||||
TARGET_LIBDIR = armeabi-v7a
|
||||
TARGET_TOOLCHAIN = arm-linux-androideabi-
|
||||
TARGET_CFLAGS_ADDON = -mfloat-abi=softfp -mfpu=vfpv3 -O3
|
||||
TARGET_CFLAGS_ADDON = -mfloat-abi=softfp -mfpu=vfpv3 -O3 -D__ANDROID_API__=$(API)
|
||||
TARGET_CXXFLAGS_ADDON = $(TARGET_CFLAGS_ADDON)
|
||||
TARGET_ARCH = armv7
|
||||
CROSS_PREFIX = arm-linux-androideabi-
|
||||
@ -82,7 +83,7 @@ OGG_LIB = $(OGG_DIR)libs/$(TARGET_ABI)/libogg.so
|
||||
VORBIS_LIB = $(OGG_DIR)libs/$(TARGET_ABI)/libogg.so
|
||||
OGG_TIMESTAMP = $(OGG_DIR)timestamp
|
||||
OGG_TIMESTAMP_INT = $(ANDR_ROOT)/deps/ogg_timestamp
|
||||
OGG_URL_GIT = https://github.com/vincentjames501/libvorbis-libogg-android
|
||||
OGG_URL_GIT = https://gitlab.com/minetest/libvorbis-libogg-android
|
||||
|
||||
IRRLICHT_REVISION = 5145
|
||||
IRRLICHT_DIR = $(ANDR_ROOT)/deps/irrlicht/
|
||||
@ -99,20 +100,13 @@ OPENSSL_TIMESTAMP = $(OPENSSL_DIR)timestamp
|
||||
OPENSSL_TIMESTAMP_INT = $(ANDR_ROOT)/deps/openssl_timestamp
|
||||
OPENSSL_URL = https://www.openssl.org/source/openssl-$(OPENSSL_VERSION).tar.gz
|
||||
|
||||
CURL_VERSION = 7.54.0
|
||||
CURL_VERSION = 7.60.0
|
||||
CURL_DIR = $(ANDR_ROOT)/deps/curl-$(CURL_VERSION)
|
||||
CURL_LIB = $(CURL_DIR)/lib/.libs/libcurl.a
|
||||
CURL_TIMESTAMP = $(CURL_DIR)/timestamp
|
||||
CURL_TIMESTAMP_INT = $(ANDR_ROOT)/deps/curl_timestamp
|
||||
CURL_URL_HTTP = https://curl.haxx.se/download/curl-${CURL_VERSION}.tar.bz2
|
||||
|
||||
GMP_VERSION = 6.1.2
|
||||
GMP_DIR = $(ANDR_ROOT)/deps/gmp-$(GMP_VERSION)
|
||||
GMP_LIB = $(GMP_DIR)/usr/lib/libgmp.so
|
||||
GMP_TIMESTAMP = $(GMP_DIR)/timestamp
|
||||
GMP_TIMESTAMP_INT = $(ANDR_ROOT)/deps/gmp_timestamp
|
||||
GMP_URL_HTTP = https://gmplib.org/download/gmp/gmp-$(GMP_VERSION).tar.bz2
|
||||
|
||||
FREETYPE_DIR = $(ANDR_ROOT)/deps/freetype2-android/
|
||||
FREETYPE_LIB = $(FREETYPE_DIR)/Android/obj/local/$(TARGET_ABI)/libfreetype2-static.a
|
||||
FREETYPE_TIMESTAMP = $(FREETYPE_DIR)timestamp
|
||||
@ -126,12 +120,11 @@ ICONV_TIMESTAMP = $(ICONV_DIR)timestamp
|
||||
ICONV_TIMESTAMP_INT = $(ANDR_ROOT)/deps/iconv_timestamp
|
||||
ICONV_URL_HTTP = https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$(ICONV_VERSION).tar.gz
|
||||
|
||||
SQLITE3_FOLDER = sqlite-amalgamation-3180000
|
||||
SQLITE3_URL = https://www.sqlite.org/2017/$(SQLITE3_FOLDER).zip
|
||||
SQLITE3_FOLDER = sqlite-amalgamation-3240000
|
||||
SQLITE3_URL = https://www.sqlite.org/2018/$(SQLITE3_FOLDER).zip
|
||||
|
||||
ANDROID_SDK = $(shell grep '^sdk\.dir' local.properties | sed 's/^.*=[[:space:]]*//')
|
||||
ANDROID_NDK = $(shell grep '^ndk\.dir' local.properties | sed 's/^.*=[[:space:]]*//')
|
||||
NDK_MODULE_PATH = $(ANDROID_NDK)/toolchains
|
||||
|
||||
#use interim target variable to switch leveldb on or off
|
||||
ifeq ($(HAVE_LEVELDB),1)
|
||||
@ -217,14 +210,10 @@ $(OPENAL_LIB): $(OPENAL_TIMESTAMP)
|
||||
if [ $$REFRESH -ne 0 ] ; then \
|
||||
echo "changed timestamp for openal detected building..."; \
|
||||
cd ${OPENAL_DIR}; \
|
||||
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||
export TARGET_ABI=${TARGET_ABI}; \
|
||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} APP_ABI=${TARGET_ABI} \
|
||||
TARGET_ARCH_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} \
|
||||
PRIVATE_CC=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}gcc \
|
||||
PRIVATE_CXX=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}g++ \
|
||||
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
|
||||
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
|
||||
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
|
||||
NDK_APPLICATION_MK=${ANDR_ROOT}/jni/Deps.mk || exit 1; \
|
||||
touch ${OPENAL_TIMESTAMP}; \
|
||||
touch ${OPENAL_TIMESTAMP_INT}; \
|
||||
else \
|
||||
@ -248,7 +237,6 @@ ogg_download :
|
||||
git clone ${OGG_URL_GIT}|| exit 1; \
|
||||
cd libvorbis-libogg-android ; \
|
||||
patch -p1 < ${ANDR_ROOT}/patches/libvorbis-libogg-fpu.patch || exit 1; \
|
||||
sed -i 's-:-?-' jni/Application.mk; \
|
||||
fi
|
||||
|
||||
ogg : $(OGG_LIB)
|
||||
@ -265,14 +253,12 @@ $(OGG_LIB): $(OGG_TIMESTAMP)
|
||||
if [ $$REFRESH -ne 0 ] ; then \
|
||||
echo "changed timestamp for ogg detected building..."; \
|
||||
cd ${OGG_DIR}; \
|
||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
||||
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} \
|
||||
PRIVATE_CC=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}gcc \
|
||||
PRIVATE_CXX=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}g++ \
|
||||
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
|
||||
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
|
||||
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
|
||||
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||
export TARGET_ABI=${TARGET_ABI}; \
|
||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||
--platform=${APP_PLATFORM} \
|
||||
--install-dir=$${TOOLCHAIN}; \
|
||||
touch ${OGG_TIMESTAMP}; \
|
||||
touch ${OGG_TIMESTAMP_INT}; \
|
||||
else \
|
||||
@ -301,7 +287,7 @@ openssl_download :
|
||||
|
||||
openssl : $(OPENSSL_LIB)
|
||||
|
||||
$(OPENSSL_LIB): $(OPENSSL_TIMESTAMP) $(GMP_LIB)
|
||||
$(OPENSSL_LIB): $(OPENSSL_TIMESTAMP)
|
||||
@REFRESH=0; \
|
||||
if [ ! -e ${OPENSSL_TIMESTAMP_INT} ] ; then \
|
||||
echo "${OPENSSL_TIMESTAMP_INT} doesn't exist"; \
|
||||
@ -317,10 +303,10 @@ $(OPENSSL_LIB): $(OPENSSL_TIMESTAMP) $(GMP_LIB)
|
||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-openssl; \
|
||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||
--platform=android-9 \
|
||||
--platform=${APP_PLATFORM} \
|
||||
--install-dir=$${TOOLCHAIN}; \
|
||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||
CC=${CROSS_PREFIX}gcc ./Configure enable-gmp -DL_ENDIAN -I${GMP_DIR} -L${GMP_DIR}/usr/lib android-${TARGET_ARCH};\
|
||||
CC=${CROSS_PREFIX}gcc ./Configure -DL_ENDIAN android-${TARGET_ARCH};\
|
||||
CC=${CROSS_PREFIX}gcc ANDROID_DEV=/tmp/ndk-${TARGET_HOST} make depend; \
|
||||
CC=${CROSS_PREFIX}gcc ANDROID_DEV=/tmp/ndk-${TARGET_HOST} make build_libs; \
|
||||
touch ${OPENSSL_TIMESTAMP}; \
|
||||
@ -368,7 +354,7 @@ $(LEVELDB_LIB): $(LEVELDB_TIMESTAMP)
|
||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-leveldb; \
|
||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||
--platform=android-9 \
|
||||
--platform=${APP_PLATFORM} \
|
||||
--install-dir=$${TOOLCHAIN}; \
|
||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||
export CC=${CROSS_PREFIX}gcc; \
|
||||
@ -420,14 +406,10 @@ $(FREETYPE_LIB) : $(FREETYPE_TIMESTAMP)
|
||||
mkdir -p ${FREETYPE_DIR}; \
|
||||
echo "changed timestamp for freetype detected building..."; \
|
||||
cd ${FREETYPE_DIR}/Android/jni; \
|
||||
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||
export TARGET_ABI=${TARGET_ABI}; \
|
||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
||||
APP_PLATFORM=${APP_PLATFORM} APP_ABI=${TARGET_ABI} \
|
||||
PRIVATE_CC=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}gcc \
|
||||
PRIVATE_CXX=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}g++ \
|
||||
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
|
||||
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
|
||||
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
|
||||
NDK_APPLICATION_MK=${ANDR_ROOT}/jni/Deps.mk || exit 1; \
|
||||
touch ${FREETYPE_TIMESTAMP}; \
|
||||
touch ${FREETYPE_TIMESTAMP_INT}; \
|
||||
else \
|
||||
@ -478,9 +460,10 @@ $(ICONV_LIB) : $(ICONV_TIMESTAMP)
|
||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-iconv; \
|
||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||
--platform=android-9 \
|
||||
--platform=${APP_PLATFORM} \
|
||||
--install-dir=$${TOOLCHAIN}; \
|
||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||
export CFLAGS="$${CFLAGS} ${TARGET_CFLAGS_ADDON}"; \
|
||||
export CC=${CROSS_PREFIX}gcc; \
|
||||
export CXX=${CROSS_PREFIX}g++; \
|
||||
export TARGET_OS=OS_ANDROID_CROSSCOMPILE; \
|
||||
@ -513,6 +496,7 @@ irrlicht_download :
|
||||
patch -p1 < ${ANDR_ROOT}/patches/irrlicht-touchcount.patch || exit 1; \
|
||||
patch -p1 < ${ANDR_ROOT}/patches/irrlicht-back_button.patch || exit 1; \
|
||||
patch -p1 < ${ANDR_ROOT}/patches/irrlicht-texturehack.patch || exit 1; \
|
||||
patch -p1 < ${ANDR_ROOT}/patches/irrlicht-native_activity.patch || exit 1; \
|
||||
fi
|
||||
|
||||
$(IRRLICHT_TIMESTAMP) : irrlicht_download
|
||||
@ -538,14 +522,10 @@ $(IRRLICHT_LIB): $(IRRLICHT_TIMESTAMP) $(FREETYPE_LIB)
|
||||
mkdir -p ${IRRLICHT_DIR}; \
|
||||
echo "changed timestamp for irrlicht detected building..."; \
|
||||
cd deps/irrlicht/source/Irrlicht/Android; \
|
||||
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||
export TARGET_ABI=${TARGET_ABI}; \
|
||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
||||
APP_ABI=${TARGET_ABI} APP_PLATFORM=${APP_PLATFORM} \
|
||||
PRIVATE_CC=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}gcc \
|
||||
PRIVATE_CXX=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}g++ \
|
||||
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
|
||||
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
|
||||
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
|
||||
NDK_APPLICATION_MK=${ANDR_ROOT}/jni/Irrlicht.mk || exit 1; \
|
||||
touch ${IRRLICHT_TIMESTAMP}; \
|
||||
touch ${IRRLICHT_TIMESTAMP_INT}; \
|
||||
else \
|
||||
@ -593,7 +573,7 @@ $(CURL_LIB): $(CURL_TIMESTAMP) $(OPENSSL_LIB)
|
||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-curl; \
|
||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||
--platform=android-9 \
|
||||
--platform=${APP_PLATFORM} \
|
||||
--install-dir=$${TOOLCHAIN}; \
|
||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||
export CC=${CROSS_PREFIX}gcc; \
|
||||
@ -615,64 +595,6 @@ clean_curl :
|
||||
$(RM) -rf deps/curl-${CURL_VERSION} \
|
||||
$(RM) -f deps/curl
|
||||
|
||||
$(GMP_TIMESTAMP) : gmp_download
|
||||
@LAST_MODIF=$$(find ${GMP_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
|
||||
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
|
||||
touch ${GMP_TIMESTAMP}; \
|
||||
fi
|
||||
|
||||
gmp_download :
|
||||
@if [ ! -d "${GMP_DIR}" ] ; then \
|
||||
echo "gmp sources missing, downloading..."; \
|
||||
mkdir -p ${ANDR_ROOT}/deps; \
|
||||
cd deps; \
|
||||
wget ${GMP_URL_HTTP} || exit 1; \
|
||||
tar -xjf gmp-${GMP_VERSION}.tar.bz2 || exit 1; \
|
||||
rm gmp-${GMP_VERSION}.tar.bz2; \
|
||||
ln -s gmp-${GMP_VERSION} gmp; \
|
||||
fi
|
||||
|
||||
gmp : $(GMP_LIB)
|
||||
|
||||
$(GMP_LIB): $(GMP_TIMESTAMP)
|
||||
@REFRESH=0; \
|
||||
if [ ! -e ${GMP_TIMESTAMP_INT} ] ; then \
|
||||
REFRESH=1; \
|
||||
fi; \
|
||||
if [ ! -e ${GMP_LIB} ] ; then \
|
||||
REFRESH=1; \
|
||||
fi; \
|
||||
if [ ${GMP_TIMESTAMP} -nt ${GMP_TIMESTAMP_INT} ] ; then \
|
||||
REFRESH=1; \
|
||||
fi; \
|
||||
if [ $$REFRESH -ne 0 ] ; then \
|
||||
mkdir -p ${GMP_DIR}; \
|
||||
echo "changed timestamp for gmp detected building..."; \
|
||||
cd deps/gmp-${GMP_VERSION}; \
|
||||
export CROSS_PREFIX=${CROSS_PREFIX}; \
|
||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-gmp; \
|
||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||
--platform=android-9 \
|
||||
--install-dir=$${TOOLCHAIN}; \
|
||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||
export CC=${CROSS_PREFIX}gcc; \
|
||||
export CXX=${CROSS_PREFIX}g++; \
|
||||
export LIBGMP_LDFLAGS="-avoid-version"; \
|
||||
export LIBGMPXX_LDFLAGS="-avoid-version"; \
|
||||
./configure --disable-static --host=${TARGET_HOST} --prefix=/usr; \
|
||||
$(MAKE) install DESTDIR=/${GMP_DIR} || exit 1; \
|
||||
touch ${GMP_TIMESTAMP}; \
|
||||
touch ${GMP_TIMESTAMP_INT}; \
|
||||
$(RM) -rf $${TOOLCHAIN}; \
|
||||
else \
|
||||
echo "nothing to be done for gmp"; \
|
||||
fi
|
||||
|
||||
clean_gmp:
|
||||
$(RM) -rf deps/gmp-${GMP_VERSION} \
|
||||
$(RM) -f deps/gmp
|
||||
|
||||
sqlite3_download: deps/${SQLITE3_FOLDER}/sqlite3.c
|
||||
|
||||
deps/${SQLITE3_FOLDER}/sqlite3.c :
|
||||
@ -762,20 +684,16 @@ assets : $(ASSETS_TIMESTAMP)
|
||||
fi
|
||||
|
||||
clean_assets :
|
||||
@$(RM) -r assets
|
||||
@$(RM) -r ${APP_ROOT}/assets
|
||||
|
||||
apk: local.properties assets $(ICONV_LIB) $(IRRLICHT_LIB) $(CURL_LIB) $(GMP_LIB) $(LEVELDB_TARGET) \
|
||||
apk: local.properties assets $(ICONV_LIB) $(IRRLICHT_LIB) $(CURL_LIB) $(LEVELDB_TARGET) \
|
||||
$(OPENAL_LIB) $(OGG_LIB) prep_srcdir $(ANDR_ROOT)/jni/src/android_version.h \
|
||||
$(ANDR_ROOT)/jni/src/android_version_githash.h sqlite3_download
|
||||
+ @${ANDROID_NDK}/ndk-build NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
||||
GPROF=${GPROF} APP_ABI=${TARGET_ABI} HAVE_LEVELDB=${HAVE_LEVELDB} \
|
||||
APP_PLATFORM=${APP_PLATFORM} \
|
||||
PRIVATE_CC=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}gcc \
|
||||
PRIVATE_CXX=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}g++ \
|
||||
TARGET_LIBDIR=${TARGET_LIBDIR} \
|
||||
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
|
||||
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
|
||||
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
|
||||
+ @export TARGET_LIBDIR=${TARGET_LIBDIR}; \
|
||||
export HAVE_LEVELDB=${HAVE_LEVELDB}; \
|
||||
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||
export TARGET_ABI=${TARGET_ABI}; \
|
||||
${ANDROID_NDK}/ndk-build || exit 1; \
|
||||
if [ ! -e ${APP_ROOT}/jniLibs ]; then \
|
||||
ln -s ${ANDR_ROOT}/libs ${APP_ROOT}/jniLibs || exit 1; \
|
||||
fi; \
|
||||
@ -807,7 +725,7 @@ clean_apk :
|
||||
clean_all :
|
||||
@$(MAKE) clean_apk; \
|
||||
$(MAKE) clean_assets clean_iconv clean_irrlicht clean_leveldb clean_curl \
|
||||
clean_openssl clean_openal clean_ogg clean_gmp; \
|
||||
clean_openssl clean_openal clean_ogg; \
|
||||
sleep 1; \
|
||||
$(RM) -r gen libs obj deps bin Debug and_env
|
||||
|
||||
|
@ -1,25 +1,46 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://maven.google.com' }
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:1.5.0"
|
||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven { url 'https://maven.google.com' }
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
def curl_version = "7.60.0"
|
||||
def gmp_version = "6.1.2"
|
||||
def irrlicht_revision = "5150"
|
||||
def openal_version = "1.18.2"
|
||||
def openssl_version = "1.0.2n"
|
||||
def sqlite3_version = "3260000"
|
||||
|
||||
apply plugin: "com.android.application"
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion "25.0.3"
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.3"
|
||||
|
||||
defaultConfig {
|
||||
versionCode 17
|
||||
versionCode 22
|
||||
versionName "${System.env.VERSION_STR}.${versionCode}"
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 9
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 28
|
||||
applicationId "net.minetest.minetest"
|
||||
manifestPlaceholders = [ package: "net.minetest.minetest", project: project.name ]
|
||||
manifestPlaceholders = [package: "net.minetest.minetest", project: project.name]
|
||||
ndk {
|
||||
// Specifies the ABI configurations of your native
|
||||
// libraries Gradle should build and package with your APK.
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64',
|
||||
'arm64-v8a'
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
@ -46,3 +67,68 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task cleanAssets(type: Delete) {
|
||||
delete 'src/main/assets'
|
||||
}
|
||||
|
||||
task cleanIconv(type: Delete) {
|
||||
delete 'deps/libiconv'
|
||||
}
|
||||
|
||||
task cleanIrrlicht(type: Delete) {
|
||||
delete 'deps/irrlicht'
|
||||
}
|
||||
|
||||
task cleanLevelDB(type: Delete) {
|
||||
delete 'deps/leveldb'
|
||||
}
|
||||
|
||||
task cleanCURL(type: Delete) {
|
||||
delete 'deps/curl'
|
||||
delete 'deps/curl-' + curl_version
|
||||
}
|
||||
|
||||
task cleanOpenSSL(type: Delete) {
|
||||
delete 'deps/openssl'
|
||||
delete 'deps/openssl-' + openssl_version
|
||||
delete 'deps/openssl-' + openssl_version + '.tar.gz'
|
||||
}
|
||||
|
||||
task cleanOpenAL(type: Delete) {
|
||||
delete 'deps/openal-soft'
|
||||
}
|
||||
|
||||
task cleanFreetype(type: Delete) {
|
||||
delete 'deps/freetype2-android'
|
||||
}
|
||||
|
||||
task cleanOgg(type: Delete) {
|
||||
delete 'deps/libvorbis-libogg-android'
|
||||
}
|
||||
|
||||
task cleanSQLite3(type: Delete) {
|
||||
delete 'deps/sqlite-amalgamation-' + sqlite3_version
|
||||
delete 'deps/sqlite-amalgamation-' + sqlite3_version + '.zip'
|
||||
}
|
||||
|
||||
task cleanGMP(type: Delete) {
|
||||
delete 'deps/gmp'
|
||||
delete 'deps/gmp-' + gmp_version
|
||||
}
|
||||
|
||||
task cleanAll(type: Delete, dependsOn: [clean, cleanAssets, cleanIconv,
|
||||
cleanFreetype, cleanIrrlicht, cleanLevelDB, cleanSQLite3, cleanCURL,
|
||||
cleanOpenSSL, cleanOpenAL, cleanOgg, cleanGMP]) {
|
||||
delete 'deps'
|
||||
delete 'gen'
|
||||
delete 'libs'
|
||||
delete 'obj'
|
||||
delete 'bin'
|
||||
delete 'Debug'
|
||||
delete 'and_env'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.android.support:support-v4:28.0.0'
|
||||
}
|
||||
|
BIN
build/android/gradle/wrapper/gradle-wrapper.jar
vendored
BIN
build/android/gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
#Sat Aug 27 20:10:09 CEST 2016
|
||||
#Mon Oct 15 00:47:03 CEST 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
|
||||
|
110
build/android/gradlew
vendored
110
build/android/gradlew
vendored
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@ -6,47 +6,6 @@
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
@ -90,7 +89,7 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
@ -114,6 +113,7 @@ fi
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
@ -154,11 +154,19 @@ if $cygwin ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
14
build/android/gradlew.bat
vendored
14
build/android/gradlew.bat
vendored
@ -8,14 +8,14 @@
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@ -46,10 +46,9 @@ echo location of your Java installation.
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
@ -60,11 +59,6 @@ set _SKIP=2
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
@ -44,11 +44,6 @@ LOCAL_MODULE := vorbis
|
||||
LOCAL_SRC_FILES := deps/libvorbis-libogg-android/libs/$(TARGET_LIBDIR)/libvorbis.so
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := gmp
|
||||
LOCAL_SRC_FILES := deps/gmp/usr/lib/libgmp.so
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ssl
|
||||
LOCAL_SRC_FILES := deps/openssl/libssl.a
|
||||
@ -98,6 +93,7 @@ endif
|
||||
LOCAL_C_INCLUDES := \
|
||||
jni/src \
|
||||
jni/src/script \
|
||||
jni/lib/gmp \
|
||||
jni/lib/lua/src \
|
||||
jni/lib/jsoncpp \
|
||||
jni/src/cguittfont \
|
||||
@ -107,7 +103,6 @@ LOCAL_C_INCLUDES := \
|
||||
deps/curl/include \
|
||||
deps/openal-soft/jni/OpenAL/include \
|
||||
deps/libvorbis-libogg-android/jni/include \
|
||||
deps/gmp/usr/include \
|
||||
deps/leveldb/include \
|
||||
deps/sqlite/
|
||||
|
||||
@ -339,6 +334,9 @@ LOCAL_SRC_FILES += \
|
||||
#freetype2 support
|
||||
LOCAL_SRC_FILES += jni/src/cguittfont/xCGUITTFont.cpp
|
||||
|
||||
# GMP
|
||||
LOCAL_SRC_FILES += jni/lib/gmp/mini-gmp.c
|
||||
|
||||
# Lua
|
||||
LOCAL_SRC_FILES += \
|
||||
jni/lib/lua/src/lapi.c \
|
||||
@ -385,7 +383,7 @@ LOCAL_SRC_FILES += \
|
||||
# JSONCPP
|
||||
LOCAL_SRC_FILES += jni/lib/jsoncpp/jsoncpp.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := iconv openal ogg vorbis gmp
|
||||
LOCAL_SHARED_LIBRARIES := iconv openal ogg vorbis
|
||||
LOCAL_STATIC_LIBRARIES := Irrlicht freetype curl ssl crypto android_native_app_glue $(PROFILER_LIBS)
|
||||
|
||||
ifeq ($(HAVE_LEVELDB), 1)
|
||||
|
@ -1,9 +1,6 @@
|
||||
# NDK_TOOLCHAIN_VERSION := clang3.8
|
||||
|
||||
APP_PLATFORM := android-9
|
||||
APP_PLATFORM := ${APP_PLATFORM}
|
||||
APP_ABI := ${TARGET_ABI}
|
||||
APP_STL := c++_shared
|
||||
APP_MODULES := minetest
|
||||
APP_STL := gnustl_static
|
||||
|
||||
APP_CPPFLAGS += -fexceptions
|
||||
APP_GNUSTL_FORCE_CPP_FEATURES := rtti
|
||||
|
||||
APP_CPPFLAGS += -fexceptions -frtti
|
||||
|
7
build/android/jni/Deps.mk
Normal file
7
build/android/jni/Deps.mk
Normal file
@ -0,0 +1,7 @@
|
||||
APP_PLATFORM := ${APP_PLATFORM}
|
||||
APP_ABI := ${TARGET_ABI}
|
||||
APP_STL := c++_shared
|
||||
APP_DEPRECATED_HEADERS := true
|
||||
|
||||
APP_CFLAGS += -mfloat-abi=softfp -mfpu=vfpv3 -O3
|
||||
APP_CPPFLAGS += -fexceptions
|
8
build/android/jni/Irrlicht.mk
Normal file
8
build/android/jni/Irrlicht.mk
Normal file
@ -0,0 +1,8 @@
|
||||
APP_PLATFORM := ${APP_PLATFORM}
|
||||
APP_ABI := ${TARGET_ABI}
|
||||
APP_STL := c++_static
|
||||
APP_DEPRECATED_HEADERS := true
|
||||
APP_MODULES := Irrlicht
|
||||
|
||||
APP_CFLAGS += -mfloat-abi=softfp -mfpu=vfpv3 -O3
|
||||
APP_CPPFLAGS += -fexceptions
|
13
build/android/patches/irrlicht-native_activity.patch
Normal file
13
build/android/patches/irrlicht-native_activity.patch
Normal file
@ -0,0 +1,13 @@
|
||||
--- irrlicht/source/Irrlicht/CEGLManager.cpp.orig 2018-06-10 16:58:11.357709173 +0200
|
||||
+++ irrlicht/source/Irrlicht/CEGLManager.cpp 2018-06-10 16:58:25.100709843 +0200
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "irrString.h"
|
||||
#include "os.h"
|
||||
|
||||
+#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
|
||||
+#include <android/native_activity.h>
|
||||
+#endif
|
||||
+
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
@ -1,2 +1 @@
|
||||
rootProject.name = "Minetest"
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.SET_DEBUG_APP" />
|
||||
|
||||
<uses-permission android:name="android.permission.SET_DEBUG_APP" />
|
||||
</manifest>
|
||||
|
@ -1,34 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="net.minetest.minetest"
|
||||
android:installLocation="auto">
|
||||
<uses-feature android:glEsVersion="0x00010000" android:required="true"/>
|
||||
package="net.minetest.minetest"
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00010000"
|
||||
android:required="true" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<application android:icon="@drawable/irr_icon"
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="${project}"
|
||||
android:resizeableActivity="false">
|
||||
|
||||
<meta-data
|
||||
android:name="android.max_aspect"
|
||||
android:value="2.1" />
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
|
||||
android:label="${project}"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:allowBackup="true">
|
||||
<activity android:name=".MtNativeActivity"
|
||||
android:label="${project}"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="orientation|keyboard|keyboardHidden|navigation"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:clearTaskOnLaunch="true">
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:theme="@style/AppTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.app.lib_name" android:value="minetest" />
|
||||
</activity>
|
||||
<activity android:name=".MinetestTextEntry"
|
||||
android:theme="@style/Theme.Transparent"
|
||||
android:excludeFromRecents="true">
|
||||
</activity>
|
||||
<activity android:name=".MinetestAssetCopy"
|
||||
android:theme="@style/Theme.Transparent"
|
||||
android:excludeFromRecents="true">
|
||||
<activity
|
||||
android:name=".MtNativeActivity"
|
||||
android:configChanges="orientation|keyboard|keyboardHidden|navigation|screenSize|smallestScreenSize"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:theme="@style/AppTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
android:value="minetest" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".MinetestTextEntry"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:theme="@style/Theme.Dialog"
|
||||
android:windowSoftInputMode="stateAlwaysHidden"/>
|
||||
<activity
|
||||
android:name=".MinetestAssetCopy"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:theme="@style/AppTheme"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -0,0 +1,79 @@
|
||||
package net.minetest.minetest;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
private final static int PERMISSIONS = 1;
|
||||
private static final String[] REQUIRED_SDK_PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
checkPermission();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkPermission() {
|
||||
final List<String> missingPermissions = new ArrayList<String>();
|
||||
// check required permission
|
||||
for (final String permission : REQUIRED_SDK_PERMISSIONS) {
|
||||
final int result = ContextCompat.checkSelfPermission(this, permission);
|
||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
||||
missingPermissions.add(permission);
|
||||
}
|
||||
}
|
||||
if (!missingPermissions.isEmpty()) {
|
||||
// request permission
|
||||
final String[] permissions = missingPermissions
|
||||
.toArray(new String[missingPermissions.size()]);
|
||||
ActivityCompat.requestPermissions(this, permissions, PERMISSIONS);
|
||||
} else {
|
||||
final int[] grantResults = new int[REQUIRED_SDK_PERMISSIONS.length];
|
||||
Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
|
||||
onRequestPermissionsResult(PERMISSIONS, REQUIRED_SDK_PERMISSIONS,
|
||||
grantResults);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
|
||||
@NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PERMISSIONS:
|
||||
for (int index = 0; index < permissions.length; index++) {
|
||||
if (grantResults[index] != PackageManager.PERMISSION_GRANTED) {
|
||||
// permission not granted - toast and exit
|
||||
Toast.makeText(this, R.string.not_granted, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// permission were granted - run
|
||||
next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void next() {
|
||||
Intent intent = new Intent(this, MtNativeActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
@ -1,5 +1,17 @@
|
||||
package net.minetest.minetest;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@ -7,410 +19,355 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.lang.Object;
|
||||
import java.util.Vector;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
public class MinetestAssetCopy extends Activity {
|
||||
ProgressBar m_ProgressBar;
|
||||
TextView m_Filename;
|
||||
copyAssetTask m_AssetCopy;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Paint;
|
||||
import android.text.TextPaint;
|
||||
|
||||
public class MinetestAssetCopy extends Activity
|
||||
{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.assetcopy);
|
||||
|
||||
m_ProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
|
||||
m_Filename = (TextView) findViewById(R.id.textView1);
|
||||
|
||||
m_ProgressBar = findViewById(R.id.progressBar1);
|
||||
m_Filename = findViewById(R.id.textView1);
|
||||
Display display = getWindowManager().getDefaultDisplay();
|
||||
m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8);
|
||||
m_ProgressBar.invalidate();
|
||||
|
||||
|
||||
/* check if there's already a copy in progress and reuse in case it is*/
|
||||
MinetestAssetCopy prevActivity =
|
||||
MinetestAssetCopy prevActivity =
|
||||
(MinetestAssetCopy) getLastNonConfigurationInstance();
|
||||
if(prevActivity!= null) {
|
||||
if (prevActivity != null) {
|
||||
m_AssetCopy = prevActivity.m_AssetCopy;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_AssetCopy = new copyAssetTask();
|
||||
m_AssetCopy.execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
makeFullScreen();
|
||||
}
|
||||
|
||||
public void makeFullScreen() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
this.getWindow().getDecorView().setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
makeFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
/* preserve asset copy background task to prevent restart of copying */
|
||||
/* this way of doing it is not recommended for latest android version */
|
||||
/* but the recommended way isn't available on android 2.x */
|
||||
public Object onRetainNonConfigurationInstance()
|
||||
{
|
||||
public Object onRetainNonConfigurationInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
ProgressBar m_ProgressBar;
|
||||
TextView m_Filename;
|
||||
|
||||
copyAssetTask m_AssetCopy;
|
||||
|
||||
private class copyAssetTask extends AsyncTask<String, Integer, String>
|
||||
{
|
||||
private long getFullSize(String filename)
|
||||
{
|
||||
long size = 0;
|
||||
try {
|
||||
InputStream src = getAssets().open(filename);
|
||||
byte[] buf = new byte[4096];
|
||||
|
||||
int len = 0;
|
||||
while ((len = src.read(buf)) > 0)
|
||||
{
|
||||
size += len;
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... files)
|
||||
{
|
||||
m_foldernames = new Vector<String>();
|
||||
m_filenames = new Vector<String>();
|
||||
m_tocopy = new Vector<String>();
|
||||
m_asset_size_unknown = new Vector<String>();
|
||||
String baseDir =
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||
+ "/";
|
||||
|
||||
|
||||
// prepare temp folder
|
||||
File TempFolder = new File(baseDir + "Minetest/tmp/");
|
||||
|
||||
if (!TempFolder.exists())
|
||||
{
|
||||
TempFolder.mkdir();
|
||||
}
|
||||
else {
|
||||
File[] todel = TempFolder.listFiles();
|
||||
|
||||
for(int i=0; i < todel.length; i++)
|
||||
{
|
||||
Log.v("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath());
|
||||
todel[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
// add a .nomedia file
|
||||
try {
|
||||
OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia");
|
||||
dst.close();
|
||||
} catch (IOException e) {
|
||||
Log.e("MinetestAssetCopy","Failed to create .nomedia file");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
// build lists from prepared data
|
||||
BuildFolderList();
|
||||
BuildFileList();
|
||||
|
||||
// scan filelist
|
||||
ProcessFileList();
|
||||
|
||||
// doing work
|
||||
m_copy_started = true;
|
||||
m_ProgressBar.setMax(m_tocopy.size());
|
||||
|
||||
for (int i = 0; i < m_tocopy.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
String filename = m_tocopy.get(i);
|
||||
publishProgress(i);
|
||||
|
||||
boolean asset_size_unknown = false;
|
||||
long filesize = -1;
|
||||
|
||||
if (m_asset_size_unknown.contains(filename))
|
||||
{
|
||||
File testme = new File(baseDir + "/" + filename);
|
||||
|
||||
if(testme.exists())
|
||||
{
|
||||
filesize = testme.length();
|
||||
}
|
||||
asset_size_unknown = true;
|
||||
}
|
||||
|
||||
InputStream src;
|
||||
try
|
||||
{
|
||||
src = getAssets().open(filename);
|
||||
} catch (IOException e) {
|
||||
Log.e("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)");
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Transfer bytes from in to out
|
||||
byte[] buf = new byte[1*1024];
|
||||
int len = src.read(buf, 0, 1024);
|
||||
|
||||
/* following handling is crazy but we need to deal with */
|
||||
/* compressed assets.Flash chips limited livetime due to */
|
||||
/* write operations, we can't allow large files to destroy */
|
||||
/* users flash. */
|
||||
if (asset_size_unknown)
|
||||
{
|
||||
if ( (len > 0) && (len < buf.length) && (len == filesize))
|
||||
{
|
||||
src.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == buf.length)
|
||||
{
|
||||
src.close();
|
||||
long size = getFullSize(filename);
|
||||
if ( size == filesize)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
src = getAssets().open(filename);
|
||||
len = src.read(buf, 0, 1024);
|
||||
}
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
int total_filesize = 0;
|
||||
OutputStream dst;
|
||||
try
|
||||
{
|
||||
dst = new FileOutputStream(baseDir + "/" + filename);
|
||||
} catch (IOException e) {
|
||||
Log.e("MinetestAssetCopy","Copying file: " + baseDir +
|
||||
"/" + filename + " FAILED (couldn't open output file)");
|
||||
e.printStackTrace();
|
||||
src.close();
|
||||
continue;
|
||||
}
|
||||
dst.write(buf, 0, len);
|
||||
total_filesize += len;
|
||||
|
||||
while ((len = src.read(buf)) > 0)
|
||||
{
|
||||
dst.write(buf, 0, len);
|
||||
total_filesize += len;
|
||||
}
|
||||
|
||||
dst.close();
|
||||
Log.v("MinetestAssetCopy","Copied file: " +
|
||||
m_tocopy.get(i) + " (" + total_filesize +
|
||||
" bytes)");
|
||||
}
|
||||
else if (len < 0)
|
||||
{
|
||||
Log.e("MinetestAssetCopy","Copying file: " +
|
||||
m_tocopy.get(i) + " failed, size < 0");
|
||||
}
|
||||
src.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.e("MinetestAssetCopy","Copying file: " +
|
||||
m_tocopy.get(i) + " failed");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update progress bar
|
||||
*/
|
||||
protected void onProgressUpdate(Integer... progress)
|
||||
{
|
||||
|
||||
if (m_copy_started)
|
||||
{
|
||||
boolean shortened = false;
|
||||
String todisplay = m_tocopy.get(progress[0]);
|
||||
m_ProgressBar.setProgress(progress[0]);
|
||||
m_Filename.setText(todisplay);
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean shortened = false;
|
||||
String todisplay = m_Foldername;
|
||||
String full_text = "scanning " + todisplay + " ...";
|
||||
m_Filename.setText(full_text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check al files and folders in filelist
|
||||
*/
|
||||
protected void ProcessFileList()
|
||||
{
|
||||
String FlashBaseDir =
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
|
||||
Iterator itr = m_filenames.iterator();
|
||||
|
||||
while (itr.hasNext())
|
||||
{
|
||||
String current_path = (String) itr.next();
|
||||
String FlashPath = FlashBaseDir + "/" + current_path;
|
||||
|
||||
if (isAssetFolder(current_path))
|
||||
{
|
||||
/* store information and update gui */
|
||||
m_Foldername = current_path;
|
||||
publishProgress(0);
|
||||
|
||||
/* open file in order to check if it's a folder */
|
||||
File current_folder = new File(FlashPath);
|
||||
if (!current_folder.exists())
|
||||
{
|
||||
if (!current_folder.mkdirs())
|
||||
{
|
||||
Log.e("MinetestAssetCopy","\t failed create folder: " +
|
||||
FlashPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.v("MinetestAssetCopy","\t created folder: " +
|
||||
FlashPath);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if it's not a folder it's most likely a file */
|
||||
boolean refresh = true;
|
||||
|
||||
File testme = new File(FlashPath);
|
||||
|
||||
long asset_filesize = -1;
|
||||
long stored_filesize = -1;
|
||||
|
||||
if (testme.exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
AssetFileDescriptor fd = getAssets().openFd(current_path);
|
||||
asset_filesize = fd.getLength();
|
||||
fd.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
refresh = true;
|
||||
m_asset_size_unknown.add(current_path);
|
||||
Log.e("MinetestAssetCopy","Failed to open asset file \"" +
|
||||
FlashPath + "\" for size check");
|
||||
}
|
||||
|
||||
stored_filesize = testme.length();
|
||||
|
||||
if (asset_filesize == stored_filesize)
|
||||
{
|
||||
refresh = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
m_tocopy.add(current_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read list of folders prepared on package build
|
||||
*/
|
||||
protected void BuildFolderList()
|
||||
{
|
||||
try
|
||||
{
|
||||
InputStream is = getAssets().open("index.txt");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
String line = reader.readLine();
|
||||
while (line != null)
|
||||
{
|
||||
m_foldernames.add(line);
|
||||
line = reader.readLine();
|
||||
}
|
||||
is.close();
|
||||
} catch (IOException e1)
|
||||
{
|
||||
Log.e("MinetestAssetCopy","Error on processing index.txt");
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read list of asset files prepared on package build
|
||||
*/
|
||||
protected void BuildFileList()
|
||||
{
|
||||
long entrycount = 0;
|
||||
try
|
||||
{
|
||||
InputStream is = getAssets().open("filelist.txt");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
String line = reader.readLine();
|
||||
while (line != null)
|
||||
{
|
||||
m_filenames.add(line);
|
||||
line = reader.readLine();
|
||||
entrycount ++;
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
catch (IOException e1)
|
||||
{
|
||||
Log.e("MinetestAssetCopy","Error on processing filelist.txt");
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute (String result)
|
||||
{
|
||||
finish();
|
||||
}
|
||||
|
||||
protected boolean isAssetFolder(String path)
|
||||
{
|
||||
return m_foldernames.contains(path);
|
||||
}
|
||||
|
||||
private class copyAssetTask extends AsyncTask<String, Integer, String> {
|
||||
boolean m_copy_started = false;
|
||||
String m_Foldername = "media";
|
||||
Vector<String> m_foldernames;
|
||||
Vector<String> m_filenames;
|
||||
Vector<String> m_tocopy;
|
||||
Vector<String> m_asset_size_unknown;
|
||||
|
||||
private long getFullSize(String filename) {
|
||||
long size = 0;
|
||||
try {
|
||||
InputStream src = getAssets().open(filename);
|
||||
byte[] buf = new byte[4096];
|
||||
|
||||
int len = 0;
|
||||
while ((len = src.read(buf)) > 0) {
|
||||
size += len;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... files) {
|
||||
m_foldernames = new Vector<String>();
|
||||
m_filenames = new Vector<String>();
|
||||
m_tocopy = new Vector<String>();
|
||||
m_asset_size_unknown = new Vector<String>();
|
||||
String baseDir =
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||
+ "/";
|
||||
|
||||
|
||||
// prepare temp folder
|
||||
File TempFolder = new File(baseDir + "Minetest/tmp/");
|
||||
|
||||
if (!TempFolder.exists()) {
|
||||
TempFolder.mkdir();
|
||||
} else {
|
||||
File[] todel = TempFolder.listFiles();
|
||||
|
||||
for (int i = 0; i < todel.length; i++) {
|
||||
Log.v("MinetestAssetCopy", "deleting: " + todel[i].getAbsolutePath());
|
||||
todel[i].delete();
|
||||
}
|
||||
}
|
||||
|
||||
// add a .nomedia file
|
||||
try {
|
||||
OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia");
|
||||
dst.close();
|
||||
} catch (IOException e) {
|
||||
Log.e("MinetestAssetCopy", "Failed to create .nomedia file");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
// build lists from prepared data
|
||||
BuildFolderList();
|
||||
BuildFileList();
|
||||
|
||||
// scan filelist
|
||||
ProcessFileList();
|
||||
|
||||
// doing work
|
||||
m_copy_started = true;
|
||||
m_ProgressBar.setMax(m_tocopy.size());
|
||||
|
||||
for (int i = 0; i < m_tocopy.size(); i++) {
|
||||
try {
|
||||
String filename = m_tocopy.get(i);
|
||||
publishProgress(i);
|
||||
|
||||
boolean asset_size_unknown = false;
|
||||
long filesize = -1;
|
||||
|
||||
if (m_asset_size_unknown.contains(filename)) {
|
||||
File testme = new File(baseDir + "/" + filename);
|
||||
|
||||
if (testme.exists()) {
|
||||
filesize = testme.length();
|
||||
}
|
||||
asset_size_unknown = true;
|
||||
}
|
||||
|
||||
InputStream src;
|
||||
try {
|
||||
src = getAssets().open(filename);
|
||||
} catch (IOException e) {
|
||||
Log.e("MinetestAssetCopy", "Copying file: " + filename + " FAILED (not in assets)");
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Transfer bytes from in to out
|
||||
byte[] buf = new byte[1024];
|
||||
int len = src.read(buf, 0, 1024);
|
||||
|
||||
/* following handling is crazy but we need to deal with */
|
||||
/* compressed assets.Flash chips limited livetime due to */
|
||||
/* write operations, we can't allow large files to destroy */
|
||||
/* users flash. */
|
||||
if (asset_size_unknown) {
|
||||
if ((len > 0) && (len < buf.length) && (len == filesize)) {
|
||||
src.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == buf.length) {
|
||||
src.close();
|
||||
long size = getFullSize(filename);
|
||||
if (size == filesize) {
|
||||
continue;
|
||||
}
|
||||
src = getAssets().open(filename);
|
||||
len = src.read(buf, 0, 1024);
|
||||
}
|
||||
}
|
||||
if (len > 0) {
|
||||
int total_filesize = 0;
|
||||
OutputStream dst;
|
||||
try {
|
||||
dst = new FileOutputStream(baseDir + "/" + filename);
|
||||
} catch (IOException e) {
|
||||
Log.e("MinetestAssetCopy", "Copying file: " + baseDir +
|
||||
"/" + filename + " FAILED (couldn't open output file)");
|
||||
e.printStackTrace();
|
||||
src.close();
|
||||
continue;
|
||||
}
|
||||
dst.write(buf, 0, len);
|
||||
total_filesize += len;
|
||||
|
||||
while ((len = src.read(buf)) > 0) {
|
||||
dst.write(buf, 0, len);
|
||||
total_filesize += len;
|
||||
}
|
||||
|
||||
dst.close();
|
||||
Log.v("MinetestAssetCopy", "Copied file: " +
|
||||
m_tocopy.get(i) + " (" + total_filesize +
|
||||
" bytes)");
|
||||
} else if (len < 0) {
|
||||
Log.e("MinetestAssetCopy", "Copying file: " +
|
||||
m_tocopy.get(i) + " failed, size < 0");
|
||||
}
|
||||
src.close();
|
||||
} catch (IOException e) {
|
||||
Log.e("MinetestAssetCopy", "Copying file: " +
|
||||
m_tocopy.get(i) + " failed");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* update progress bar
|
||||
*/
|
||||
protected void onProgressUpdate(Integer... progress) {
|
||||
|
||||
if (m_copy_started) {
|
||||
boolean shortened = false;
|
||||
String todisplay = m_tocopy.get(progress[0]);
|
||||
m_ProgressBar.setProgress(progress[0]);
|
||||
m_Filename.setText(todisplay);
|
||||
} else {
|
||||
boolean shortened = false;
|
||||
String todisplay = m_Foldername;
|
||||
String full_text = "scanning " + todisplay + " ...";
|
||||
m_Filename.setText(full_text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check all files and folders in filelist
|
||||
*/
|
||||
protected void ProcessFileList() {
|
||||
String FlashBaseDir =
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
|
||||
Iterator itr = m_filenames.iterator();
|
||||
|
||||
while (itr.hasNext()) {
|
||||
String current_path = (String) itr.next();
|
||||
String FlashPath = FlashBaseDir + "/" + current_path;
|
||||
|
||||
if (isAssetFolder(current_path)) {
|
||||
/* store information and update gui */
|
||||
m_Foldername = current_path;
|
||||
publishProgress(0);
|
||||
|
||||
/* open file in order to check if it's a folder */
|
||||
File current_folder = new File(FlashPath);
|
||||
if (!current_folder.exists()) {
|
||||
if (!current_folder.mkdirs()) {
|
||||
Log.e("MinetestAssetCopy", "\t failed create folder: " +
|
||||
FlashPath);
|
||||
} else {
|
||||
Log.v("MinetestAssetCopy", "\t created folder: " +
|
||||
FlashPath);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if it's not a folder it's most likely a file */
|
||||
boolean refresh = true;
|
||||
|
||||
File testme = new File(FlashPath);
|
||||
|
||||
long asset_filesize = -1;
|
||||
long stored_filesize = -1;
|
||||
|
||||
if (testme.exists()) {
|
||||
try {
|
||||
AssetFileDescriptor fd = getAssets().openFd(current_path);
|
||||
asset_filesize = fd.getLength();
|
||||
fd.close();
|
||||
} catch (IOException e) {
|
||||
refresh = true;
|
||||
m_asset_size_unknown.add(current_path);
|
||||
Log.e("MinetestAssetCopy", "Failed to open asset file \"" +
|
||||
FlashPath + "\" for size check");
|
||||
}
|
||||
|
||||
stored_filesize = testme.length();
|
||||
|
||||
if (asset_filesize == stored_filesize) {
|
||||
refresh = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
m_tocopy.add(current_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read list of folders prepared on package build
|
||||
*/
|
||||
protected void BuildFolderList() {
|
||||
try {
|
||||
InputStream is = getAssets().open("index.txt");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
m_foldernames.add(line);
|
||||
line = reader.readLine();
|
||||
}
|
||||
is.close();
|
||||
} catch (IOException e1) {
|
||||
Log.e("MinetestAssetCopy", "Error on processing index.txt");
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read list of asset files prepared on package build
|
||||
*/
|
||||
protected void BuildFileList() {
|
||||
long entrycount = 0;
|
||||
try {
|
||||
InputStream is = getAssets().open("filelist.txt");
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
m_filenames.add(line);
|
||||
line = reader.readLine();
|
||||
entrycount++;
|
||||
}
|
||||
is.close();
|
||||
} catch (IOException e1) {
|
||||
Log.e("MinetestAssetCopy", "Error on processing filelist.txt");
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPostExecute(String result) {
|
||||
finish();
|
||||
}
|
||||
|
||||
protected boolean isAssetFolder(String path) {
|
||||
return m_foldernames.contains(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,63 +6,59 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnKeyListener;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class MinetestTextEntry extends Activity {
|
||||
private final int MultiLineTextInput = 1;
|
||||
private final int SingleLineTextInput = 2;
|
||||
private final int SingleLinePasswordInput = 3;
|
||||
public AlertDialog mTextInputDialog;
|
||||
public EditText mTextInputWidget;
|
||||
|
||||
private final int MultiLineTextInput = 1;
|
||||
private final int SingleLineTextInput = 2;
|
||||
private final int SingleLinePasswordInput = 3;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Bundle b = getIntent().getExtras();
|
||||
String acceptButton = b.getString("EnterButton");
|
||||
String hint = b.getString("hint");
|
||||
String current = b.getString("current");
|
||||
int editType = b.getInt("editType");
|
||||
|
||||
String hint = b.getString("hint");
|
||||
String current = b.getString("current");
|
||||
int editType = b.getInt("editType");
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
mTextInputWidget = new EditText(this);
|
||||
mTextInputWidget.setHint(hint);
|
||||
mTextInputWidget.setText(current);
|
||||
mTextInputWidget.setMinWidth(300);
|
||||
if (editType == SingleLinePasswordInput) {
|
||||
mTextInputWidget.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||
mTextInputWidget.setInputType(InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mTextInputWidget.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
builder.setView(mTextInputWidget);
|
||||
|
||||
|
||||
if (editType == MultiLineTextInput) {
|
||||
builder.setPositiveButton(acceptButton, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int whichButton)
|
||||
{ pushResult(mTextInputWidget.getText().toString()); }
|
||||
});
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
pushResult(mTextInputWidget.getText().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
cancelDialog();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
mTextInputWidget.setOnKeyListener(new OnKeyListener() {
|
||||
@Override
|
||||
public boolean onKey(View view, int KeyCode, KeyEvent event) {
|
||||
if ( KeyCode == KeyEvent.KEYCODE_ENTER){
|
||||
if (KeyCode == KeyEvent.KEYCODE_ENTER) {
|
||||
|
||||
pushResult(mTextInputWidget.getText().toString());
|
||||
return true;
|
||||
@ -70,19 +66,19 @@ public class MinetestTextEntry extends Activity {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
mTextInputDialog = builder.create();
|
||||
mTextInputDialog.show();
|
||||
}
|
||||
|
||||
|
||||
public void pushResult(String text) {
|
||||
Intent resultData = new Intent();
|
||||
resultData.putExtra("text", text);
|
||||
setResult(Activity.RESULT_OK,resultData);
|
||||
setResult(Activity.RESULT_OK, resultData);
|
||||
mTextInputDialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
public void cancelDialog() {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
mTextInputDialog.dismiss();
|
||||
|
@ -2,22 +2,54 @@ package net.minetest.minetest;
|
||||
|
||||
import android.app.NativeActivity;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class MtNativeActivity extends NativeActivity {
|
||||
|
||||
static {
|
||||
System.loadLibrary("c++_shared");
|
||||
System.loadLibrary("openal");
|
||||
System.loadLibrary("ogg");
|
||||
System.loadLibrary("vorbis");
|
||||
System.loadLibrary("iconv");
|
||||
System.loadLibrary("minetest");
|
||||
}
|
||||
|
||||
private int m_MessagReturnCode;
|
||||
private String m_MessageReturnValue;
|
||||
|
||||
public static native void putMessageBoxResult(String text);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
m_MessagReturnCode = -1;
|
||||
m_MessageReturnValue = "";
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
makeFullScreen();
|
||||
}
|
||||
|
||||
public void makeFullScreen() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
this.getWindow().getDecorView().setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
makeFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
public void copyAssets() {
|
||||
@ -26,7 +58,7 @@ public class MtNativeActivity extends NativeActivity {
|
||||
}
|
||||
|
||||
public void showDialog(String acceptButton, String hint, String current,
|
||||
int editType) {
|
||||
int editType) {
|
||||
|
||||
Intent intent = new Intent(this, MinetestTextEntry.class);
|
||||
Bundle params = new Bundle();
|
||||
@ -37,11 +69,9 @@ public class MtNativeActivity extends NativeActivity {
|
||||
intent.putExtras(params);
|
||||
startActivityForResult(intent, 101);
|
||||
m_MessageReturnValue = "";
|
||||
m_MessagReturnCode = -1;
|
||||
m_MessagReturnCode = -1;
|
||||
}
|
||||
|
||||
public static native void putMessageBoxResult(String text);
|
||||
|
||||
/* ugly code to workaround putMessageBoxResult not beeing found */
|
||||
public int getDialogState() {
|
||||
return m_MessagReturnCode;
|
||||
@ -66,34 +96,15 @@ public class MtNativeActivity extends NativeActivity {
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
Intent data) {
|
||||
if (requestCode == 101) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
String text = data.getStringExtra("text");
|
||||
m_MessagReturnCode = 0;
|
||||
m_MessageReturnValue = text;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_MessagReturnCode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("openal");
|
||||
System.loadLibrary("ogg");
|
||||
System.loadLibrary("vorbis");
|
||||
System.loadLibrary("ssl");
|
||||
System.loadLibrary("crypto");
|
||||
System.loadLibrary("gmp");
|
||||
System.loadLibrary("iconv");
|
||||
|
||||
// We don't have to load libminetest.so ourselves,
|
||||
// but if we do, we get nicer logcat errors when
|
||||
// loading fails.
|
||||
System.loadLibrary("minetest");
|
||||
}
|
||||
|
||||
private int m_MessagReturnCode;
|
||||
private String m_MessageReturnValue;
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.4 KiB |
BIN
build/android/src/main/res/drawable/background.png
Normal file
BIN
build/android/src/main/res/drawable/background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 83 B |
4
build/android/src/main/res/drawable/bg.xml
Normal file
4
build/android/src/main/res/drawable/bg.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/background"
|
||||
android:tileMode="repeat" />
|
@ -1,24 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/activity_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar1"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical" />
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar1"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginLeft="90dp"
|
||||
android:layout_marginRight="90dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/preparing_media"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/progressBar1"
|
||||
android:layout_centerInParent="true"
|
||||
android:text="@string/preparing_media" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
BIN
build/android/src/main/res/mipmap/ic_launcher.png
Normal file
BIN
build/android/src/main/res/mipmap/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
12
build/android/src/main/res/values-v21/styles.xml
Normal file
12
build/android/src/main/res/values-v21/styles.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="@android:style/android:Theme.Material.Light.NoActionBar.Fullscreen">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<item name="android:windowBackground">@drawable/bg</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Dialog" parent="@android:style/Theme.Material.Light.Dialog.NoActionBar"/>
|
||||
|
||||
</resources>
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="preparing_media">Preparing media...</string>
|
||||
</resources>
|
||||
|
||||
<string name="preparing_media">Preparing media…</string>
|
||||
<string name="not_granted">Required permission wasn\'t granted, Minetest can\'t run without it</string>
|
||||
</resources>
|
@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.Transparent" parent="android:Theme">
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
|
||||
<style name="AppTheme" parent="@android:style/android:Theme.Holo.Light.NoActionBar.Fullscreen">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<item name="android:windowBackground">@drawable/bg</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
<style name="Theme.Dialog" parent="@android:style/android:Theme.Holo.Light.Dialog.NoActionBar"/>
|
||||
|
||||
</resources>
|
||||
|
@ -120,7 +120,12 @@ end
|
||||
-- The dumped and level arguments are internal-only.
|
||||
|
||||
function dump(o, indent, nested, level)
|
||||
if type(o) ~= "table" then
|
||||
local t = type(o)
|
||||
if not level and t == "userdata" then
|
||||
-- when userdata (e.g. player) is passed directly, print its metatable:
|
||||
return "userdata metatable: " .. dump(getmetatable(o))
|
||||
end
|
||||
if t ~= "table" then
|
||||
return basic_dump(o)
|
||||
end
|
||||
-- Contains table -> true/nil of currently nested tables
|
||||
@ -308,59 +313,25 @@ function core.formspec_escape(text)
|
||||
end
|
||||
|
||||
|
||||
function core.wrap_text(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
|
||||
retval[#retval + 1] = 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
|
||||
retval[#retval + 1] = 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
|
||||
function core.wrap_text(text, max_length, as_table)
|
||||
local result = {}
|
||||
local line = {}
|
||||
if #text <= max_length then
|
||||
return as_table and {text} or text
|
||||
end
|
||||
|
||||
--add last part of text
|
||||
if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
|
||||
retval[#retval + 1] = last_line
|
||||
retval[#retval + 1] = string_sub(text, current_idx)
|
||||
else
|
||||
last_line = last_line .. " " .. string_sub(text, current_idx)
|
||||
retval[#retval + 1] = last_line
|
||||
for word in text:gmatch('%S+') do
|
||||
local cur_length = #table.concat(line, ' ')
|
||||
if cur_length > 0 and cur_length + #word + 1 >= max_length then
|
||||
-- word wouldn't fit on current line, move to next line
|
||||
table.insert(result, table.concat(line, ' '))
|
||||
line = {}
|
||||
end
|
||||
table.insert(line, word)
|
||||
end
|
||||
|
||||
return retval
|
||||
table.insert(result, table.concat(line, ' '))
|
||||
return as_table and result or table.concat(result, '\n')
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -370,7 +341,7 @@ if INIT == "game" then
|
||||
local dirs2 = {20, 23, 22, 21}
|
||||
|
||||
function core.rotate_and_place(itemstack, placer, pointed_thing,
|
||||
infinitestacks, orient_flags)
|
||||
infinitestacks, orient_flags, prevent_after_place)
|
||||
orient_flags = orient_flags or {}
|
||||
|
||||
local unode = core.get_node_or_nil(pointed_thing.under)
|
||||
@ -379,41 +350,20 @@ if INIT == "game" then
|
||||
end
|
||||
local undef = core.registered_nodes[unode.name]
|
||||
if undef and undef.on_rightclick then
|
||||
undef.on_rightclick(pointed_thing.under, unode, placer,
|
||||
return undef.on_rightclick(pointed_thing.under, unode, placer,
|
||||
itemstack, pointed_thing)
|
||||
return
|
||||
end
|
||||
local fdir = core.dir_to_facedir(placer:get_look_dir())
|
||||
local wield_name = itemstack:get_name()
|
||||
local fdir = placer and core.dir_to_facedir(placer:get_look_dir()) or 0
|
||||
|
||||
local above = pointed_thing.above
|
||||
local under = pointed_thing.under
|
||||
local iswall = (above.y == under.y)
|
||||
local isceiling = not iswall and (above.y < under.y)
|
||||
local anode = core.get_node_or_nil(above)
|
||||
if not anode then
|
||||
return
|
||||
end
|
||||
local pos = pointed_thing.above
|
||||
local node = anode
|
||||
|
||||
if undef and undef.buildable_to then
|
||||
pos = pointed_thing.under
|
||||
node = unode
|
||||
iswall = false
|
||||
end
|
||||
|
||||
if core.is_protected(pos, placer:get_player_name()) then
|
||||
core.record_protection_violation(pos,
|
||||
placer:get_player_name())
|
||||
return
|
||||
end
|
||||
|
||||
local ndef = core.registered_nodes[node.name]
|
||||
if not ndef or not ndef.buildable_to then
|
||||
return
|
||||
end
|
||||
|
||||
if orient_flags.force_floor then
|
||||
iswall = false
|
||||
isceiling = false
|
||||
@ -427,31 +377,26 @@ if INIT == "game" then
|
||||
iswall = not iswall
|
||||
end
|
||||
|
||||
local param2 = fdir
|
||||
if iswall then
|
||||
core.set_node(pos, {name = wield_name,
|
||||
param2 = dirs1[fdir + 1]})
|
||||
param2 = dirs1[fdir + 1]
|
||||
elseif isceiling then
|
||||
if orient_flags.force_facedir then
|
||||
core.set_node(pos, {name = wield_name,
|
||||
param2 = 20})
|
||||
cparam2 = 20
|
||||
else
|
||||
core.set_node(pos, {name = wield_name,
|
||||
param2 = dirs2[fdir + 1]})
|
||||
param2 = dirs2[fdir + 1]
|
||||
end
|
||||
else -- place right side up
|
||||
if orient_flags.force_facedir then
|
||||
core.set_node(pos, {name = wield_name,
|
||||
param2 = 0})
|
||||
else
|
||||
core.set_node(pos, {name = wield_name,
|
||||
param2 = fdir})
|
||||
param2 = 0
|
||||
end
|
||||
end
|
||||
|
||||
if not infinitestacks then
|
||||
itemstack:take_item()
|
||||
return itemstack
|
||||
end
|
||||
local old_itemstack = ItemStack(itemstack)
|
||||
local new_itemstack, removed = core.item_place_node(
|
||||
itemstack, placer, pointed_thing, param2, prevent_after_place
|
||||
)
|
||||
return infinitestacks and old_itemstack or new_itemstack
|
||||
end
|
||||
|
||||
|
||||
@ -459,12 +404,18 @@ if INIT == "game" then
|
||||
--Wrapper for rotate_and_place() to check for sneak and assume Creative mode
|
||||
--implies infinite stacks when performing a 6d rotation.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local creative_mode_cache = core.settings:get_bool("creative_mode")
|
||||
local function is_creative(name)
|
||||
return creative_mode_cache or
|
||||
core.check_player_privs(name, {creative = true})
|
||||
end
|
||||
|
||||
core.rotate_node = function(itemstack, placer, pointed_thing)
|
||||
local name = placer and placer:get_player_name() or ""
|
||||
local invert_wall = placer and placer:get_player_control().sneak or false
|
||||
core.rotate_and_place(itemstack, placer, pointed_thing,
|
||||
core.settings:get_bool("creative_mode"),
|
||||
{invert_wall = placer:get_player_control().sneak})
|
||||
is_creative(name),
|
||||
{invert_wall = invert_wall}, true)
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
@ -642,44 +593,26 @@ end
|
||||
|
||||
local ESCAPE_CHAR = string.char(0x1b)
|
||||
|
||||
-- Client-side mods don't have access to settings
|
||||
if core.settings and core.settings:get_bool("disable_escape_sequences") then
|
||||
|
||||
function core.get_color_escape_sequence(color)
|
||||
return ""
|
||||
end
|
||||
|
||||
function core.get_background_escape_sequence(color)
|
||||
return ""
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
return message
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
function core.get_color_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(c@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.get_background_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(b@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
local lines = tostring(message):split("\n", true)
|
||||
local color_code = core.get_color_escape_sequence(color)
|
||||
|
||||
for i, line in ipairs(lines) do
|
||||
lines[i] = color_code .. line
|
||||
end
|
||||
|
||||
return table.concat(lines, "\n") .. core.get_color_escape_sequence("#ffffff")
|
||||
end
|
||||
|
||||
function core.get_color_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(c@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.get_background_escape_sequence(color)
|
||||
return ESCAPE_CHAR .. "(b@" .. color .. ")"
|
||||
end
|
||||
|
||||
function core.colorize(color, message)
|
||||
local lines = tostring(message):split("\n", true)
|
||||
local color_code = core.get_color_escape_sequence(color)
|
||||
|
||||
for i, line in ipairs(lines) do
|
||||
lines[i] = color_code .. line
|
||||
end
|
||||
|
||||
return table.concat(lines, "\n") .. core.get_color_escape_sequence("#ffffff")
|
||||
end
|
||||
|
||||
|
||||
function core.strip_foreground_colors(str)
|
||||
return (str:gsub(ESCAPE_CHAR .. "%(c@[^)]+%)", ""))
|
||||
end
|
||||
|
@ -67,16 +67,15 @@ local function save_auth_file()
|
||||
assert(type(stuff.privileges) == "table")
|
||||
assert(stuff.last_login == nil or type(stuff.last_login) == "number")
|
||||
end
|
||||
local file, errmsg = io.open(core.auth_file_path, 'w+b')
|
||||
if not file then
|
||||
error(core.auth_file_path.." could not be opened for writing: "..errmsg)
|
||||
end
|
||||
local content = {}
|
||||
for name, stuff in pairs(core.auth_table) do
|
||||
local priv_string = core.privs_to_string(stuff.privileges)
|
||||
local parts = {name, stuff.password, priv_string, stuff.last_login or ""}
|
||||
file:write(table.concat(parts, ":").."\n")
|
||||
content[#content + 1] = table.concat(parts, ":")
|
||||
end
|
||||
if not core.safe_file_write(core.auth_file_path, table.concat(content, "\n")) then
|
||||
error(core.auth_file_path.." could not be written to")
|
||||
end
|
||||
io.close(file)
|
||||
end
|
||||
|
||||
read_auth_file()
|
||||
|
@ -653,8 +653,8 @@ core.register_chatcommand("pulverize", {
|
||||
core.rollback_punch_callbacks = {}
|
||||
|
||||
core.register_on_punchnode(function(pos, node, puncher)
|
||||
local name = puncher:get_player_name()
|
||||
if core.rollback_punch_callbacks[name] then
|
||||
local name = puncher and puncher:get_player_name()
|
||||
if name and core.rollback_punch_callbacks[name] then
|
||||
core.rollback_punch_callbacks[name](pos, node, puncher)
|
||||
core.rollback_punch_callbacks[name] = nil
|
||||
end
|
||||
@ -814,7 +814,7 @@ core.register_chatcommand("shutdown", {
|
||||
message = message or ""
|
||||
|
||||
if delay ~= "" then
|
||||
delay = tonumber(param) or 0
|
||||
delay = tonumber(delay) or 0
|
||||
else
|
||||
delay = 0
|
||||
core.log("action", name .. " shuts down server")
|
||||
|
@ -60,8 +60,13 @@ core.register_entity(":__builtin:falling_node", {
|
||||
local pos = self.object:getpos()
|
||||
-- Position of bottom center point
|
||||
local bcp = {x = pos.x, y = pos.y - 0.7, z = pos.z}
|
||||
-- Avoid bugs caused by an unloaded node below
|
||||
-- 'bcn' is nil for unloaded nodes
|
||||
local bcn = core.get_node_or_nil(bcp)
|
||||
-- Delete on contact with ignore at world edges
|
||||
if bcn and bcn.name == "ignore" then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
local bcd = bcn and core.registered_nodes[bcn.name]
|
||||
if bcn and
|
||||
(not bcd or bcd.walkable or
|
||||
@ -93,7 +98,7 @@ core.register_entity(":__builtin:falling_node", {
|
||||
core.remove_node(np)
|
||||
if nd and nd.buildable_to == false then
|
||||
-- Add dropped items
|
||||
local drops = core.get_node_drops(n2.name, "")
|
||||
local drops = core.get_node_drops(n2, "")
|
||||
for _, dropped_item in pairs(drops) do
|
||||
core.add_item(np, dropped_item)
|
||||
end
|
||||
@ -145,9 +150,9 @@ function core.spawn_falling_node(pos)
|
||||
end
|
||||
|
||||
local function drop_attached_node(p)
|
||||
local nn = core.get_node(p).name
|
||||
local n = core.get_node(p)
|
||||
core.remove_node(p)
|
||||
for _, item in pairs(core.get_node_drops(nn, "")) do
|
||||
for _, item in pairs(core.get_node_drops(n, "")) do
|
||||
local pos = {
|
||||
x = p.x + math.random()/2 - 0.25,
|
||||
y = p.y + math.random()/2 - 0.25,
|
||||
|
@ -155,11 +155,45 @@ function core.yaw_to_dir(yaw)
|
||||
return {x = -math.sin(yaw), y = 0, z = math.cos(yaw)}
|
||||
end
|
||||
|
||||
function core.get_node_drops(nodename, toolname)
|
||||
function core.is_colored_paramtype(ptype)
|
||||
return (ptype == "color") or (ptype == "colorfacedir") or
|
||||
(ptype == "colorwallmounted")
|
||||
end
|
||||
|
||||
function core.strip_param2_color(param2, paramtype2)
|
||||
if not core.is_colored_paramtype(paramtype2) then
|
||||
return nil
|
||||
end
|
||||
if paramtype2 == "colorfacedir" then
|
||||
param2 = math.floor(param2 / 32) * 32
|
||||
elseif paramtype2 == "colorwallmounted" then
|
||||
param2 = math.floor(param2 / 8) * 8
|
||||
end
|
||||
-- paramtype2 == "color" requires no modification.
|
||||
return param2
|
||||
end
|
||||
|
||||
function core.get_node_drops(node, toolname)
|
||||
-- Compatibility, if node is string
|
||||
local nodename = node
|
||||
local param2 = 0
|
||||
-- New format, if node is table
|
||||
if (type(node) == "table") then
|
||||
nodename = node.name
|
||||
param2 = node.param2
|
||||
end
|
||||
local def = core.registered_nodes[nodename]
|
||||
local drop = def and def.drop
|
||||
local ptype = def and def.paramtype2
|
||||
-- get color, if there is color (otherwise nil)
|
||||
local palette_index = core.strip_param2_color(param2, ptype)
|
||||
if drop == nil then
|
||||
-- default drop
|
||||
if palette_index then
|
||||
local stack = ItemStack(nodename)
|
||||
stack:get_meta():set_int("palette_index", palette_index)
|
||||
return {stack:to_string()}
|
||||
end
|
||||
return {nodename}
|
||||
elseif type(drop) == "string" then
|
||||
-- itemstring drop
|
||||
@ -181,6 +215,8 @@ function core.get_node_drops(nodename, toolname)
|
||||
end
|
||||
if item.tools ~= nil then
|
||||
good_tool = false
|
||||
end
|
||||
if item.tools ~= nil and toolname then
|
||||
for _, tool in ipairs(item.tools) do
|
||||
if tool:sub(1, 1) == '~' then
|
||||
good_tool = toolname:find(tool:sub(2)) ~= nil
|
||||
@ -191,10 +227,16 @@ function core.get_node_drops(nodename, toolname)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if good_rarity and good_tool then
|
||||
got_count = got_count + 1
|
||||
for _, add_item in ipairs(item.items) do
|
||||
-- add color, if necessary
|
||||
if item.inherit_color and palette_index then
|
||||
local stack = ItemStack(add_item)
|
||||
stack:get_meta():set_int("palette_index", palette_index)
|
||||
add_item = stack:to_string()
|
||||
end
|
||||
got_items[#got_items+1] = add_item
|
||||
end
|
||||
if drop.max_items ~= nil and got_count == drop.max_items then
|
||||
@ -205,7 +247,22 @@ function core.get_node_drops(nodename, toolname)
|
||||
return got_items
|
||||
end
|
||||
|
||||
function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
local function user_name(user)
|
||||
return user and user:get_player_name() or ""
|
||||
end
|
||||
|
||||
local function is_protected(pos, name)
|
||||
return core.is_protected(pos, name) and
|
||||
not minetest.check_player_privs(name, "protection_bypass")
|
||||
end
|
||||
|
||||
-- Returns a logging function. For empty names, does not log.
|
||||
local function make_log(name)
|
||||
return name ~= "" and core.log or function() end
|
||||
end
|
||||
|
||||
function core.item_place_node(itemstack, placer, pointed_thing, param2,
|
||||
prevent_after_place)
|
||||
local def = itemstack:get_definition()
|
||||
if def.type ~= "node" or pointed_thing.type ~= "node" then
|
||||
return itemstack, false
|
||||
@ -215,10 +272,11 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
local oldnode_under = core.get_node_or_nil(under)
|
||||
local above = pointed_thing.above
|
||||
local oldnode_above = core.get_node_or_nil(above)
|
||||
local playername = placer:get_player_name()
|
||||
local playername = user_name(placer)
|
||||
local log = make_log(playername)
|
||||
|
||||
if not oldnode_under or not oldnode_above then
|
||||
core.log("info", playername .. " tried to place"
|
||||
log("info", playername .. " tried to place"
|
||||
.. " node in unloaded position " .. core.pos_to_string(above))
|
||||
return itemstack, false
|
||||
end
|
||||
@ -229,7 +287,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
olddef_above = olddef_above or core.nodedef_default
|
||||
|
||||
if not olddef_above.buildable_to and not olddef_under.buildable_to then
|
||||
core.log("info", playername .. " tried to place"
|
||||
log("info", playername .. " tried to place"
|
||||
.. " node in invalid position " .. core.pos_to_string(above)
|
||||
.. ", replacing " .. oldnode_above.name)
|
||||
return itemstack, false
|
||||
@ -240,13 +298,12 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
|
||||
-- If node under is buildable_to, place into it instead (eg. snow)
|
||||
if olddef_under.buildable_to then
|
||||
core.log("info", "node under is buildable to")
|
||||
log("info", "node under is buildable to")
|
||||
place_to = {x = under.x, y = under.y, z = under.z}
|
||||
end
|
||||
|
||||
if core.is_protected(place_to, playername) and
|
||||
not minetest.check_player_privs(placer, "protection_bypass") then
|
||||
core.log("action", playername
|
||||
if is_protected(place_to, playername) then
|
||||
log("action", playername
|
||||
.. " tried to place " .. def.name
|
||||
.. " at protected position "
|
||||
.. core.pos_to_string(place_to))
|
||||
@ -254,11 +311,11 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
core.log("action", playername .. " places node "
|
||||
log("action", playername .. " places node "
|
||||
.. def.name .. " at " .. core.pos_to_string(place_to))
|
||||
|
||||
local oldnode = core.get_node(place_to)
|
||||
local newnode = {name = def.name, param1 = 0, param2 = param2}
|
||||
local newnode = {name = def.name, param1 = 0, param2 = param2 or 0}
|
||||
|
||||
-- Calculate direction for wall mounted stuff like torches and signs
|
||||
if def.place_param2 ~= nil then
|
||||
@ -274,7 +331,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
-- Calculate the direction for furnaces and chests and stuff
|
||||
elseif (def.paramtype2 == "facedir" or
|
||||
def.paramtype2 == "colorfacedir") and not param2 then
|
||||
local placer_pos = placer:getpos()
|
||||
local placer_pos = placer and placer:getpos()
|
||||
if placer_pos then
|
||||
local dir = {
|
||||
x = above.x - placer_pos.x,
|
||||
@ -282,14 +339,33 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
z = above.z - placer_pos.z
|
||||
}
|
||||
newnode.param2 = core.dir_to_facedir(dir)
|
||||
core.log("action", "facedir: " .. newnode.param2)
|
||||
log("action", "facedir: " .. newnode.param2)
|
||||
end
|
||||
end
|
||||
|
||||
local metatable = itemstack:get_meta():to_table().fields
|
||||
|
||||
-- Transfer color information
|
||||
if metatable.palette_index and not def.place_param2 then
|
||||
local color_divisor = nil
|
||||
if def.paramtype2 == "color" then
|
||||
color_divisor = 1
|
||||
elseif def.paramtype2 == "colorwallmounted" then
|
||||
color_divisor = 8
|
||||
elseif def.paramtype2 == "colorfacedir" then
|
||||
color_divisor = 32
|
||||
end
|
||||
if color_divisor then
|
||||
local color = math.floor(metatable.palette_index / color_divisor)
|
||||
local other = newnode.param2 % color_divisor
|
||||
newnode.param2 = color * color_divisor + other
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if the node is attached and if it can be placed there
|
||||
if core.get_item_group(def.name, "attached_node") ~= 0 and
|
||||
not builtin_shared.check_attached_node(place_to, newnode) then
|
||||
core.log("action", "attached node " .. def.name ..
|
||||
log("action", "attached node " .. def.name ..
|
||||
" can not be placed at " .. core.pos_to_string(place_to))
|
||||
return itemstack, false
|
||||
end
|
||||
@ -300,7 +376,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
|
||||
local take_item = true
|
||||
|
||||
-- Run callback
|
||||
if def.after_place_node then
|
||||
if def.after_place_node and not prevent_after_place then
|
||||
-- Deepcopy place_to and pointed_thing because callback can modify it
|
||||
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||
@ -360,28 +436,27 @@ function core.item_secondary_use(itemstack, placer)
|
||||
end
|
||||
|
||||
function core.item_drop(itemstack, dropper, pos)
|
||||
if dropper and dropper:is_player() then
|
||||
local v = dropper:get_look_dir()
|
||||
local p = {x=pos.x, y=pos.y+1.2, z=pos.z}
|
||||
local cs = itemstack:get_count()
|
||||
local dropper_is_player = dropper and dropper:is_player()
|
||||
local p = table.copy(pos)
|
||||
local cnt = itemstack:get_count()
|
||||
if dropper_is_player then
|
||||
p.y = p.y + 1.2
|
||||
if dropper:get_player_control().sneak then
|
||||
cs = 1
|
||||
cnt = 1
|
||||
end
|
||||
local item = itemstack:take_item(cs)
|
||||
local obj = core.add_item(p, item)
|
||||
if obj then
|
||||
v.x = v.x*2
|
||||
v.y = v.y*2 + 2
|
||||
v.z = v.z*2
|
||||
obj:setvelocity(v)
|
||||
end
|
||||
local item = itemstack:take_item(cnt)
|
||||
local obj = core.add_item(p, item)
|
||||
if obj then
|
||||
if dropper_is_player then
|
||||
local dir = dropper:get_look_dir()
|
||||
dir.x = dir.x * 2.9
|
||||
dir.y = dir.y * 2.9 + 2
|
||||
dir.z = dir.z * 2.9
|
||||
obj:set_velocity(dir)
|
||||
obj:get_luaentity().dropped_by = dropper:get_player_name()
|
||||
return itemstack
|
||||
end
|
||||
|
||||
else
|
||||
if core.add_item(pos, itemstack) then
|
||||
return itemstack
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
-- If we reach this, adding the object to the
|
||||
-- environment failed
|
||||
@ -402,7 +477,8 @@ function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed
|
||||
itemstack:add_item(replace_with_item)
|
||||
else
|
||||
local inv = user:get_inventory()
|
||||
if inv:room_for_item("main", {name=replace_with_item}) then
|
||||
-- Check if inv is null, since non-players don't have one
|
||||
if inv and inv:room_for_item("main", {name=replace_with_item}) then
|
||||
inv:add_item("main", replace_with_item)
|
||||
else
|
||||
local pos = user:getpos()
|
||||
@ -417,7 +493,9 @@ end
|
||||
|
||||
function core.item_eat(hp_change, replace_with_item)
|
||||
return function(itemstack, user, pointed_thing) -- closure
|
||||
return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||
if user then
|
||||
return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -434,63 +512,76 @@ end
|
||||
|
||||
function core.handle_node_drops(pos, drops, digger)
|
||||
-- Add dropped items to object's inventory
|
||||
if digger:get_inventory() then
|
||||
local _, dropped_item
|
||||
for _, dropped_item in ipairs(drops) do
|
||||
local left = digger:get_inventory():add_item("main", dropped_item)
|
||||
if not left:is_empty() then
|
||||
local p = {
|
||||
x = pos.x + math.random()/2-0.25,
|
||||
y = pos.y + math.random()/2-0.25,
|
||||
z = pos.z + math.random()/2-0.25,
|
||||
}
|
||||
core.add_item(p, left)
|
||||
end
|
||||
local inv = digger and digger:get_inventory()
|
||||
local give_item
|
||||
if inv then
|
||||
give_item = function(item)
|
||||
return inv:add_item("main", item)
|
||||
end
|
||||
else
|
||||
give_item = function(item)
|
||||
-- itemstring to ItemStack for left:is_empty()
|
||||
return ItemStack(item)
|
||||
end
|
||||
end
|
||||
|
||||
for _, dropped_item in pairs(drops) do
|
||||
local left = give_item(dropped_item)
|
||||
if not left:is_empty() then
|
||||
local p = {
|
||||
x = pos.x + math.random()/2-0.25,
|
||||
y = pos.y + math.random()/2-0.25,
|
||||
z = pos.z + math.random()/2-0.25,
|
||||
}
|
||||
core.add_item(p, left)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function core.node_dig(pos, node, digger)
|
||||
local diggername = user_name(digger)
|
||||
local log = make_log(diggername)
|
||||
local def = core.registered_nodes[node.name]
|
||||
if def and (not def.diggable or
|
||||
(def.can_dig and not def.can_dig(pos, digger))) then
|
||||
core.log("info", digger:get_player_name() .. " tried to dig "
|
||||
log("info", diggername .. " tried to dig "
|
||||
.. node.name .. " which is not diggable "
|
||||
.. core.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
|
||||
if core.is_protected(pos, digger:get_player_name()) and
|
||||
not minetest.check_player_privs(digger, "protection_bypass") then
|
||||
core.log("action", digger:get_player_name()
|
||||
if is_protected(pos, diggername) then
|
||||
log("action", diggername
|
||||
.. " tried to dig " .. node.name
|
||||
.. " at protected position "
|
||||
.. core.pos_to_string(pos))
|
||||
core.record_protection_violation(pos, digger:get_player_name())
|
||||
core.record_protection_violation(pos, diggername)
|
||||
return
|
||||
end
|
||||
|
||||
core.log('action', digger:get_player_name() .. " digs "
|
||||
log('action', diggername .. " digs "
|
||||
.. node.name .. " at " .. core.pos_to_string(pos))
|
||||
|
||||
local wielded = digger:get_wielded_item()
|
||||
local drops = core.get_node_drops(node.name, wielded:get_name())
|
||||
local wielded = digger and digger:get_wielded_item()
|
||||
local drops = core.get_node_drops(node, wielded and wielded:get_name())
|
||||
|
||||
local wdef = wielded:get_definition()
|
||||
local tp = wielded:get_tool_capabilities()
|
||||
local dp = core.get_dig_params(def and def.groups, tp)
|
||||
if wdef and wdef.after_use then
|
||||
wielded = wdef.after_use(wielded, digger, node, dp) or wielded
|
||||
else
|
||||
-- Wear out tool
|
||||
if not core.settings:get_bool("creative_mode") then
|
||||
wielded:add_wear(dp.wear)
|
||||
if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then
|
||||
core.sound_play(wdef.sound.breaks, {pos = pos, gain = 0.5})
|
||||
if wielded then
|
||||
local wdef = wielded:get_definition()
|
||||
local tp = wielded:get_tool_capabilities()
|
||||
local dp = core.get_dig_params(def and def.groups, tp)
|
||||
if wdef and wdef.after_use then
|
||||
wielded = wdef.after_use(wielded, digger, node, dp) or wielded
|
||||
else
|
||||
-- Wear out tool
|
||||
if not core.settings:get_bool("creative_mode") then
|
||||
wielded:add_wear(dp.wear)
|
||||
if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then
|
||||
core.sound_play(wdef.sound.breaks, {pos = pos, gain = 0.5})
|
||||
end
|
||||
end
|
||||
end
|
||||
digger:set_wielded_item(wielded)
|
||||
end
|
||||
digger:set_wielded_item(wielded)
|
||||
|
||||
-- Handle drops
|
||||
core.handle_node_drops(pos, drops, digger)
|
||||
|
@ -174,19 +174,18 @@ core.register_entity(":__builtin:item", {
|
||||
local p = self.object:getpos()
|
||||
p.y = p.y - 0.5
|
||||
local node = core.get_node_or_nil(p)
|
||||
local in_unloaded = (node == nil)
|
||||
if in_unloaded then
|
||||
-- Don't infinetly fall into unloaded map
|
||||
self.object:setvelocity({x = 0, y = 0, z = 0})
|
||||
self.object:setacceleration({x = 0, y = 0, z = 0})
|
||||
self.physical_state = false
|
||||
self.object:set_properties({physical = false})
|
||||
-- Delete in 'ignore' nodes
|
||||
if node and node.name == "ignore" then
|
||||
self.itemstring = ""
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
local nn = node.name
|
||||
-- If node is not registered or node is walkably solid and resting on nodebox
|
||||
|
||||
-- If node is nil (unloaded area), or node is not registered, or node is
|
||||
-- walkably solid and item is resting on nodebox
|
||||
local v = self.object:getvelocity()
|
||||
if not core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then
|
||||
if not node or not core.registered_nodes[node.name] or
|
||||
core.registered_nodes[node.name].walkable and v.y == 0 then
|
||||
if self.physical_state then
|
||||
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
|
||||
-- Merge with close entities of the same item
|
||||
|
@ -5,12 +5,11 @@
|
||||
--
|
||||
|
||||
function core.check_player_privs(name, ...)
|
||||
local arg_type = type(name)
|
||||
if (arg_type == "userdata" or arg_type == "table") and
|
||||
name.get_player_name then -- If it quacks like a Player...
|
||||
if core.is_player(name) then
|
||||
name = name:get_player_name()
|
||||
elseif arg_type ~= "string" then
|
||||
error("Invalid core.check_player_privs argument type: " .. arg_type, 2)
|
||||
elseif type(name) ~= "string" then
|
||||
error("core.check_player_privs expects a player or playername as " ..
|
||||
"argument.", 2)
|
||||
end
|
||||
|
||||
local requested_privs = {...}
|
||||
@ -70,6 +69,16 @@ function core.get_connected_players()
|
||||
return temp_table
|
||||
end
|
||||
|
||||
|
||||
function core.is_player(player)
|
||||
-- a table being a player is also supported because it quacks sufficiently
|
||||
-- like a player if it has the is_player function
|
||||
local t = type(player)
|
||||
return (t == "userdata" or t == "table") and
|
||||
type(player.is_player) == "function" and player:is_player()
|
||||
end
|
||||
|
||||
|
||||
function minetest.player_exists(name)
|
||||
return minetest.get_auth_handler().get_auth(name) ~= nil
|
||||
end
|
||||
|
@ -116,6 +116,8 @@ function core.register_item(name, itemdef)
|
||||
end
|
||||
itemdef.name = name
|
||||
|
||||
local is_overriding = core.registered_items[name]
|
||||
|
||||
-- Apply defaults and add to registered_* table
|
||||
if itemdef.type == "node" then
|
||||
-- Use the nodebox as selection box if it's not set manually
|
||||
@ -177,7 +179,13 @@ function core.register_item(name, itemdef)
|
||||
--core.log("Registering item: " .. itemdef.name)
|
||||
core.registered_items[itemdef.name] = itemdef
|
||||
core.registered_aliases[itemdef.name] = nil
|
||||
register_item_raw(itemdef)
|
||||
|
||||
-- Used to allow builtin to register ignore to registered_items
|
||||
if name ~= "ignore" then
|
||||
register_item_raw(itemdef)
|
||||
elseif is_overriding then
|
||||
core.log("warning", "Attempted redefinition of \"ignore\"")
|
||||
end
|
||||
end
|
||||
|
||||
function core.unregister_item(name)
|
||||
|
@ -21,7 +21,6 @@ if core.print then
|
||||
core.print = nil -- don't pollute our namespace
|
||||
end
|
||||
math.randomseed(os.time())
|
||||
os.setlocale("C", "numeric")
|
||||
minetest = core
|
||||
|
||||
-- Load other files
|
||||
@ -47,7 +46,6 @@ elseif INIT == "mainmenu" then
|
||||
elseif INIT == "async" then
|
||||
dofile(asyncpath .. "init.lua")
|
||||
elseif INIT == "client" then
|
||||
os.setlocale = nil
|
||||
dofile(clientpath .. "init.lua")
|
||||
else
|
||||
error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT)))
|
||||
|
@ -250,7 +250,7 @@ end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
|
||||
local textlines = core.wrap_text(text, textlen)
|
||||
local textlines = core.wrap_text(text, textlen, true)
|
||||
local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
|
||||
"," .. height .. ";" .. tl_name .. ";"
|
||||
|
||||
|
@ -17,39 +17,36 @@
|
||||
|
||||
|
||||
local function delete_world_formspec(dialogdata)
|
||||
|
||||
local retval =
|
||||
"size[11.5,4.5,true]" ..
|
||||
"label[2,2;" ..
|
||||
"size[10,2.5,true]" ..
|
||||
"label[0.5,0.5;" ..
|
||||
fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
|
||||
"button[3.25,3.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
|
||||
"button[5.75,3.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
|
||||
"button[0.5,1.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
|
||||
"button[7.0,1.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
|
||||
return retval
|
||||
end
|
||||
|
||||
local function delete_world_buttonhandler(this, fields)
|
||||
if fields["world_delete_confirm"] then
|
||||
|
||||
if this.data.delete_index > 0 and
|
||||
this.data.delete_index <= #menudata.worldlist:get_raw_list() then
|
||||
this.data.delete_index <= #menudata.worldlist:get_raw_list() then
|
||||
core.delete_world(this.data.delete_index)
|
||||
menudata.worldlist:refresh()
|
||||
end
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
if fields["world_delete_cancel"] then
|
||||
this:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function create_delete_world_dlg(name_to_del,index_to_del)
|
||||
|
||||
function create_delete_world_dlg(name_to_del, index_to_del)
|
||||
assert(name_to_del ~= nil and type(name_to_del) == "string" and name_to_del ~= "")
|
||||
assert(index_to_del ~= nil and type(index_to_del) == "number")
|
||||
|
||||
@ -59,6 +56,6 @@ function create_delete_world_dlg(name_to_del,index_to_del)
|
||||
nil)
|
||||
retval.data.delete_name = name_to_del
|
||||
retval.data.delete_index = index_to_del
|
||||
|
||||
|
||||
return retval
|
||||
end
|
||||
|
@ -74,7 +74,7 @@ local previous_contributors = {
|
||||
}
|
||||
|
||||
local function buildCreditList(source)
|
||||
ret = {}
|
||||
local ret = {}
|
||||
for i = 1, #source do
|
||||
ret[i] = core.formspec_escape(source[i])
|
||||
end
|
||||
|
@ -75,7 +75,7 @@ local function get_formspec(tabview, name, tabdata)
|
||||
if error == nil then
|
||||
local descriptiontext = descriptionfile:read("*all")
|
||||
|
||||
descriptionlines = core.wrap_text(descriptiontext, 42)
|
||||
descriptionlines = core.wrap_text(descriptiontext, 42, true)
|
||||
descriptionfile:close()
|
||||
else
|
||||
descriptionlines = {}
|
||||
|
@ -176,7 +176,7 @@ end
|
||||
|
||||
local function formspec(tabview, name, tabdata)
|
||||
local tab_string =
|
||||
"box[0,0;3.5,4.5;#999999]" ..
|
||||
"box[0,0;3.75,4.5;#999999]" ..
|
||||
"checkbox[0.25,0;cb_smooth_lighting;" .. fgettext("Smooth Lighting") .. ";"
|
||||
.. dump(core.settings:get_bool("smooth_lighting")) .. "]" ..
|
||||
"checkbox[0.25,0.5;cb_particles;" .. fgettext("Particles") .. ";"
|
||||
@ -187,38 +187,38 @@ local function formspec(tabview, name, tabdata)
|
||||
.. dump(core.settings:get_bool("opaque_water")) .. "]" ..
|
||||
"checkbox[0.25,2.0;cb_connected_glass;" .. fgettext("Connected Glass") .. ";"
|
||||
.. dump(core.settings:get_bool("connected_glass")) .. "]" ..
|
||||
"dropdown[0.25,2.8;3.3;dd_node_highlighting;" .. dd_options.node_highlighting[1] .. ";"
|
||||
"dropdown[0.25,2.8;3.5;dd_node_highlighting;" .. dd_options.node_highlighting[1] .. ";"
|
||||
.. getSettingIndex.NodeHighlighting() .. "]" ..
|
||||
"dropdown[0.25,3.6;3.3;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
|
||||
"dropdown[0.25,3.6;3.5;dd_leaves_style;" .. dd_options.leaves[1] .. ";"
|
||||
.. getSettingIndex.Leaves() .. "]" ..
|
||||
"box[3.75,0;3.75,4.45;#999999]" ..
|
||||
"label[3.85,0.1;" .. fgettext("Texturing:") .. "]" ..
|
||||
"dropdown[3.85,0.55;3.85;dd_filters;" .. dd_options.filters[1] .. ";"
|
||||
"box[4,0;3.75,4.5;#999999]" ..
|
||||
"label[4.25,0.1;" .. fgettext("Texturing:") .. "]" ..
|
||||
"dropdown[4.25,0.55;3.5;dd_filters;" .. dd_options.filters[1] .. ";"
|
||||
.. getSettingIndex.Filter() .. "]" ..
|
||||
"dropdown[3.85,1.35;3.85;dd_mipmap;" .. dd_options.mipmap[1] .. ";"
|
||||
"dropdown[4.25,1.35;3.5;dd_mipmap;" .. dd_options.mipmap[1] .. ";"
|
||||
.. getSettingIndex.Mipmap() .. "]" ..
|
||||
"label[3.85,2.15;" .. fgettext("Antialiasing:") .. "]" ..
|
||||
"dropdown[3.85,2.6;3.85;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
|
||||
"label[4.25,2.15;" .. fgettext("Antialiasing:") .. "]" ..
|
||||
"dropdown[4.25,2.6;3.5;dd_antialiasing;" .. dd_options.antialiasing[1] .. ";"
|
||||
.. getSettingIndex.Antialiasing() .. "]" ..
|
||||
"label[3.85,3.45;" .. fgettext("Screen:") .. "]" ..
|
||||
"checkbox[3.85,3.6;cb_autosave_screensize;" .. fgettext("Autosave screen size") .. ";"
|
||||
"label[4.25,3.45;" .. fgettext("Screen:") .. "]" ..
|
||||
"checkbox[4.25,3.6;cb_autosave_screensize;" .. fgettext("Autosave screen size") .. ";"
|
||||
.. dump(core.settings:get_bool("autosave_screensize")) .. "]" ..
|
||||
"box[7.75,0;4,4.4;#999999]" ..
|
||||
"checkbox[8,0;cb_shaders;" .. fgettext("Shaders") .. ";"
|
||||
"box[8,0;3.75,4.5;#999999]" ..
|
||||
"checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_shaders")) .. "]"
|
||||
|
||||
if PLATFORM == "Android" then
|
||||
tab_string = tab_string ..
|
||||
"button[8,4.75;3.75,0.5;btn_reset_singleplayer;"
|
||||
"button[8,4.75;4.1,1;btn_reset_singleplayer;"
|
||||
.. fgettext("Reset singleplayer world") .. "]"
|
||||
else
|
||||
tab_string = tab_string ..
|
||||
"button[8,4.85;3.75,0.5;btn_change_keys;"
|
||||
"button[8,4.75;4,1;btn_change_keys;"
|
||||
.. fgettext("Change keys") .. "]"
|
||||
end
|
||||
|
||||
tab_string = tab_string ..
|
||||
"button[0,4.85;3.75,0.5;btn_advanced_settings;"
|
||||
"button[0,4.75;4,1;btn_advanced_settings;"
|
||||
.. fgettext("Advanced Settings") .. "]"
|
||||
|
||||
|
||||
@ -231,19 +231,19 @@ local function formspec(tabview, name, tabdata)
|
||||
|
||||
if core.settings:get_bool("enable_shaders") then
|
||||
tab_string = tab_string ..
|
||||
"checkbox[8,0.5;cb_bumpmapping;" .. fgettext("Bump Mapping") .. ";"
|
||||
"checkbox[8.25,0.5;cb_bumpmapping;" .. fgettext("Bump Mapping") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_bumpmapping")) .. "]" ..
|
||||
"checkbox[8,1;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
|
||||
"checkbox[8.25,1;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
|
||||
.. dump(core.settings:get_bool("tone_mapping")) .. "]" ..
|
||||
"checkbox[8,1.5;cb_generate_normalmaps;" .. fgettext("Normal Mapping") .. ";"
|
||||
"checkbox[8.25,1.5;cb_generate_normalmaps;" .. fgettext("Normal Mapping") .. ";"
|
||||
.. dump(core.settings:get_bool("generate_normalmaps")) .. "]" ..
|
||||
"checkbox[8,2;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";"
|
||||
"checkbox[8.25,2;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_parallax_occlusion")) .. "]" ..
|
||||
"checkbox[8,2.5;cb_waving_water;" .. fgettext("Waving Water") .. ";"
|
||||
"checkbox[8.25,2.5;cb_waving_water;" .. fgettext("Waving Water") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_water")) .. "]" ..
|
||||
"checkbox[8,3;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
|
||||
"checkbox[8.25,3;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_leaves")) .. "]" ..
|
||||
"checkbox[8,3.5;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
|
||||
"checkbox[8.25,3.5;cb_waving_plants;" .. fgettext("Waving Plants") .. ";"
|
||||
.. dump(core.settings:get_bool("enable_waving_plants")) .. "]"
|
||||
else
|
||||
tab_string = tab_string ..
|
||||
|
@ -133,7 +133,7 @@ local function instrument_register(func, func_name)
|
||||
return func(instrument {
|
||||
func = callback,
|
||||
func_name = register_name
|
||||
}), ...
|
||||
}, ...)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -166,10 +166,6 @@ keymap_cmd (Command key) key /
|
||||
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
|
||||
keymap_cmd_local (Command key) key .
|
||||
|
||||
# Key for opening the chat console.
|
||||
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
|
||||
keyman_console (Console key) key KEY_F10
|
||||
|
||||
# Key for toggling unlimited view range.
|
||||
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
|
||||
keymap_rangeselect (Range select key) key KEY_KEY_R
|
||||
@ -476,6 +472,12 @@ pause_fps_max (FPS in pause menu) int 20
|
||||
# View distance in nodes.
|
||||
viewing_range (Viewing range) int 100 20 4000
|
||||
|
||||
# Camera near plane distance in nodes, between 0 and 0.5
|
||||
# Most users will not need to change this.
|
||||
# Increasing can reduce artifacting on weaker GPUs.
|
||||
# 0.1 = Default, 0.25 = Good value for weaker tablets.
|
||||
near_plane (Near plane) float 0.1 0 0.5
|
||||
|
||||
# Width component of the initial window size.
|
||||
screenW (Screen width) int 800
|
||||
|
||||
@ -721,10 +723,9 @@ server_announce (Announce server) bool false
|
||||
# If you want to announce your ipv6 address, use serverlist_url = v6.servers.minetest.net.
|
||||
serverlist_url (Serverlist URL) string servers.minetest.net
|
||||
|
||||
# Disable escape sequences, e.g. chat coloring.
|
||||
# Use this if you want to run a server with pre-0.4.14 clients and you want to disable
|
||||
# the escape sequences generated by mods.
|
||||
disable_escape_sequences (Disable escape sequences) bool false
|
||||
# Remove color codes from incoming chat messages
|
||||
# Use this to stop players from being able to use color in their messages
|
||||
strip_color_codes (Strip color codes) bool false
|
||||
|
||||
[*Network]
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
FIND_PATH(LUA_INCLUDE_DIR luajit.h
|
||||
HINTS
|
||||
$ENV{LUA_DIR}
|
||||
PATH_SUFFIXES include/luajit-2.0 include/luajit-5_1-2.0 include
|
||||
PATH_SUFFIXES include/luajit-2.1 include/luajit-2.0 include/luajit-5_1-2.1 include/luajit-5_1-2.0 include
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
|
@ -628,6 +628,9 @@ Minetest namespace reference
|
||||
version entirely. To check for the presence of engine features, test
|
||||
whether the functions exported by the wanted features exist. For example:
|
||||
`if minetest.nodeupdate then ... end`.
|
||||
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data
|
||||
* `data`: string of data to hash
|
||||
* `raw`: return raw bytes instead of hex digits, default: false
|
||||
|
||||
### Logging
|
||||
* `minetest.debug(...)`
|
||||
@ -1117,15 +1120,15 @@ The following functions provide escape sequences:
|
||||
`minetest.get_color_escape_sequence(color) ..
|
||||
message ..
|
||||
minetest.get_color_escape_sequence("#ffffff")`
|
||||
* `color.get_background_escape_sequence(color)`
|
||||
* `minetest.get_background_escape_sequence(color)`
|
||||
* `color` is a [ColorString](#colorstring)
|
||||
* The escape sequence sets the background of the whole text element to
|
||||
`color`. Only defined for item descriptions and tooltips.
|
||||
* `color.strip_foreground_colors(str)`
|
||||
* `minetest.strip_foreground_colors(str)`
|
||||
* Removes foreground colors added by `get_color_escape_sequence`.
|
||||
* `color.strip_background_colors(str)`
|
||||
* `minetest.strip_background_colors(str)`
|
||||
* Removes background colors added by `get_background_escape_sequence`.
|
||||
* `color.strip_colors(str)`
|
||||
* `minetest.strip_colors(str)`
|
||||
* Removes all color escape sequences.
|
||||
|
||||
`ColorString`
|
||||
|
290
doc/lua_api.txt
290
doc/lua_api.txt
@ -1,4 +1,4 @@
|
||||
Minetest Lua Modding API Reference 0.4.16
|
||||
Minetest Lua Modding API Reference 0.4.17
|
||||
=========================================
|
||||
* More information at <http://www.minetest.net/>
|
||||
* Developer Wiki: <http://dev.minetest.net/>
|
||||
@ -211,7 +211,8 @@ when registering it.
|
||||
|
||||
The `:` prefix can also be used for maintaining backwards compatibility.
|
||||
|
||||
### Aliases
|
||||
Aliases
|
||||
-------
|
||||
Aliases can be added by using `minetest.register_alias(name, convert_to)` or
|
||||
`minetest.register_alias_force(name, convert_to)`.
|
||||
|
||||
@ -232,6 +233,75 @@ you have an item called `epiclylongmodname:stuff`, you could do
|
||||
|
||||
and be able to use `/giveme stuff`.
|
||||
|
||||
Mapgen aliases
|
||||
--------------
|
||||
In a game, a certain number of these must be set to tell core mapgens which
|
||||
of the game's nodes are to be used by the core mapgens. For example:
|
||||
|
||||
minetest.register_alias("mapgen_stone", "default:stone")
|
||||
|
||||
### Aliases needed for all mapgens except Mapgen v6
|
||||
|
||||
Base terrain:
|
||||
|
||||
"mapgen_stone"
|
||||
"mapgen_water_source"
|
||||
"mapgen_river_water_source"
|
||||
|
||||
Caves:
|
||||
|
||||
"mapgen_lava_source"
|
||||
|
||||
Dungeons:
|
||||
|
||||
Only needed for registered biomes where 'node_stone' is stone:
|
||||
"mapgen_cobble"
|
||||
"mapgen_stair_cobble"
|
||||
"mapgen_mossycobble"
|
||||
Only needed for registered biomes where 'node_stone' is desert stone:
|
||||
"mapgen_desert_stone"
|
||||
"mapgen_stair_desert_stone"
|
||||
Only needed for registered biomes where 'node_stone' is sandstone:
|
||||
"mapgen_sandstone"
|
||||
"mapgen_sandstonebrick"
|
||||
"mapgen_stair_sandstone_block"
|
||||
|
||||
### Aliases needed for Mapgen v6
|
||||
|
||||
Terrain and biomes:
|
||||
|
||||
"mapgen_stone"
|
||||
"mapgen_water_source"
|
||||
"mapgen_lava_source"
|
||||
"mapgen_dirt"
|
||||
"mapgen_dirt_with_grass"
|
||||
"mapgen_sand"
|
||||
"mapgen_gravel"
|
||||
"mapgen_desert_stone"
|
||||
"mapgen_desert_sand"
|
||||
"mapgen_dirt_with_snow"
|
||||
"mapgen_snowblock"
|
||||
"mapgen_snow"
|
||||
"mapgen_ice"
|
||||
|
||||
Flora:
|
||||
|
||||
"mapgen_tree"
|
||||
"mapgen_leaves"
|
||||
"mapgen_apple"
|
||||
"mapgen_jungletree"
|
||||
"mapgen_jungleleaves"
|
||||
"mapgen_junglegrass"
|
||||
"mapgen_pine_tree"
|
||||
"mapgen_pine_needles"
|
||||
|
||||
Dungeons:
|
||||
|
||||
"mapgen_cobble"
|
||||
"mapgen_stair_cobble"
|
||||
"mapgen_mossycobble"
|
||||
"mapgen_stair_desert_stone"
|
||||
|
||||
Textures
|
||||
--------
|
||||
Mods should generally prefix their textures with `modname_`, e.g. given
|
||||
@ -531,9 +601,26 @@ for conversion.
|
||||
If the `ItemStack`'s metadata contains the `color` field, it will be
|
||||
lost on placement, because nodes on the map can only use palettes.
|
||||
|
||||
If the `ItemStack`'s metadata contains the `palette_index` field, you
|
||||
currently must manually convert between it and the node's `param2` with
|
||||
custom `on_place` and `on_dig` callbacks.
|
||||
If the `ItemStack`'s metadata contains the `palette_index` field, it is
|
||||
automatically transferred between node and item forms by the engine,
|
||||
when a player digs or places a colored node.
|
||||
You can disable this feature by setting the `drop` field of the node
|
||||
to itself (without metadata).
|
||||
To transfer the color to a special drop, you need a drop table.
|
||||
Example:
|
||||
|
||||
minetest.register_node("mod:stone", {
|
||||
description = "Stone",
|
||||
tiles = {"default_stone.png"},
|
||||
paramtype2 = "color",
|
||||
palette = "palette.png",
|
||||
drop = {
|
||||
items = {
|
||||
-- assume that mod:cobblestone also has the same palette
|
||||
{items = {"mod:cobblestone"}, inherit_color = true },
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
### Colored items in craft recipes
|
||||
Craft recipes only support item strings, but fortunately item strings
|
||||
@ -792,6 +879,11 @@ node definition:
|
||||
0 = y+ 1 = z+ 2 = z- 3 = x+ 4 = x- 5 = y-
|
||||
facedir modulo 4 = rotation around that axis
|
||||
paramtype2 == "leveled"
|
||||
^ Only valid for "nodebox" with type = "leveled".
|
||||
The level of the top face of the nodebox is stored in param2.
|
||||
The other faces are defined by 'fixed = {}' like 'type = "fixed"' nodeboxes.
|
||||
The nodebox height is param2 / 64 nodes.
|
||||
The maximum accepted value of param2 is 127.
|
||||
paramtype2 == "degrotate"
|
||||
^ The rotation of this node is stored in param2. Plants are rotated this way.
|
||||
Values range 0 - 179. The value stored in param2 is multiplied by two to
|
||||
@ -2060,15 +2152,15 @@ The following functions provide escape sequences:
|
||||
`minetest.get_color_escape_sequence(color) ..
|
||||
message ..
|
||||
minetest.get_color_escape_sequence("#ffffff")`
|
||||
* `color.get_background_escape_sequence(color)`
|
||||
* `minetest.get_background_escape_sequence(color)`
|
||||
* `color` is a ColorString
|
||||
* The escape sequence sets the background of the whole text element to
|
||||
`color`. Only defined for item descriptions and tooltips.
|
||||
* `color.strip_foreground_colors(str)`
|
||||
* `minetest.strip_foreground_colors(str)`
|
||||
* Removes foreground colors added by `get_color_escape_sequence`.
|
||||
* `color.strip_background_colors(str)`
|
||||
* `minetest.strip_background_colors(str)`
|
||||
* Removes background colors added by `get_background_escape_sequence`.
|
||||
* `color.strip_colors(str)`
|
||||
* `minetest.strip_colors(str)`
|
||||
* Removes all color escape sequences.
|
||||
|
||||
Spatial Vectors
|
||||
@ -2111,9 +2203,11 @@ Helper functions
|
||||
* e.g. `string:split("a,b", ",") == {"a","b"}`
|
||||
* `string:trim()`
|
||||
* e.g. `string.trim("\n \t\tfoo bar\t ") == "foo bar"`
|
||||
* `minetest.wrap_text(str, limit)`: returns a string
|
||||
* Adds new lines to the string to keep it within the specified character limit
|
||||
* `minetest.wrap_text(str, limit, [as_table])`: returns a string or table
|
||||
* Adds newlines to the string to keep it within the specified character limit
|
||||
Note that returned lines may be longer than the limit since it only splits at word borders.
|
||||
* limit: Maximal amount of characters in one line
|
||||
* as_table: optional, if true return table of lines instead of string
|
||||
* `minetest.pos_to_string({x=X,y=Y,z=Z}, decimal_places))`: returns string `"(X,Y,Z)"`
|
||||
* Convert position to a printable string
|
||||
Optional: 'decimal_places' will round the x, y and z of the pos to the given decimal place.
|
||||
@ -2181,7 +2275,7 @@ Helper functions
|
||||
max_jitter = 0.5, -- maximum packet time jitter
|
||||
avg_jitter = 0.03, -- average packet time jitter
|
||||
connection_uptime = 200, -- seconds since client connected
|
||||
prot_vers = 31, -- protocol version used by client
|
||||
protocol_version = 32, -- protocol version used by client
|
||||
-- following information is available on debug build only!!!
|
||||
-- DO NOT USE IN MODS
|
||||
--ser_vers = 26, -- serialization version used by client
|
||||
@ -2199,6 +2293,10 @@ Helper functions
|
||||
* nil: return all entries,
|
||||
* true: return only subdirectory names, or
|
||||
* false: return only file names.
|
||||
* `minetest.safe_file_write(path, content)`: returns boolean indicating success
|
||||
* Replaces contents of file at path with new contents in a safe (atomic) way.
|
||||
Use this instead of below code when writing e.g. database files:
|
||||
`local f = io.open(path, "wb"); f:write(content); f:close()`
|
||||
* `minetest.get_version()`: returns a table containing components of the
|
||||
engine version. Components:
|
||||
* `project`: Name of the project, eg, "Minetest"
|
||||
@ -2210,6 +2308,9 @@ Helper functions
|
||||
version entirely. To check for the presence of engine features, test
|
||||
whether the functions exported by the wanted features exist. For example:
|
||||
`if minetest.nodeupdate then ... end`.
|
||||
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data
|
||||
* `data`: string of data to hash
|
||||
* `raw`: return raw bytes instead of hex digits, default: false
|
||||
|
||||
### Logging
|
||||
* `minetest.debug(...)`
|
||||
@ -2229,6 +2330,8 @@ Call these functions only at load time!
|
||||
* `minetest.register_craftitem(name, item definition)`
|
||||
* `minetest.unregister_item(name)`
|
||||
* `minetest.register_alias(name, convert_to)`
|
||||
* Also use this to set the 'mapgen aliases' needed in a game for the core
|
||||
* mapgens. See 'Mapgen aliases' section above.
|
||||
* `minetest.register_alias_force(name, convert_to)`
|
||||
* `minetest.register_craft(recipe)`
|
||||
* Check recipe table syntax for different types below.
|
||||
@ -2263,6 +2366,7 @@ Call these functions only at load time!
|
||||
* `minetest.register_on_placenode(func(pos, newnode, placer, oldnode, itemstack, pointed_thing))`
|
||||
* Called when a node has been placed
|
||||
* If return `true` no item is taken from `itemstack`
|
||||
* `placer` may be any valid ObjectRef or nil.
|
||||
* **Not recommended**; use `on_construct` or `after_place_node` in node definition
|
||||
whenever possible
|
||||
* `minetest.register_on_dignode(func(pos, oldnode, digger))`
|
||||
@ -2356,8 +2460,9 @@ Call these functions only at load time!
|
||||
* `definition`: `{ description = "description text", give_to_singleplayer = boolean}`
|
||||
the default of `give_to_singleplayer` is true
|
||||
* To allow players with `basic_privs` to grant, see `basic_privs` minetest.conf setting.
|
||||
* `minetest.register_authentication_handler(handler)`
|
||||
* See `minetest.builtin_auth_handler` in `builtin.lua` for reference
|
||||
* `minetest.register_authentication_handler(authentication handler definition)`
|
||||
* Registers an auth handler that overrides the builtin one
|
||||
* This function can be called by a single mod once only.
|
||||
|
||||
### Setting-related
|
||||
* `minetest.settings`: Settings object containing all of the settings from the
|
||||
@ -2366,37 +2471,44 @@ Call these functions only at load time!
|
||||
parses it as a position (in the format `(1,2,3)`). Returns a position or nil.
|
||||
|
||||
### Authentication
|
||||
* `minetest.notify_authentication_modified(name)`
|
||||
* Should be called by the authentication handler if privileges changes.
|
||||
* To report everybody, set `name=nil`.
|
||||
* `minetest.check_password_entry(name, entry, password)`
|
||||
* Returns true if the "db entry" for a player with name matches given
|
||||
* password, false otherwise.
|
||||
* The "db entry" is the usually player-individual value that is derived
|
||||
* from the player's chosen password and stored on the server in order to allow
|
||||
* authentication whenever the player desires to log in.
|
||||
* Only use this function for making it possible to log in via the password from
|
||||
* via protocols like IRC, other uses for inside the game are frowned upon.
|
||||
* `minetest.get_password_hash(name, raw_password)`
|
||||
* Convert a name-password pair to a password hash that Minetest can use.
|
||||
* The returned value alone is not a good basis for password checks based
|
||||
* on comparing the password hash in the database with the password hash
|
||||
* from the function, with an externally provided password, as the hash
|
||||
* in the db might use the new SRP verifier format.
|
||||
* For this purpose, use `minetest.check_password_entry` instead.
|
||||
* `minetest.string_to_privs(str)`: returns `{priv1=true,...}`
|
||||
* `minetest.privs_to_string(privs)`: returns `"priv1,priv2,..."`
|
||||
* Convert between two privilege representations
|
||||
* `minetest.set_player_password(name, password_hash)`
|
||||
* `minetest.set_player_privs(name, {priv1=true,...})`
|
||||
* `minetest.get_player_privs(name) -> {priv1=true,...}`
|
||||
* `minetest.auth_reload()`
|
||||
* `minetest.check_player_privs(player_or_name, ...)`: returns `bool, missing_privs`
|
||||
* A quickhand for checking privileges.
|
||||
* `player_or_name`: Either a Player object or the name of a player.
|
||||
* `...` is either a list of strings, e.g. `"priva", "privb"` or
|
||||
a table, e.g. `{ priva = true, privb = true }`.
|
||||
* `minetest.get_player_ip(name)`: returns an IP address string
|
||||
* `player_or_name`: Either a Player object or the name of a player.
|
||||
* `...` is either a list of strings, e.g. `"priva", "privb"` or
|
||||
a table, e.g. `{ priva = true, privb = true }`.
|
||||
|
||||
* `minetest.check_password_entry(name, entry, password)`
|
||||
* Returns true if the "password entry" for a player with name matches given
|
||||
password, false otherwise.
|
||||
* The "password entry" is the password representation generated by the engine
|
||||
as returned as part of a `get_auth()` call on the auth handler.
|
||||
* Only use this function for making it possible to log in via password from
|
||||
external protocols such as IRC, other uses are frowned upon.
|
||||
* `minetest.get_password_hash(name, raw_password)`
|
||||
* Convert a name-password pair to a password hash that Minetest can use.
|
||||
* The returned value alone is not a good basis for password checks based
|
||||
on comparing the password hash in the database with the password hash
|
||||
from the function, with an externally provided password, as the hash
|
||||
in the db might use the new SRP verifier format.
|
||||
* For this purpose, use `minetest.check_password_entry` instead.
|
||||
* `minetest.get_player_ip(name)`: returns an IP address string for the player `name`
|
||||
* The player needs to be online for this to be successful.
|
||||
|
||||
* `minetest.get_auth_handler()`: Return the currently active auth handler
|
||||
* See the `Authentication handler definition`
|
||||
* Use this to e.g. get the authentication data for a player:
|
||||
`local auth_data = minetest.get_auth_handler().get_auth(playername)`
|
||||
* `minetest.notify_authentication_modified(name)`
|
||||
* Must be called by the authentication handler for privilege changes.
|
||||
* `name`: string; if omitted, all auth data should be considered modified
|
||||
* `minetest.set_player_password(name, password_hash)`: Set password hash of player `name`
|
||||
* `minetest.set_player_privs(name, {priv1=true,...})`: Set privileges of player `name`
|
||||
* `minetest.auth_reload()`
|
||||
* See `reload()` in authentication handler definition
|
||||
|
||||
`minetest.set_player_password`, `minetest_set_player_privs`, `minetest_get_player_privs`
|
||||
and `minetest.auth_reload` call the authetification handler.
|
||||
@ -2462,12 +2574,15 @@ and `minetest.auth_reload` call the authetification handler.
|
||||
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
||||
* `search_center` is an optional boolean (default: `false`)
|
||||
If true `pos` is also checked for the nodes
|
||||
* `minetest.find_nodes_in_area(minp, maxp, nodenames)`: returns a list of positions
|
||||
* returns as second value a table with the count of the individual nodes found
|
||||
* `minetest.find_nodes_in_area(pos1, pos2, nodenames)`: returns a list of positions
|
||||
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
||||
* `minetest.find_nodes_in_area_under_air(minp, maxp, nodenames)`: returns a list of positions
|
||||
* returned positions are nodes with a node air above
|
||||
* First return value: Table with all node positions
|
||||
* Second return value: Table with the count of each node with the node name as index
|
||||
* Area volume is limited to 4,096,000 nodes
|
||||
* `minetest.find_nodes_in_area_under_air(pos1, pos2, nodenames)`: returns a list of positions
|
||||
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
||||
* Return value: Table with all node positions with a node air above
|
||||
* Area volume is limited to 4,096,000 nodes
|
||||
* `minetest.get_perlin(noiseparams)`
|
||||
* `minetest.get_perlin(seeddiff, octaves, persistence, scale)`
|
||||
* Return world-specific perlin noise (`int(worldseed)+seeddiff`)
|
||||
@ -2676,6 +2791,13 @@ and `minetest.auth_reload` call the authetification handler.
|
||||
* Convert a vector into a yaw (angle)
|
||||
* `minetest.yaw_to_dir(yaw)`
|
||||
* Convert yaw (angle) to a vector
|
||||
* `minetest.is_colored_paramtype(ptype)`
|
||||
* Returns a boolean. Returns `true` if the given `paramtype2` contains color
|
||||
information (`color`, `colorwallmounted` or `colorfacedir`).
|
||||
* `minetest.strip_param2_color(param2, paramtype2)`
|
||||
* Removes everything but the color information from the
|
||||
given `param2` value.
|
||||
* Returns `nil` if the given `paramtype2` does not contain color information
|
||||
* `minetest.get_node_drops(nodename, toolname)`
|
||||
* Returns list of item names.
|
||||
* **Note**: This will be removed or modified in a future version.
|
||||
@ -2711,9 +2833,9 @@ and `minetest.auth_reload` call the authetification handler.
|
||||
* Example query for `"default:gold_ingot"` will return table:
|
||||
|
||||
{
|
||||
[1]={type = "cooking", width = 3, output = "default:gold_ingot",
|
||||
[1]={method = "cooking", width = 3, output = "default:gold_ingot",
|
||||
items = {1 = "default:gold_lump"}},
|
||||
[2]={type = "normal", width = 1, output = "default:gold_ingot 9",
|
||||
[2]={method = "normal", width = 1, output = "default:gold_ingot 9",
|
||||
items = {1 = "default:goldblock"}}
|
||||
}
|
||||
* `minetest.handle_node_drops(pos, drops, digger)`
|
||||
@ -2735,9 +2857,11 @@ and `minetest.auth_reload` call the authetification handler.
|
||||
### Defaults for the `on_*` item definition functions
|
||||
These functions return the leftover itemstack.
|
||||
|
||||
* `minetest.item_place_node(itemstack, placer, pointed_thing, param2)`
|
||||
* `minetest.item_place_node(itemstack, placer, pointed_thing[, param2, prevent_after_place])`
|
||||
* Place item as a node
|
||||
* `param2` overrides `facedir` and wallmounted `param2`
|
||||
* `prevent_after_place`: if set to `true`, `after_place_node` is not called
|
||||
for the newly placed node to prevent a callback and placement loop
|
||||
* returns `itemstack, success`
|
||||
* `minetest.item_place_object(itemstack, placer, pointed_thing)`
|
||||
* Place item as-is
|
||||
@ -2893,6 +3017,7 @@ These functions return the leftover itemstack.
|
||||
|
||||
### Misc.
|
||||
* `minetest.get_connected_players()`: returns list of `ObjectRefs`
|
||||
* `minetest.is_player(o)`: boolean, whether `o` is a player
|
||||
* `minetest.player_exists(name)`: boolean, whether player exists (regardless of online status)
|
||||
* `minetest.hud_replace_builtin(name, hud_definition)`
|
||||
* Replaces definition of a builtin hud element
|
||||
@ -2960,6 +3085,7 @@ These functions return the leftover itemstack.
|
||||
* Returns true, if player `name` shouldn't be abled to dig at `pos` or do other
|
||||
actions, defineable by mods, due to some mod-defined ownership-like concept.
|
||||
Returns false or nil, if the player is allowed to do such actions.
|
||||
* `name` will be "" for non-players or unknown players.
|
||||
* This function should be overridden 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
|
||||
@ -2976,25 +3102,29 @@ These functions return the leftover itemstack.
|
||||
* `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)`
|
||||
* `minetest.rotate_and_place(itemstack, placer, pointed_thing[, infinitestacks,
|
||||
orient_flags, prevent_after_place])`
|
||||
* 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.
|
||||
defined by `itemstack`, and place it accordingly (on-wall, on the floor,
|
||||
or hanging from the ceiling).
|
||||
* `infinitestacks`: if `true`, the itemstack is not changed. Otherwise the
|
||||
stacks are handled normally.
|
||||
* `orient_flags`: 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.
|
||||
* `force_facedir`: if `true`, forcefully reset the facedir to north when placing on
|
||||
the floor or ceiling
|
||||
* The first four options are mutually-exclusive; the last in the list takes
|
||||
precedence over the first.
|
||||
* `force_facedir`: if `true`, forcefully reset the facedir to north
|
||||
when placing on the floor or ceiling.
|
||||
* The first four options are mutually-exclusive; the last in the list
|
||||
takes precedence over the first.
|
||||
* `prevent_after_place` is directly passed to `minetest.item_place_node`
|
||||
* Returns the new itemstack after placement
|
||||
* `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.
|
||||
* calls `rotate_and_place()` with `infinitestacks` set according to the state
|
||||
of the creative mode setting, checks for "sneak" to set the `invert_wall`
|
||||
parameter and `prevent_after_place` set to `true`.
|
||||
|
||||
* `minetest.forceload_block(pos[, transient])`
|
||||
* forceloads the position `pos`.
|
||||
@ -3150,7 +3280,7 @@ This is basically a reference to a C++ `ServerActiveObject`
|
||||
* `set_attach(parent, bone, position, rotation)`
|
||||
* `bone`: string
|
||||
* `position`: `{x=num, y=num, z=num}` (relative)
|
||||
* `rotation`: `{x=num, y=num, z=num}`
|
||||
* `rotation`: `{x=num, y=num, z=num}` = Rotation on each axis, in degrees
|
||||
* `get_attach()`: returns parent, bone, position, rotation or nil if it isn't attached
|
||||
* `set_detach()`
|
||||
* `set_bone_position(bone, position, rotation)`
|
||||
@ -3218,7 +3348,7 @@ This is basically a reference to a C++ `ServerActiveObject`
|
||||
* `11`: bubbles bar is not shown
|
||||
* `set_attribute(attribute, value)`:
|
||||
* Sets an extra attribute with value on player.
|
||||
* `value` must be a string.
|
||||
* `value` must be a string, or a number which will be converted to a string.
|
||||
* If `value` is `nil`, remove attribute from player.
|
||||
* `get_attribute(attribute)`:
|
||||
* Returns value (a string) for extra attribute.
|
||||
@ -3322,8 +3452,9 @@ An `InvRef` is a reference to an inventory.
|
||||
* `add_item(listname, stack)`: add item somewhere in list, returns leftover `ItemStack`
|
||||
* `room_for_item(listname, stack):` returns `true` if the stack of items
|
||||
can be fully added to the list
|
||||
* `contains_item(listname, stack)`: returns `true` if the stack of items
|
||||
can be fully taken from the list
|
||||
* `contains_item(listname, stack, [match_meta])`: returns `true` if
|
||||
the stack of items can be fully taken from the list.
|
||||
If `match_meta` is false, only the items' names are compared (default: `false`).
|
||||
* `remove_item(listname, stack)`: take as many items as specified from the list,
|
||||
returns the items that were actually removed (as an `ItemStack`) -- note that
|
||||
any item metadata is ignored, so attempting to remove a specific unique
|
||||
@ -4212,6 +4343,7 @@ Definition tables
|
||||
{
|
||||
items = {"foo:bar", "baz:frob"}, -- Items to drop.
|
||||
rarity = 1, -- Probability of dropping is 1 / rarity.
|
||||
inherit_color = true, -- To inherit palette color from the node
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -4242,6 +4374,7 @@ Definition tables
|
||||
^ Called after constructing node when node was placed using
|
||||
minetest.item_place_node / minetest.place_node
|
||||
^ If return true no item is taken from itemstack
|
||||
^ `placer` may be any valid ObjectRef or nil
|
||||
^ default: nil ]]
|
||||
after_dig_node = func(pos, oldnode, oldmetadata, digger), --[[
|
||||
^ oldmetadata is in table format
|
||||
@ -4257,9 +4390,11 @@ Definition tables
|
||||
^ By default: Calls minetest.register_on_punchnode callbacks ]]
|
||||
on_rightclick = func(pos, node, clicker, itemstack, pointed_thing), --[[
|
||||
^ default: nil
|
||||
^ if defined, itemstack will hold clicker's wielded item
|
||||
^ itemstack will hold clicker's wielded item
|
||||
^ Shall return the leftover itemstack
|
||||
^ Note: pointed_thing can be nil, if a mod calls this function ]]
|
||||
^ Note: pointed_thing can be nil, if a mod calls this function
|
||||
This function does not get triggered by clients <=0.4.16 if the
|
||||
"formspec" node metadata field is set ]]
|
||||
|
||||
on_dig = func(pos, node, digger), --[[
|
||||
^ default: minetest.node_dig
|
||||
@ -4674,3 +4809,26 @@ The Biome API is still in an experimental phase and subject to change.
|
||||
-- ^ HTTP status code
|
||||
data = "response"
|
||||
}
|
||||
|
||||
### Authentication handler definition
|
||||
|
||||
{
|
||||
get_auth = func(name),
|
||||
-- ^ Get authentication data for existing player `name` (`nil` if player doesn't exist)
|
||||
-- ^ returns following structure `{password=<string>, privileges=<table>, last_login=<number or nil>}`
|
||||
create_auth = func(name, password),
|
||||
-- ^ Create new auth data for player `name`
|
||||
-- ^ Note that `password` is not plain-text but an arbitrary representation decided by the engine
|
||||
set_password = func(name, password),
|
||||
-- ^ Set password of player `name` to `password`
|
||||
Auth data should be created if not present
|
||||
set_privileges = func(name, privileges),
|
||||
-- ^ Set privileges of player `name`
|
||||
-- ^ `privileges` is in table form, auth data should be created if not present
|
||||
reload = func(),
|
||||
-- ^ Reload authentication data from the storage location
|
||||
-- ^ Returns boolean indicating success
|
||||
record_login = func(name),
|
||||
-- ^ Called when player joins, used for keeping track of last_login
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
Minetest Lua Mainmenu API Reference 0.4.16
|
||||
Minetest Lua Mainmenu API Reference 0.4.17
|
||||
========================================
|
||||
|
||||
Introduction
|
||||
|
@ -1270,7 +1270,9 @@ minetest.register_node("default:chest_locked", {
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
after_place_node = function(pos, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("owner", placer:get_player_name() or "")
|
||||
local pname =
|
||||
placer and placer:get_player_name() or ""
|
||||
meta:set_string("owner", pname)
|
||||
meta:set_string("infotext", "Locked Chest (owned by "..
|
||||
meta:get_string("owner")..")")
|
||||
end,
|
||||
|
@ -161,11 +161,6 @@
|
||||
# type: key
|
||||
# keymap_cmd_local = .
|
||||
|
||||
# Key for opening the chat console.
|
||||
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
|
||||
# type: key
|
||||
# keyman_console = KEY_F10
|
||||
|
||||
# Key for toggling unlimited view range.
|
||||
# See http://irrlicht.sourceforge.net/docu/namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3
|
||||
# type: key
|
||||
@ -344,8 +339,8 @@
|
||||
# serverlist_file = favoriteservers.txt
|
||||
|
||||
# Maximum size of the out chat queue. 0 to disable queueing and -1 to make the queue size unlimited
|
||||
# type: int min: -1
|
||||
max_out_chat_queue_size = 20
|
||||
# type: int
|
||||
# max_out_chat_queue_size = 20
|
||||
|
||||
## Graphics
|
||||
|
||||
@ -555,7 +550,7 @@ max_out_chat_queue_size = 20
|
||||
# type: int
|
||||
# screenH = 600
|
||||
|
||||
# Save the window size automatically when modified.
|
||||
# Save window size automatically when modified.
|
||||
# type: bool
|
||||
# autosave_screensize = true
|
||||
|
||||
@ -867,11 +862,10 @@ max_out_chat_queue_size = 20
|
||||
# type: string
|
||||
# serverlist_url = servers.minetest.net
|
||||
|
||||
# Disable escape sequences, e.g. chat coloring.
|
||||
# Use this if you want to run a server with pre-0.4.14 clients and you want to disable
|
||||
# the escape sequences generated by mods.
|
||||
# Remove color codes from incoming chat messages
|
||||
# Use this to stop players from being able to use color in their messages
|
||||
# type: bool
|
||||
# disable_escape_sequences = false
|
||||
# strip_color_codes = false
|
||||
|
||||
## Network
|
||||
|
||||
@ -1841,3 +1835,4 @@ max_out_chat_queue_size = 20
|
||||
# Print the engine's profiling data in regular intervals (in seconds). 0 = disable. Useful for developers.
|
||||
# type: int
|
||||
# profiler_print_interval = 0
|
||||
|
||||
|
@ -268,7 +268,7 @@ if(WIN32)
|
||||
else() # Probably MinGW = GCC
|
||||
set(PLATFORM_LIBS "")
|
||||
endif()
|
||||
set(PLATFORM_LIBS ws2_32.lib shlwapi.lib ${PLATFORM_LIBS})
|
||||
set(PLATFORM_LIBS ws2_32.lib version.lib shlwapi.lib ${PLATFORM_LIBS})
|
||||
|
||||
# Zlib stuff
|
||||
set(ZLIB_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/../../zlib/zlib-1.2.5"
|
||||
@ -325,10 +325,12 @@ else()
|
||||
endif(HAVE_LIBRT)
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT APPLE)
|
||||
# This way Xxf86vm is found on OpenBSD too
|
||||
find_library(XXF86VM_LIBRARY Xxf86vm)
|
||||
mark_as_advanced(XXF86VM_LIBRARY)
|
||||
set(CLIENT_PLATFORM_LIBS ${CLIENT_PLATFORM_LIBS} ${XXF86VM_LIBRARY})
|
||||
find_library(XXF86VM_LIBRARY Xxf86vm)
|
||||
mark_as_advanced(XXF86VM_LIBRARY)
|
||||
set(CLIENT_PLATFORM_LIBS ${CLIENT_PLATFORM_LIBS} ${XXF86VM_LIBRARY})
|
||||
endif(NOT APPLE)
|
||||
|
||||
# Prefer local iconv if installed
|
||||
find_library(ICONV_LIBRARY iconv)
|
||||
|
@ -386,8 +386,9 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
|
||||
// *100.0 helps in large map coordinates
|
||||
m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction);
|
||||
|
||||
// update the camera position in front-view mode to render blocks behind player
|
||||
if (m_camera_mode == CAMERA_MODE_THIRD_FRONT)
|
||||
// update the camera position in third-person mode to render blocks behind player
|
||||
// and correctly apply liquid post FX.
|
||||
if (m_camera_mode != CAMERA_MODE_FIRST)
|
||||
m_camera_position = my_cp;
|
||||
|
||||
// Get FOV
|
||||
@ -487,7 +488,9 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
|
||||
void Camera::updateViewingRange()
|
||||
{
|
||||
f32 viewing_range = g_settings->getFloat("viewing_range");
|
||||
f32 near_plane = g_settings->getFloat("near_plane");
|
||||
m_draw_control.wanted_range = viewing_range;
|
||||
m_cameranode->setNearValue(rangelim(near_plane, 0.0f, 0.5f) * BS);
|
||||
if (m_draw_control.range_all) {
|
||||
m_cameranode->setFarValue(100000.0);
|
||||
return;
|
||||
|
@ -332,7 +332,7 @@ void CavesRandomWalk::makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax,
|
||||
|
||||
route_y_min = 0;
|
||||
// Allow half a diameter + 7 over stone surface
|
||||
route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
|
||||
route_y_max = -of.Y + max_stone_height + max_tunnel_diameter / 2 + 7;
|
||||
|
||||
// Limit maximum to area
|
||||
route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
|
||||
|
@ -134,7 +134,6 @@ public:
|
||||
bool large_cave_is_flat;
|
||||
bool flooded;
|
||||
|
||||
s16 max_stone_y;
|
||||
v3s16 node_min;
|
||||
v3s16 node_max;
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
#ifndef __IRR_USTRING_H_INCLUDED__
|
||||
#define __IRR_USTRING_H_INCLUDED__
|
||||
|
||||
#if (__cplusplus > 199711L) || (_MSC_VER >= 1600) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1600) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define USTRING_CPP0X
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)))
|
||||
# define USTRING_CPP0X_NEWLITERALS
|
||||
|
@ -73,7 +73,6 @@ Client::Client(
|
||||
m_connection_reinit_timer(0.1),
|
||||
m_avg_rtt_timer(0.0),
|
||||
m_playerpos_send_timer(0.0),
|
||||
m_ignore_damage_timer(0.0),
|
||||
m_tsrc(tsrc),
|
||||
m_shsrc(shsrc),
|
||||
m_itemdef(itemdef),
|
||||
@ -231,6 +230,8 @@ Client::~Client()
|
||||
m_shutdown = true;
|
||||
m_con.Disconnect();
|
||||
|
||||
deleteAuthData();
|
||||
|
||||
m_mesh_update_thread.stop();
|
||||
m_mesh_update_thread.wait();
|
||||
while (!m_mesh_update_thread.m_queue_out.empty()) {
|
||||
@ -258,6 +259,7 @@ Client::~Client()
|
||||
}
|
||||
|
||||
delete m_minimap;
|
||||
delete m_media_downloader;
|
||||
}
|
||||
|
||||
void Client::connect(Address address, bool is_local_server)
|
||||
@ -275,14 +277,9 @@ void Client::step(float dtime)
|
||||
DSTACK(FUNCTION_NAME);
|
||||
|
||||
// Limit a bit
|
||||
if(dtime > 2.0)
|
||||
if (dtime > 2.0)
|
||||
dtime = 2.0;
|
||||
|
||||
if(m_ignore_damage_timer > dtime)
|
||||
m_ignore_damage_timer -= dtime;
|
||||
else
|
||||
m_ignore_damage_timer = 0.0;
|
||||
|
||||
m_animation_time += dtime;
|
||||
if(m_animation_time > 60.0)
|
||||
m_animation_time -= 60.0;
|
||||
@ -429,18 +426,16 @@ void Client::step(float dtime)
|
||||
ClientEnvEvent envEvent = m_env.getClientEnvEvent();
|
||||
|
||||
if (envEvent.type == CEE_PLAYER_DAMAGE) {
|
||||
if (m_ignore_damage_timer <= 0) {
|
||||
u8 damage = envEvent.player_damage.amount;
|
||||
u8 damage = envEvent.player_damage.amount;
|
||||
|
||||
if (envEvent.player_damage.send_to_server)
|
||||
sendDamage(damage);
|
||||
if (envEvent.player_damage.send_to_server)
|
||||
sendDamage(damage);
|
||||
|
||||
// Add to ClientEvent queue
|
||||
ClientEvent event;
|
||||
event.type = CE_PLAYER_DAMAGE;
|
||||
event.player_damage.amount = damage;
|
||||
m_client_event_queue.push(event);
|
||||
}
|
||||
// Add to ClientEvent queue
|
||||
ClientEvent event;
|
||||
event.type = CE_PLAYER_DAMAGE;
|
||||
event.player_damage.amount = damage;
|
||||
m_client_event_queue.push(event);
|
||||
}
|
||||
// Protocol v29 or greater obsoleted this event
|
||||
else if (envEvent.type == CEE_PLAYER_BREATH && m_proto_ver < 29) {
|
||||
|
@ -574,7 +574,6 @@ private:
|
||||
float m_connection_reinit_timer;
|
||||
float m_avg_rtt_timer;
|
||||
float m_playerpos_send_timer;
|
||||
float m_ignore_damage_timer; // Used after server moves player
|
||||
IntervalLimiter m_map_timer_and_unload_interval;
|
||||
|
||||
IWritableTextureSource *m_tsrc;
|
||||
|
@ -60,6 +60,8 @@ struct JoystickButtonCmb : public JoystickCombination {
|
||||
this->key = key;
|
||||
}
|
||||
|
||||
virtual ~JoystickButtonCmb() {}
|
||||
|
||||
virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const;
|
||||
|
||||
u32 filter_mask;
|
||||
@ -77,6 +79,8 @@ struct JoystickAxisCmb : public JoystickCombination {
|
||||
this->key = key;
|
||||
}
|
||||
|
||||
virtual ~JoystickAxisCmb() {}
|
||||
|
||||
virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const;
|
||||
|
||||
u16 axis_to_compare;
|
||||
|
@ -1138,13 +1138,14 @@ video::IImage * Align2Npot2(video::IImage * image,
|
||||
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
|
||||
std::string extensions = (char*) glGetString(GL_EXTENSIONS);
|
||||
|
||||
// Only GLES2 is trusted to correctly report npot support
|
||||
if (get_GL_major_version() > 1 &&
|
||||
extensions.find("GL_OES_texture_npot") != std::string::npos) {
|
||||
// Note: we cache the boolean result. GL context will never change on Android.
|
||||
static const bool hasNPotSupport = get_GL_major_version() > 1 &&
|
||||
glGetString(GL_EXTENSIONS) &&
|
||||
strstr(glGetString(GL_EXTENSIONS), "GL_OES_texture_npot");
|
||||
|
||||
if (hasNPotSupport)
|
||||
return image;
|
||||
}
|
||||
|
||||
unsigned int height = npot2(dim.Height);
|
||||
unsigned int width = npot2(dim.Width);
|
||||
@ -1805,7 +1806,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
* mix high- and low-res textures, or for mods with least-common-denominator
|
||||
* textures that don't have the resources to offer high-res alternatives.
|
||||
*/
|
||||
s32 scaleto = g_settings->getS32("texture_min_size");
|
||||
const bool filter = m_setting_trilinear_filter || m_setting_bilinear_filter;
|
||||
const s32 scaleto = filter ? g_settings->getS32("texture_min_size") : 1;
|
||||
if (scaleto > 1) {
|
||||
const core::dimension2d<u32> dim = baseimg->getDimension();
|
||||
|
||||
|
@ -159,7 +159,8 @@ enum MaterialType{
|
||||
TILE_MATERIAL_LIQUID_TRANSPARENT,
|
||||
TILE_MATERIAL_LIQUID_OPAQUE,
|
||||
TILE_MATERIAL_WAVING_LEAVES,
|
||||
TILE_MATERIAL_WAVING_PLANTS
|
||||
TILE_MATERIAL_WAVING_PLANTS,
|
||||
TILE_MATERIAL_OPAQUE
|
||||
};
|
||||
|
||||
// Material flags
|
||||
@ -243,18 +244,20 @@ struct TileLayer
|
||||
void applyMaterialOptions(video::SMaterial &material) const
|
||||
{
|
||||
switch (material_type) {
|
||||
case TILE_MATERIAL_OPAQUE:
|
||||
case TILE_MATERIAL_LIQUID_OPAQUE:
|
||||
material.MaterialType = video::EMT_SOLID;
|
||||
break;
|
||||
case TILE_MATERIAL_BASIC:
|
||||
case TILE_MATERIAL_WAVING_LEAVES:
|
||||
case TILE_MATERIAL_WAVING_PLANTS:
|
||||
material.MaterialTypeParam = 0.5;
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
break;
|
||||
case TILE_MATERIAL_ALPHA:
|
||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
break;
|
||||
case TILE_MATERIAL_LIQUID_OPAQUE:
|
||||
material.MaterialType = video::EMT_SOLID;
|
||||
break;
|
||||
}
|
||||
material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING)
|
||||
? true : false;
|
||||
|
@ -633,6 +633,16 @@ std::vector<u16> ClientInterface::getClientIDs(ClientState min_state)
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if user limit was reached.
|
||||
* User limit count all clients from HelloSent state (MT protocol user) to Active state
|
||||
* @return true if user limit was reached
|
||||
*/
|
||||
bool ClientInterface::isUserLimitReached()
|
||||
{
|
||||
return getClientIDs(CS_HelloSent).size() >= g_settings->getU16("max_users");
|
||||
}
|
||||
|
||||
void ClientInterface::step(float dtime)
|
||||
{
|
||||
m_print_info_timer += dtime;
|
||||
|
@ -449,6 +449,9 @@ public:
|
||||
/* get list of active client id's */
|
||||
std::vector<u16> getClientIDs(ClientState min_state=CS_Active);
|
||||
|
||||
/* verify is server user limit was reached */
|
||||
bool isUserLimitReached();
|
||||
|
||||
/* get list of client player names */
|
||||
const std::vector<std::string> &getPlayerNames() const { return m_clients_names; }
|
||||
|
||||
@ -493,7 +496,6 @@ public:
|
||||
}
|
||||
|
||||
static std::string state2Name(ClientState state);
|
||||
|
||||
protected:
|
||||
//TODO find way to avoid this functions
|
||||
void lock() { m_clients_mutex.lock(); }
|
||||
|
@ -290,49 +290,46 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
|
||||
|
||||
struct MeshBufList
|
||||
{
|
||||
/*!
|
||||
* Specifies in which layer the list is.
|
||||
* All lists which are in a lower layer are rendered before this list.
|
||||
*/
|
||||
u8 layer;
|
||||
video::SMaterial m;
|
||||
std::vector<scene::IMeshBuffer*> bufs;
|
||||
};
|
||||
|
||||
struct MeshBufListList
|
||||
{
|
||||
std::vector<MeshBufList> lists;
|
||||
/*!
|
||||
* Stores the mesh buffers of the world.
|
||||
* The array index is the material's layer.
|
||||
* The vector part groups vertices by material.
|
||||
*/
|
||||
std::vector<MeshBufList> lists[MAX_TILE_LAYERS];
|
||||
|
||||
void clear()
|
||||
{
|
||||
lists.clear();
|
||||
for (int l = 0; l < MAX_TILE_LAYERS; l++)
|
||||
lists[l].clear();
|
||||
}
|
||||
|
||||
void add(scene::IMeshBuffer *buf, u8 layer)
|
||||
{
|
||||
// Append to the correct layer
|
||||
std::vector<MeshBufList> &list = lists[layer];
|
||||
const video::SMaterial &m = buf->getMaterial();
|
||||
for(std::vector<MeshBufList>::iterator i = lists.begin();
|
||||
i != lists.end(); ++i){
|
||||
MeshBufList &l = *i;
|
||||
|
||||
for (std::vector<MeshBufList>::iterator it = list.begin(); it != list.end();
|
||||
++it) {
|
||||
// comparing a full material is quite expensive so we don't do it if
|
||||
// not even first texture is equal
|
||||
if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
|
||||
if ((*it).m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
|
||||
continue;
|
||||
|
||||
if(l.layer != layer)
|
||||
continue;
|
||||
|
||||
if (l.m == m) {
|
||||
l.bufs.push_back(buf);
|
||||
if ((*it).m == m) {
|
||||
(*it).bufs.push_back(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
MeshBufList l;
|
||||
l.layer = layer;
|
||||
l.m = m;
|
||||
l.bufs.push_back(buf);
|
||||
lists.push_back(l);
|
||||
list.push_back(l);
|
||||
}
|
||||
};
|
||||
|
||||
@ -360,7 +357,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
Measuring time is very useful for long delays when the
|
||||
machine is swapping a lot.
|
||||
*/
|
||||
int time1 = time(0);
|
||||
time_t time1 = time(0);
|
||||
|
||||
/*
|
||||
Get animation parameters
|
||||
@ -476,35 +473,34 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<MeshBufList> &lists = drawbufs.lists;
|
||||
// Render all layers in order
|
||||
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
|
||||
std::vector<MeshBufList> &lists = drawbufs.lists[layer];
|
||||
|
||||
int timecheck_counter = 0;
|
||||
for (std::vector<MeshBufList>::iterator i = lists.begin();
|
||||
i != lists.end(); ++i) {
|
||||
timecheck_counter++;
|
||||
if (timecheck_counter > 50) {
|
||||
timecheck_counter = 0;
|
||||
int time2 = time(0);
|
||||
if (time2 > time1 + 4) {
|
||||
infostream << "ClientMap::renderMap(): "
|
||||
"Rendering takes ages, returning."
|
||||
<< std::endl;
|
||||
return;
|
||||
int timecheck_counter = 0;
|
||||
for (std::vector<MeshBufList>::iterator it = lists.begin(); it != lists.end();
|
||||
++it) {
|
||||
timecheck_counter++;
|
||||
if (timecheck_counter > 50) {
|
||||
timecheck_counter = 0;
|
||||
time_t time2 = time(0);
|
||||
if (time2 > time1 + 4) {
|
||||
infostream << "ClientMap::renderMap(): "
|
||||
"Rendering takes ages, returning."
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
driver->setMaterial((*it).m);
|
||||
|
||||
for (std::vector<scene::IMeshBuffer*>::iterator it2 = (*it).bufs.begin();
|
||||
it2 != (*it).bufs.end(); ++it2) {
|
||||
driver->drawMeshBuffer(*it2);
|
||||
vertex_count += (*it2)->getVertexCount();
|
||||
meshbuffer_count++;
|
||||
}
|
||||
}
|
||||
|
||||
MeshBufList &list = *i;
|
||||
|
||||
driver->setMaterial(list.m);
|
||||
|
||||
for (std::vector<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
|
||||
j != list.bufs.end(); ++j) {
|
||||
scene::IMeshBuffer *buf = *j;
|
||||
driver->drawMeshBuffer(buf);
|
||||
vertex_count += buf->getVertexCount();
|
||||
meshbuffer_count++;
|
||||
}
|
||||
|
||||
}
|
||||
} // ScopeProfiler
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define VERSION_MAJOR @VERSION_MAJOR@
|
||||
#define VERSION_MINOR @VERSION_MINOR@
|
||||
#define VERSION_PATCH @VERSION_PATCH@
|
||||
#define VERSION_TWEAK @VERSION_TWEAK@
|
||||
#define VERSION_EXTRA "@VERSION_EXTRA@"
|
||||
#define VERSION_STRING "@VERSION_STRING@"
|
||||
#define PRODUCT_VERSION_STRING "@VERSION_MAJOR@.@VERSION_MINOR@"
|
||||
|
@ -258,27 +258,32 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||
//TimeTaker tt2("collisionMoveSimple collect boxes");
|
||||
ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);
|
||||
|
||||
v3s16 oldpos_i = floatToInt(*pos_f, BS);
|
||||
v3s16 newpos_i = floatToInt(*pos_f + *speed_f * dtime, BS);
|
||||
s16 min_x = MYMIN(oldpos_i.X, newpos_i.X) + (box_0.MinEdge.X / BS) - 1;
|
||||
s16 min_y = MYMIN(oldpos_i.Y, newpos_i.Y) + (box_0.MinEdge.Y / BS) - 1;
|
||||
s16 min_z = MYMIN(oldpos_i.Z, newpos_i.Z) + (box_0.MinEdge.Z / BS) - 1;
|
||||
s16 max_x = MYMAX(oldpos_i.X, newpos_i.X) + (box_0.MaxEdge.X / BS) + 1;
|
||||
s16 max_y = MYMAX(oldpos_i.Y, newpos_i.Y) + (box_0.MaxEdge.Y / BS) + 1;
|
||||
s16 max_z = MYMAX(oldpos_i.Z, newpos_i.Z) + (box_0.MaxEdge.Z / BS) + 1;
|
||||
v3f newpos_f = *pos_f + *speed_f * dtime;
|
||||
v3f minpos_f(
|
||||
MYMIN(pos_f->X, newpos_f.X),
|
||||
MYMIN(pos_f->Y, newpos_f.Y) + 0.01 * BS, // bias rounding, player often at +/-n.5
|
||||
MYMIN(pos_f->Z, newpos_f.Z)
|
||||
);
|
||||
v3f maxpos_f(
|
||||
MYMAX(pos_f->X, newpos_f.X),
|
||||
MYMAX(pos_f->Y, newpos_f.Y),
|
||||
MYMAX(pos_f->Z, newpos_f.Z)
|
||||
);
|
||||
v3s16 min = floatToInt(minpos_f + box_0.MinEdge, BS) - v3s16(1, 1, 1);
|
||||
v3s16 max = floatToInt(maxpos_f + box_0.MaxEdge, BS) + v3s16(1, 1, 1);
|
||||
|
||||
bool any_position_valid = false;
|
||||
|
||||
for(s16 x = min_x; x <= max_x; x++)
|
||||
for(s16 y = min_y; y <= max_y; y++)
|
||||
for(s16 z = min_z; z <= max_z; z++)
|
||||
for(s16 x = min.X; x <= max.X; x++)
|
||||
for(s16 y = min.Y; y <= max.Y; y++)
|
||||
for(s16 z = min.Z; z <= max.Z; z++)
|
||||
{
|
||||
v3s16 p(x,y,z);
|
||||
|
||||
bool is_position_valid;
|
||||
MapNode n = map->getNodeNoEx(p, &is_position_valid);
|
||||
|
||||
if (is_position_valid) {
|
||||
if (is_position_valid && n.getContent() != CONTENT_IGNORE) {
|
||||
// Object collides into walkable nodes
|
||||
|
||||
any_position_valid = true;
|
||||
@ -328,7 +333,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||
false, n_bouncy_value, p, box));
|
||||
}
|
||||
} else {
|
||||
// Collide with unloaded nodes
|
||||
// Collide with unloaded nodes (position invalid) and loaded
|
||||
// CONTENT_IGNORE nodes (position valid)
|
||||
aabb3f box = getNodeBox(p, BS);
|
||||
cinfo.push_back(NearbyCollisionInfo(true, false, 0, p, box));
|
||||
}
|
||||
@ -336,6 +342,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
|
||||
|
||||
// Do not move if world has not loaded yet, since custom node boxes
|
||||
// are not available for collision detection.
|
||||
// This also intentionally occurs in the case of the object being positioned
|
||||
// solely on loaded CONTENT_IGNORE nodes, no matter where they come from.
|
||||
if (!any_position_valid) {
|
||||
*speed_f = v3f(0, 0, 0);
|
||||
return result;
|
||||
|
@ -1184,16 +1184,17 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
|
||||
|
||||
float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
|
||||
m_step_distance_counter += moved;
|
||||
if(m_step_distance_counter > 1.5*BS)
|
||||
{
|
||||
m_step_distance_counter = 0;
|
||||
if(!m_is_local_player && m_prop.makes_footstep_sound)
|
||||
{
|
||||
if (m_step_distance_counter > 1.5f * BS) {
|
||||
m_step_distance_counter = 0.0f;
|
||||
if (!m_is_local_player && m_prop.makes_footstep_sound) {
|
||||
INodeDefManager *ndef = m_client->ndef();
|
||||
v3s16 p = floatToInt(getPosition() + v3f(0,
|
||||
(m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
|
||||
v3s16 p = floatToInt(getPosition() +
|
||||
v3f(0.0f, (m_prop.collisionbox.MinEdge.Y - 0.5f) * BS, 0.0f), BS);
|
||||
MapNode n = m_env->getMap().getNodeNoEx(p);
|
||||
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
|
||||
// Reduce footstep gain, as non-local-player footsteps are
|
||||
// somehow louder.
|
||||
spec.gain *= 0.6f;
|
||||
m_client->sound()->playSoundAt(spec, false, getPosition());
|
||||
}
|
||||
}
|
||||
@ -1354,6 +1355,13 @@ void GenericCAO::updateTextures(std::string mod)
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
|
||||
// don't filter low-res textures, makes them look blurry
|
||||
// player models have a res of 64
|
||||
const core::dimension2d<u32> &size = texture->getOriginalSize();
|
||||
const u32 res = std::min(size.Height, size.Width);
|
||||
use_trilinear_filter &= res > 64;
|
||||
use_bilinear_filter &= res > 64;
|
||||
|
||||
m_animated_meshnode->getMaterial(i)
|
||||
.setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||
m_animated_meshnode->getMaterial(i)
|
||||
|
@ -43,7 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// Corresponding offsets are listed in g_27dirs
|
||||
#define FRAMED_NEIGHBOR_COUNT 18
|
||||
|
||||
static constexpr v3s16 light_dirs[8] = {
|
||||
static const v3s16 light_dirs[8] = {
|
||||
v3s16(-1, -1, -1),
|
||||
v3s16(-1, -1, 1),
|
||||
v3s16(-1, 1, -1),
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
m_age += dtime;
|
||||
if(m_age > 10)
|
||||
{
|
||||
m_removed = true;
|
||||
m_pending_removal = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -406,20 +406,6 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||
m_env->getScriptIface()->luaentity_Step(m_id, dtime);
|
||||
}
|
||||
|
||||
// Remove LuaEntity beyond terrain edges
|
||||
{
|
||||
ServerMap *map = dynamic_cast<ServerMap *>(&m_env->getMap());
|
||||
assert(map);
|
||||
if (!m_pending_deactivation &&
|
||||
map->saoPositionOverLimit(m_base_position)) {
|
||||
infostream << "Remove SAO " << m_id << "(" << m_init_name
|
||||
<< "), outside of limits" << std::endl;
|
||||
m_pending_deactivation = true;
|
||||
m_removed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(send_recommended == false)
|
||||
return;
|
||||
|
||||
@ -555,9 +541,9 @@ int LuaEntitySAO::punch(v3f dir,
|
||||
ServerActiveObject *puncher,
|
||||
float time_from_last_punch)
|
||||
{
|
||||
if (!m_registered){
|
||||
if (!m_registered) {
|
||||
// Delete unknown LuaEntities when punched
|
||||
m_removed = true;
|
||||
m_pending_removal = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -601,7 +587,7 @@ int LuaEntitySAO::punch(v3f dir,
|
||||
}
|
||||
|
||||
if (getHP() == 0)
|
||||
m_removed = true;
|
||||
m_pending_removal = true;
|
||||
|
||||
|
||||
|
||||
@ -1361,11 +1347,10 @@ void PlayerSAO::setWieldIndex(int i)
|
||||
}
|
||||
}
|
||||
|
||||
// Erase the peer id and make the object for removal
|
||||
void PlayerSAO::disconnected()
|
||||
{
|
||||
m_peer_id = 0;
|
||||
m_removed = true;
|
||||
m_pending_removal = true;
|
||||
}
|
||||
|
||||
void PlayerSAO::unlinkPlayerSessionAndSave()
|
||||
@ -1402,26 +1387,38 @@ bool PlayerSAO::checkMovementCheat()
|
||||
too, and much more lightweight.
|
||||
*/
|
||||
|
||||
float player_max_speed = 0;
|
||||
float player_max_walk = 0; // horizontal movement
|
||||
float player_max_jump = 0; // vertical upwards movement
|
||||
|
||||
if (m_privs.count("fast") != 0) {
|
||||
// Fast speed
|
||||
player_max_speed = m_player->movement_speed_fast * m_physics_override_speed;
|
||||
} else {
|
||||
// Normal speed
|
||||
player_max_speed = m_player->movement_speed_walk * m_physics_override_speed;
|
||||
}
|
||||
// Tolerance. The lag pool does this a bit.
|
||||
//player_max_speed *= 2.5;
|
||||
if (m_privs.count("fast") != 0)
|
||||
player_max_walk = m_player->movement_speed_fast; // Fast speed
|
||||
else
|
||||
player_max_walk = m_player->movement_speed_walk; // Normal speed
|
||||
player_max_walk *= m_physics_override_speed;
|
||||
player_max_jump = m_player->movement_speed_jump * m_physics_override_jump;
|
||||
// FIXME: Bouncy nodes cause practically unbound increase in Y speed,
|
||||
// until this can be verified correctly, tolerate higher jumping speeds
|
||||
player_max_jump *= 2.0;
|
||||
|
||||
// Don't divide by zero!
|
||||
if (player_max_walk < 0.0001f)
|
||||
player_max_walk = 0.0001f;
|
||||
if (player_max_jump < 0.0001f)
|
||||
player_max_jump = 0.0001f;
|
||||
|
||||
v3f diff = (m_base_position - m_last_good_position);
|
||||
float d_vert = diff.Y;
|
||||
diff.Y = 0;
|
||||
float d_horiz = diff.getLength();
|
||||
float required_time = d_horiz / player_max_speed;
|
||||
float required_time = d_horiz / player_max_walk;
|
||||
|
||||
if (d_vert > 0 && d_vert / player_max_speed > required_time)
|
||||
required_time = d_vert / player_max_speed; // Moving upwards
|
||||
// FIXME: Checking downwards movement is not easily possible currently,
|
||||
// the server could calculate speed differences to examine the gravity
|
||||
if (d_vert > 0) {
|
||||
// In certain cases (water, ladders) walking speed is applied vertically
|
||||
float s = MYMAX(player_max_jump, player_max_walk);
|
||||
required_time = MYMAX(required_time, d_vert / s);
|
||||
}
|
||||
|
||||
if (m_move_pool.grab(required_time)) {
|
||||
m_last_good_position = m_base_position;
|
||||
|
@ -923,8 +923,19 @@ public:
|
||||
<< " against " << def->dump() << std::endl;*/
|
||||
|
||||
if (def->check(input, gamedef)) {
|
||||
// Check if the crafted node/item exists
|
||||
CraftOutput out = def->getOutput(input, gamedef);
|
||||
ItemStack is;
|
||||
is.deSerialize(out.item, gamedef->idef());
|
||||
if (!is.isKnown(gamedef->idef())) {
|
||||
infostream << "trying to craft non-existent "
|
||||
<< out.item << ", ignoring recipe" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get output, then decrement input (if requested)
|
||||
output = def->getOutput(input, gamedef);
|
||||
output = out;
|
||||
|
||||
if (decrementInput)
|
||||
def->decrementInput(input, output_replacement, gamedef);
|
||||
/*errorstream << "Check RETURNS TRUE" << std::endl;*/
|
||||
|
@ -125,6 +125,7 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("fps_max", "60");
|
||||
settings->setDefault("pause_fps_max", "20");
|
||||
settings->setDefault("viewing_range", "100");
|
||||
settings->setDefault("near_plane", "0.1");
|
||||
settings->setDefault("screenW", "800");
|
||||
settings->setDefault("screenH", "600");
|
||||
settings->setDefault("autosave_screensize", "true");
|
||||
@ -252,6 +253,7 @@ void set_default_settings(Settings *settings)
|
||||
|
||||
// Server
|
||||
settings->setDefault("disable_escape_sequences", "false");
|
||||
settings->setDefault("strip_color_codes", "false");
|
||||
|
||||
// Network
|
||||
settings->setDefault("enable_ipv6", "true");
|
||||
|
@ -431,8 +431,10 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
|
||||
VMANIP_FLAG_DUNGEON_UNTOUCHABLE,
|
||||
MapNode(dp.c_wall),
|
||||
0);
|
||||
makeHole(p);
|
||||
makeHole(p - dir);
|
||||
makeFill(p, dp.holesize, VMANIP_FLAG_DUNGEON_UNTOUCHABLE,
|
||||
MapNode(CONTENT_AIR), VMANIP_FLAG_DUNGEON_INSIDE);
|
||||
makeFill(p - dir, dp.holesize, VMANIP_FLAG_DUNGEON_UNTOUCHABLE,
|
||||
MapNode(CONTENT_AIR), VMANIP_FLAG_DUNGEON_INSIDE);
|
||||
|
||||
// TODO: fix stairs code so it works 100%
|
||||
// (quite difficult)
|
||||
@ -451,16 +453,21 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
|
||||
v3s16 swv = (dir.Z != 0) ? v3s16(1, 0, 0) : v3s16(0, 0, 1);
|
||||
|
||||
for (u16 st = 0; st < stair_width; st++) {
|
||||
u32 vi = vm->m_area.index(ps.X - dir.X, ps.Y - 1, ps.Z - dir.Z);
|
||||
if (vm->m_area.contains(ps + v3s16(-dir.X, -1, -dir.Z)) &&
|
||||
vm->m_data[vi].getContent() == dp.c_wall)
|
||||
vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
|
||||
|
||||
vi = vm->m_area.index(ps.X, ps.Y, ps.Z);
|
||||
if (vm->m_area.contains(ps) &&
|
||||
vm->m_data[vi].getContent() == dp.c_wall)
|
||||
vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
|
||||
|
||||
if (make_stairs == -1) {
|
||||
u32 vi = vm->m_area.index(ps.X - dir.X, ps.Y - 1, ps.Z - dir.Z);
|
||||
if (vm->m_area.contains(ps + v3s16(-dir.X, -1, -dir.Z)) &&
|
||||
vm->m_data[vi].getContent() == dp.c_wall) {
|
||||
vm->m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
|
||||
vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
|
||||
}
|
||||
} else if (make_stairs == 1) {
|
||||
u32 vi = vm->m_area.index(ps.X, ps.Y - 1, ps.Z);
|
||||
if (vm->m_area.contains(ps + v3s16(0, -1, 0)) &&
|
||||
vm->m_data[vi].getContent() == dp.c_wall) {
|
||||
vm->m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
|
||||
vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
|
||||
}
|
||||
}
|
||||
ps += swv;
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,10 @@ EmergeManager::~EmergeManager()
|
||||
}
|
||||
|
||||
delete thread;
|
||||
delete m_mapgens[i];
|
||||
|
||||
// Mapgen init might not be finished if there is an error during startup.
|
||||
if (m_mapgens.size() > i)
|
||||
delete m_mapgens[i];
|
||||
}
|
||||
|
||||
delete biomemgr;
|
||||
@ -570,6 +573,12 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata,
|
||||
m_server->setAsyncFatalError("Lua: finishGen" + std::string(e.what()));
|
||||
}
|
||||
|
||||
/*
|
||||
Clear generate notifier events
|
||||
*/
|
||||
Mapgen *mg = m_emerge->getCurrentMapgen();
|
||||
mg->gennotify.clearEvents();
|
||||
|
||||
EMERGE_DBG_OUT("ended up with: " << analyze_block(block));
|
||||
|
||||
/*
|
||||
|
@ -27,6 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "porting.h"
|
||||
#ifdef __ANDROID__
|
||||
#include "settings.h" // For g_settings
|
||||
#endif
|
||||
|
||||
namespace fs
|
||||
{
|
||||
@ -374,7 +377,7 @@ std::string TempPath()
|
||||
configuration hardcodes mkstemp("/tmp/lua_XXXXXX").
|
||||
*/
|
||||
#ifdef __ANDROID__
|
||||
return DIR_DELIM "sdcard" DIR_DELIM PROJECT_NAME DIR_DELIM "tmp";
|
||||
return g_settings->get("TMPFolder");
|
||||
#else
|
||||
return DIR_DELIM "tmp";
|
||||
#endif
|
||||
|
@ -341,32 +341,70 @@ void FontEngine::initFont(unsigned int basesize, FontMode mode)
|
||||
font_path.c_str(), size, true, true, font_shadow,
|
||||
font_shadow_alpha);
|
||||
|
||||
if (font != NULL) {
|
||||
if (font) {
|
||||
m_font_cache[mode][basesize] = font;
|
||||
return;
|
||||
}
|
||||
|
||||
// try fallback font
|
||||
errorstream << "FontEngine: failed to load: " << font_path << ", trying to fall back "
|
||||
"to fallback font" << std::endl;
|
||||
if (font_config_prefix == "mono_") {
|
||||
const std::string &mono_font_path = m_settings->getDefault("mono_font_path");
|
||||
|
||||
font_path = g_settings->get(font_config_prefix + "fallback_font_path");
|
||||
if (font_path != mono_font_path) {
|
||||
// try original mono font
|
||||
errorstream << "FontEngine: failed to load custom mono "
|
||||
"font: " << font_path << ", trying to fall back to "
|
||||
"original mono font" << std::endl;
|
||||
|
||||
font = gui::CGUITTFont::createTTFont(m_env,
|
||||
font_path.c_str(), size, true, true, font_shadow,
|
||||
font_shadow_alpha);
|
||||
font = gui::CGUITTFont::createTTFont(m_env,
|
||||
mono_font_path.c_str(), size, true, true,
|
||||
font_shadow, font_shadow_alpha);
|
||||
|
||||
if (font != NULL) {
|
||||
m_font_cache[mode][basesize] = font;
|
||||
return;
|
||||
if (font) {
|
||||
m_font_cache[mode][basesize] = font;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// try fallback font
|
||||
errorstream << "FontEngine: failed to load: " << font_path <<
|
||||
", trying to fall back to fallback font" << std::endl;
|
||||
|
||||
font_path = g_settings->get(font_config_prefix + "fallback_font_path");
|
||||
|
||||
font = gui::CGUITTFont::createTTFont(m_env,
|
||||
font_path.c_str(), size, true, true, font_shadow,
|
||||
font_shadow_alpha);
|
||||
|
||||
if (font) {
|
||||
m_font_cache[mode][basesize] = font;
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string &fallback_font_path = m_settings->getDefault("fallback_font_path");
|
||||
|
||||
if (font_path != fallback_font_path) {
|
||||
// try original fallback font
|
||||
errorstream << "FontEngine: failed to load custom fallback "
|
||||
"font: " << font_path << ", trying to fall back to "
|
||||
"original fallback font" << std::endl;
|
||||
|
||||
font = gui::CGUITTFont::createTTFont(m_env,
|
||||
fallback_font_path.c_str(), size, true, true,
|
||||
font_shadow, font_shadow_alpha);
|
||||
|
||||
if (font) {
|
||||
m_font_cache[mode][basesize] = font;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// give up
|
||||
errorstream << "FontEngine: failed to load freetype font: "
|
||||
<< font_path << std::endl;
|
||||
errorstream << "minetest can not continue without a valid font. Please correct "
|
||||
"the 'font_path' setting or install the font file in the proper "
|
||||
"location" << std::endl;
|
||||
errorstream << "minetest can not continue without a valid font. "
|
||||
"Please correct the 'font_path' setting or install the font "
|
||||
"file in the proper location" << std::endl;
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
@ -468,7 +506,7 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
|
||||
}
|
||||
}
|
||||
|
||||
if (font != NULL) {
|
||||
if (font) {
|
||||
font->grab();
|
||||
m_font_cache[mode][basesize] = font;
|
||||
}
|
||||
|
74
src/game.cpp
74
src/game.cpp
@ -170,7 +170,8 @@ struct LocalFormspecHandler : public TextDest
|
||||
}
|
||||
|
||||
// Don't disable this part when modding is disabled, it's used in builtin
|
||||
m_client->getScript()->on_formspec_input(m_formname, fields);
|
||||
if (m_client && m_client->getScript())
|
||||
m_client->getScript()->on_formspec_input(m_formname, fields);
|
||||
}
|
||||
|
||||
Client *m_client;
|
||||
@ -774,8 +775,8 @@ public:
|
||||
};
|
||||
|
||||
|
||||
bool nodePlacementPrediction(Client &client,
|
||||
const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos)
|
||||
bool nodePlacementPrediction(Client &client, const ItemDefinition &playeritem_def,
|
||||
const ItemStack &playeritem, v3s16 nodepos, v3s16 neighbourpos)
|
||||
{
|
||||
std::string prediction = playeritem_def.node_placement_prediction;
|
||||
INodeDefManager *nodedef = client.ndef();
|
||||
@ -818,11 +819,13 @@ bool nodePlacementPrediction(Client &client,
|
||||
return false;
|
||||
}
|
||||
|
||||
const ContentFeatures &predicted_f = nodedef->get(id);
|
||||
|
||||
// Predict param2 for facedir and wallmounted nodes
|
||||
u8 param2 = 0;
|
||||
|
||||
if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
|
||||
nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED) {
|
||||
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
|
||||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
|
||||
v3s16 dir = nodepos - neighbourpos;
|
||||
|
||||
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
|
||||
@ -834,8 +837,8 @@ bool nodePlacementPrediction(Client &client,
|
||||
}
|
||||
}
|
||||
|
||||
if (nodedef->get(id).param_type_2 == CPT2_FACEDIR ||
|
||||
nodedef->get(id).param_type_2 == CPT2_COLORED_FACEDIR) {
|
||||
if (predicted_f.param_type_2 == CPT2_FACEDIR ||
|
||||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
|
||||
v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS);
|
||||
|
||||
if (abs(dir.X) > abs(dir.Z)) {
|
||||
@ -848,7 +851,7 @@ bool nodePlacementPrediction(Client &client,
|
||||
assert(param2 <= 5);
|
||||
|
||||
//Check attachment if node is in group attached_node
|
||||
if (((ItemGroupList) nodedef->get(id).groups)["attached_node"] != 0) {
|
||||
if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
|
||||
static v3s16 wallmounted_dirs[8] = {
|
||||
v3s16(0, 1, 0),
|
||||
v3s16(0, -1, 0),
|
||||
@ -859,8 +862,8 @@ bool nodePlacementPrediction(Client &client,
|
||||
};
|
||||
v3s16 pp;
|
||||
|
||||
if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
|
||||
nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED)
|
||||
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
|
||||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
|
||||
pp = p + wallmounted_dirs[param2];
|
||||
else
|
||||
pp = p + v3s16(0, -1, 0);
|
||||
@ -869,6 +872,28 @@ bool nodePlacementPrediction(Client &client,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply color
|
||||
if ((predicted_f.param_type_2 == CPT2_COLOR
|
||||
|| predicted_f.param_type_2 == CPT2_COLORED_FACEDIR
|
||||
|| predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
|
||||
const std::string &indexstr = playeritem.metadata.getString(
|
||||
"palette_index", 0);
|
||||
if (!indexstr.empty()) {
|
||||
s32 index = mystoi(indexstr);
|
||||
if (predicted_f.param_type_2 == CPT2_COLOR) {
|
||||
param2 = index;
|
||||
} else if (predicted_f.param_type_2
|
||||
== CPT2_COLORED_WALLMOUNTED) {
|
||||
// param2 = pure palette index + other
|
||||
param2 = (index & 0xf8) | (param2 & 0x07);
|
||||
} else if (predicted_f.param_type_2
|
||||
== CPT2_COLORED_FACEDIR) {
|
||||
// param2 = pure palette index + other
|
||||
param2 = (index & 0xe0) | (param2 & 0x1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add node to client map
|
||||
MapNode n(id, 0, param2);
|
||||
|
||||
@ -1277,8 +1302,9 @@ protected:
|
||||
const core::line3d<f32> &shootline, bool liquids_pointable,
|
||||
bool look_for_object, const v3s16 &camera_offset);
|
||||
void handlePointingAtNothing(const ItemStack &playerItem);
|
||||
void handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime);
|
||||
void handlePointingAtNode(const PointedThing &pointed,
|
||||
const ItemDefinition &playeritem_def, const ItemStack &playeritem,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime);
|
||||
void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
|
||||
const v3f &player_position, bool show_debug);
|
||||
void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
|
||||
@ -2949,8 +2975,8 @@ void Game::decreaseViewRange()
|
||||
void Game::toggleFullViewRange()
|
||||
{
|
||||
static const wchar_t *msg[] = {
|
||||
L"Disabled full viewing range",
|
||||
L"Enabled full viewing range"
|
||||
L"Normal view range",
|
||||
L"Infinite view range"
|
||||
};
|
||||
|
||||
draw_control->range_all = !draw_control->range_all;
|
||||
@ -3525,6 +3551,9 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
|
||||
|
||||
if ((g_settings->getBool("touchtarget")) && (g_touchscreengui)) {
|
||||
shootline = g_touchscreengui->getShootline();
|
||||
// Scale shootline to the acual distance the player can reach
|
||||
shootline.end = shootline.start
|
||||
+ shootline.getVector().normalize() * BS * d;
|
||||
shootline.start += intToFloat(camera_offset, BS);
|
||||
shootline.end += intToFloat(camera_offset, BS);
|
||||
}
|
||||
@ -3597,10 +3626,11 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
|
||||
} else if (pointed.type == POINTEDTHING_NODE) {
|
||||
ToolCapabilities playeritem_toolcap =
|
||||
playeritem.getToolCapabilities(itemdef_manager);
|
||||
if (playeritem.name.empty()) {
|
||||
if (playeritem.name.empty() && hand_def.tool_capabilities != NULL) {
|
||||
playeritem_toolcap = *hand_def.tool_capabilities;
|
||||
}
|
||||
handlePointingAtNode(pointed, playeritem_def, playeritem_toolcap, dtime);
|
||||
handlePointingAtNode(pointed, playeritem_def, playeritem,
|
||||
playeritem_toolcap, dtime);
|
||||
} else if (pointed.type == POINTEDTHING_OBJECT) {
|
||||
handlePointingAtObject(pointed, playeritem, player_position, show_debug);
|
||||
} else if (isLeftPressed()) {
|
||||
@ -3735,8 +3765,9 @@ void Game::handlePointingAtNothing(const ItemStack &playerItem)
|
||||
}
|
||||
|
||||
|
||||
void Game::handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime)
|
||||
void Game::handlePointingAtNode(const PointedThing &pointed,
|
||||
const ItemDefinition &playeritem_def, const ItemStack &playeritem,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime)
|
||||
{
|
||||
v3s16 nodepos = pointed.node_undersurface;
|
||||
v3s16 neighbourpos = pointed.node_abovesurface;
|
||||
@ -3774,6 +3805,11 @@ void Game::handlePointingAtNode(const PointedThing &pointed, const ItemDefinitio
|
||||
|
||||
if (meta && meta->getString("formspec") != "" && !random_input
|
||||
&& !isKeyDown(KeyType::SNEAK)) {
|
||||
// Report right click to server
|
||||
if (nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
|
||||
client->interact(3, pointed);
|
||||
}
|
||||
|
||||
infostream << "Launching custom inventory view" << std::endl;
|
||||
|
||||
InventoryLocation inventoryloc;
|
||||
@ -3796,7 +3832,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed, const ItemDefinitio
|
||||
// If the wielded item has node placement prediction,
|
||||
// make that happen
|
||||
bool placed = nodePlacementPrediction(*client,
|
||||
playeritem_def,
|
||||
playeritem_def, playeritem,
|
||||
nodepos, neighbourpos);
|
||||
|
||||
if (placed) {
|
||||
|
@ -51,12 +51,13 @@ extern wchar_t *utf8_to_wide_c(const char *str);
|
||||
// The returned string is allocated using new
|
||||
inline const wchar_t *wgettext(const char *str)
|
||||
{
|
||||
return utf8_to_wide_c(gettext(str));
|
||||
// We must check here that is not an empty string to avoid trying to translate it
|
||||
return str[0] ? utf8_to_wide_c(gettext(str)) : utf8_to_wide_c("");
|
||||
}
|
||||
|
||||
inline std::string strgettext(const std::string &text)
|
||||
{
|
||||
return gettext(text.c_str());
|
||||
return text.empty() ? "" : gettext(text.c_str());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -204,8 +204,8 @@ void GUIChatConsole::draw()
|
||||
// scale current console height to new window size
|
||||
if (m_screensize.Y != 0)
|
||||
m_height = m_height * screensize.Y / m_screensize.Y;
|
||||
m_desired_height = m_desired_height_fraction * m_screensize.Y;
|
||||
m_screensize = screensize;
|
||||
m_desired_height = m_desired_height_fraction * m_screensize.Y;
|
||||
reformatConsole();
|
||||
}
|
||||
|
||||
@ -231,6 +231,7 @@ void GUIChatConsole::reformatConsole()
|
||||
s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
|
||||
if (cols <= 0 || rows <= 0)
|
||||
cols = rows = 0;
|
||||
recalculateConsolePosition();
|
||||
m_chat_backend->reformat(cols, rows);
|
||||
}
|
||||
|
||||
|
@ -87,22 +87,30 @@ MenuTextureSource::~MenuTextureSource()
|
||||
/******************************************************************************/
|
||||
video::ITexture* MenuTextureSource::getTexture(const std::string &name, u32 *id)
|
||||
{
|
||||
if(id)
|
||||
if (id)
|
||||
*id = 0;
|
||||
if(name.empty())
|
||||
|
||||
if (name.empty())
|
||||
return NULL;
|
||||
|
||||
m_to_delete.insert(name);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
video::IImage *image = m_driver->createImageFromFile(name.c_str());
|
||||
if (image) {
|
||||
image = Align2Npot2(image, m_driver);
|
||||
video::ITexture* retval = m_driver->addTexture(name.c_str(), image);
|
||||
image->drop();
|
||||
video::ITexture *retval = m_driver->findTexture(name.c_str());
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
video::IImage *image = m_driver->createImageFromFile(name.c_str());
|
||||
if (!image)
|
||||
return NULL;
|
||||
|
||||
image = Align2Npot2(image, m_driver);
|
||||
retval = m_driver->addTexture(name.c_str(), image);
|
||||
image->drop();
|
||||
return retval;
|
||||
#else
|
||||
return m_driver->getTexture(name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -3681,18 +3681,24 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
a->from_i = m_selected_item->i;
|
||||
m_invmgr->inventoryAction(a);
|
||||
} else if (craft_amount > 0) {
|
||||
m_selected_content_guess = ItemStack(); // Clear
|
||||
|
||||
// Send IACTION_CRAFT
|
||||
|
||||
assert(s.isValid());
|
||||
assert(inv_s);
|
||||
|
||||
// if there are no items selected or the selected item
|
||||
// belongs to craftresult list, proceed with crafting
|
||||
if (m_selected_item == NULL ||
|
||||
!m_selected_item->isValid() || m_selected_item->listname == "craftresult") {
|
||||
|
||||
m_selected_content_guess = ItemStack(); // Clear
|
||||
|
||||
assert(inv_s);
|
||||
|
||||
infostream << "Handing IACTION_CRAFT to manager" << std::endl;
|
||||
ICraftAction *a = new ICraftAction();
|
||||
a->count = craft_amount;
|
||||
a->craft_inv = s.inventoryloc;
|
||||
m_invmgr->inventoryAction(a);
|
||||
// Send IACTION_CRAFT
|
||||
infostream << "Handing IACTION_CRAFT to manager" << std::endl;
|
||||
ICraftAction *a = new ICraftAction();
|
||||
a->count = craft_amount;
|
||||
a->craft_inv = s.inventoryloc;
|
||||
m_invmgr->inventoryAction(a);
|
||||
}
|
||||
}
|
||||
|
||||
// If m_selected_amount has been decreased to zero, deselect
|
||||
|
@ -248,6 +248,7 @@ HTTPFetchOngoing::HTTPFetchOngoing(const HTTPFetchRequest &request_,
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_ENCODING, "gzip");
|
||||
|
||||
std::string bind_address = g_settings->get("bind_address");
|
||||
if (!bind_address.empty()) {
|
||||
|
22
src/hud.cpp
22
src/hud.cpp
@ -407,24 +407,32 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
|
||||
p += offset;
|
||||
|
||||
v2s32 steppos;
|
||||
core::rect<s32> srchalfrect, dsthalfrect;
|
||||
switch (drawdir) {
|
||||
case HUD_DIR_RIGHT_LEFT:
|
||||
steppos = v2s32(-1, 0);
|
||||
srchalfrect = core::rect<s32>(srcd.Width / 2, 0, srcd.Width, srcd.Height);
|
||||
dsthalfrect = core::rect<s32>(dstd.Width / 2, 0, dstd.Width, dstd.Height);
|
||||
break;
|
||||
case HUD_DIR_TOP_BOTTOM:
|
||||
steppos = v2s32(0, 1);
|
||||
srchalfrect = core::rect<s32>(0, 0, srcd.Width, srcd.Height / 2);
|
||||
dsthalfrect = core::rect<s32>(0, 0, dstd.Width, dstd.Height / 2);
|
||||
break;
|
||||
case HUD_DIR_BOTTOM_TOP:
|
||||
steppos = v2s32(0, -1);
|
||||
srchalfrect = core::rect<s32>(0, srcd.Height / 2, srcd.Width, srcd.Height);
|
||||
dsthalfrect = core::rect<s32>(0, dstd.Height / 2, dstd.Width, dstd.Height);
|
||||
break;
|
||||
default:
|
||||
steppos = v2s32(1, 0);
|
||||
srchalfrect = core::rect<s32>(0, 0, srcd.Width / 2, srcd.Height);
|
||||
dsthalfrect = core::rect<s32>(0, 0, dstd.Width / 2, dstd.Height);
|
||||
}
|
||||
steppos.X *= dstd.Width;
|
||||
steppos.Y *= dstd.Height;
|
||||
|
||||
for (s32 i = 0; i < count / 2; i++)
|
||||
{
|
||||
for (s32 i = 0; i < count / 2; i++) {
|
||||
core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
|
||||
core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
|
||||
|
||||
@ -433,13 +441,9 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
|
||||
p += steppos;
|
||||
}
|
||||
|
||||
if (count % 2 == 1)
|
||||
{
|
||||
core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
|
||||
core::rect<s32> dstrect(0,0, dstd.Width / 2, dstd.Height);
|
||||
|
||||
dstrect += p;
|
||||
draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
|
||||
if (count % 2 == 1) {
|
||||
dsthalfrect += p;
|
||||
draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1418,14 +1418,14 @@ void intlGUIEditBox::calculateScrollPos()
|
||||
// todo: adjust scrollbar
|
||||
}
|
||||
|
||||
// vertical scroll position
|
||||
if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y + VScrollPos)
|
||||
VScrollPos = CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y + VScrollPos;
|
||||
if (!WordWrap && !MultiLine)
|
||||
return;
|
||||
|
||||
else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y + VScrollPos)
|
||||
VScrollPos = CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y + VScrollPos;
|
||||
else
|
||||
VScrollPos = 0;
|
||||
// vertical scroll position
|
||||
if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y)
|
||||
VScrollPos += CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y; // scrolling downwards
|
||||
else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y)
|
||||
VScrollPos += CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y; // scrolling upwards
|
||||
|
||||
// todo: adjust scrollbar
|
||||
}
|
||||
|
@ -659,7 +659,7 @@ bool InventoryList::roomForItem(const ItemStack &item_) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InventoryList::containsItem(const ItemStack &item) const
|
||||
bool InventoryList::containsItem(const ItemStack &item, bool match_meta) const
|
||||
{
|
||||
u32 count = item.count;
|
||||
if(count == 0)
|
||||
@ -670,9 +670,9 @@ bool InventoryList::containsItem(const ItemStack &item) const
|
||||
{
|
||||
if(count == 0)
|
||||
break;
|
||||
if(i->name == item.name)
|
||||
{
|
||||
if(i->count >= count)
|
||||
if (i->name == item.name
|
||||
&& (!match_meta || (i->metadata == item.metadata))) {
|
||||
if (i->count >= count)
|
||||
return true;
|
||||
else
|
||||
count -= i->count;
|
||||
|
@ -223,9 +223,10 @@ public:
|
||||
// Checks whether there is room for a given item
|
||||
bool roomForItem(const ItemStack &item) const;
|
||||
|
||||
// Checks whether the given count of the given item name
|
||||
// Checks whether the given count of the given item
|
||||
// exists in this inventory list.
|
||||
bool containsItem(const ItemStack &item) const;
|
||||
// If match_meta is false, only the items' names are compared.
|
||||
bool containsItem(const ItemStack &item, bool match_meta) const;
|
||||
|
||||
// Removes the given count of the given item name from
|
||||
// this inventory list. Walks the list in reverse order.
|
||||
|
@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <vector3d.h>
|
||||
|
||||
typedef core::vector3df v3f;
|
||||
typedef core::vector3d<double> v3d;
|
||||
typedef core::vector3d<s16> v3s16;
|
||||
typedef core::vector3d<u16> v3u16;
|
||||
typedef core::vector3d<s32> v3s32;
|
||||
|
@ -13,11 +13,11 @@ void ItemStackMetadata::serialize(std::ostream &os) const
|
||||
{
|
||||
std::ostringstream os2;
|
||||
os2 << DESERIALIZE_START;
|
||||
for (StringMap::const_iterator
|
||||
it = m_stringvars.begin();
|
||||
it != m_stringvars.end(); ++it) {
|
||||
os2 << it->first << DESERIALIZE_KV_DELIM
|
||||
<< it->second << DESERIALIZE_PAIR_DELIM;
|
||||
for (StringMap::const_iterator it = m_stringvars.begin(); it != m_stringvars.end();
|
||||
++it) {
|
||||
if (!(*it).first.empty() || !(*it).second.empty())
|
||||
os2 << (*it).first << DESERIALIZE_KV_DELIM
|
||||
<< (*it).second << DESERIALIZE_PAIR_DELIM;
|
||||
}
|
||||
os << serializeJsonStringIfNeeded(os2.str());
|
||||
}
|
||||
@ -28,16 +28,18 @@ void ItemStackMetadata::deSerialize(std::istream &is)
|
||||
|
||||
m_stringvars.clear();
|
||||
|
||||
if (!in.empty() && in[0] == DESERIALIZE_START) {
|
||||
Strfnd fnd(in);
|
||||
fnd.to(1);
|
||||
while (!fnd.at_end()) {
|
||||
std::string name = fnd.next(DESERIALIZE_KV_DELIM_STR);
|
||||
std::string var = fnd.next(DESERIALIZE_PAIR_DELIM_STR);
|
||||
m_stringvars[name] = var;
|
||||
if (!in.empty()) {
|
||||
if (in[0] == DESERIALIZE_START) {
|
||||
Strfnd fnd(in);
|
||||
fnd.to(1);
|
||||
while (!fnd.at_end()) {
|
||||
std::string name = fnd.next(DESERIALIZE_KV_DELIM_STR);
|
||||
std::string var = fnd.next(DESERIALIZE_PAIR_DELIM_STR);
|
||||
m_stringvars[name] = var;
|
||||
}
|
||||
} else {
|
||||
// BACKWARDS COMPATIBILITY
|
||||
m_stringvars[""] = in;
|
||||
}
|
||||
} else {
|
||||
// BACKWARDS COMPATIBILITY
|
||||
m_stringvars[""] = in;
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
LocalPlayer::LocalPlayer(Client *client, const char *name):
|
||||
Player(name, client->idef()),
|
||||
parent(0),
|
||||
parent(NULL),
|
||||
hp(PLAYER_MAX_HP),
|
||||
isAttached(false),
|
||||
touching_ground(false),
|
||||
@ -53,8 +53,8 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
|
||||
overridePosition(v3f(0,0,0)),
|
||||
last_position(v3f(0,0,0)),
|
||||
last_speed(v3f(0,0,0)),
|
||||
last_pitch(0),
|
||||
last_yaw(0),
|
||||
last_pitch(0.0f),
|
||||
last_yaw(0.0f),
|
||||
last_keyPressed(0),
|
||||
last_camera_fov(0),
|
||||
last_wanted_range(0),
|
||||
@ -67,13 +67,12 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
|
||||
hurt_tilt_timer(0.0f),
|
||||
hurt_tilt_strength(0.0f),
|
||||
m_position(0,0,0),
|
||||
m_sneak_node(32767,32767,32767),
|
||||
m_sneak_node_bb_ymax(0), // To support temporary option for old move code
|
||||
m_sneak_node_bb_top(0,0,0,0,0,0),
|
||||
m_sneak_node(32767, 32767, 32767),
|
||||
m_sneak_node_bb_top(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f),
|
||||
m_sneak_node_exists(false),
|
||||
m_need_to_get_new_sneak_node(true),
|
||||
m_sneak_ladder_detected(false),
|
||||
m_ledge_detected(false),
|
||||
m_sneak_node_bb_ymax(0.0f),
|
||||
m_need_to_get_new_sneak_node(true),
|
||||
m_old_node_below(32767,32767,32767),
|
||||
m_old_node_below_type("air"),
|
||||
m_can_jump(false),
|
||||
@ -96,91 +95,142 @@ LocalPlayer::~LocalPlayer()
|
||||
{
|
||||
}
|
||||
|
||||
static aabb3f getTopBoundingBox(const std::vector<aabb3f> &nodeboxes)
|
||||
static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
|
||||
{
|
||||
if (nodeboxes.size() == 0)
|
||||
return aabb3f(0, 0, 0, 0, 0, 0);
|
||||
|
||||
aabb3f b_max;
|
||||
b_max.reset(-BS, -BS, -BS);
|
||||
for (std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
|
||||
it != nodeboxes.end(); ++it) {
|
||||
aabb3f box = *it;
|
||||
if (box.MaxEdge.Y > b_max.MaxEdge.Y)
|
||||
b_max = box;
|
||||
else if (box.MaxEdge.Y == b_max.MaxEdge.Y)
|
||||
b_max.addInternalBox(box);
|
||||
}
|
||||
return aabb3f(v3f(b_max.MinEdge.X, b_max.MaxEdge.Y, b_max.MinEdge.Z), b_max.MaxEdge);
|
||||
|
||||
std::vector<aabb3f>::const_iterator it = nodeboxes.begin();
|
||||
b_max = aabb3f(it->MinEdge, it->MaxEdge);
|
||||
|
||||
++it;
|
||||
for (; it != nodeboxes.end(); ++it)
|
||||
b_max.addInternalBox(*it);
|
||||
|
||||
return b_max;
|
||||
}
|
||||
|
||||
#define GETNODE(map, p3, v2, y, valid) \
|
||||
(map)->getNodeNoEx((p3) + v3s16((v2).X, y, (v2).Y), valid)
|
||||
|
||||
// pos is the node the player is standing inside(!)
|
||||
static bool detectSneakLadder(Map *map, INodeDefManager *nodemgr, v3s16 pos)
|
||||
bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
|
||||
const v3f &sneak_max)
|
||||
{
|
||||
// Detects a structure known as "sneak ladder" or "sneak elevator"
|
||||
// that relies on bugs to provide a fast means of vertical transportation,
|
||||
// the bugs have since been fixed but this function remains to keep it working.
|
||||
// NOTE: This is just entirely a huge hack and causes way too many problems.
|
||||
bool is_valid_position;
|
||||
static const v3s16 dir9_center[9] = {
|
||||
v3s16( 0, 0, 0),
|
||||
v3s16( 1, 0, 0),
|
||||
v3s16(-1, 0, 0),
|
||||
v3s16( 0, 0, 1),
|
||||
v3s16( 0, 0, -1),
|
||||
v3s16( 1, 0, 1),
|
||||
v3s16(-1, 0, 1),
|
||||
v3s16( 1, 0, -1),
|
||||
v3s16(-1, 0, -1)
|
||||
};
|
||||
|
||||
INodeDefManager *nodemgr = m_client->ndef();
|
||||
MapNode node;
|
||||
// X/Z vectors for 4 neighboring nodes
|
||||
static const v2s16 vecs[] = { v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1) };
|
||||
bool is_valid_position;
|
||||
bool new_sneak_node_exists = m_sneak_node_exists;
|
||||
|
||||
for (u16 i = 0; i < ARRLEN(vecs); i++) {
|
||||
const v2s16 vec = vecs[i];
|
||||
// We want the top of the sneak node to be below the players feet
|
||||
f32 position_y_mod = 0.05 * BS;
|
||||
if (m_sneak_node_exists)
|
||||
position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - position_y_mod;
|
||||
|
||||
// walkability of bottom & top node should differ
|
||||
node = GETNODE(map, pos, vec, 0, &is_valid_position);
|
||||
if (!is_valid_position)
|
||||
continue;
|
||||
bool w = nodemgr->get(node).walkable;
|
||||
node = GETNODE(map, pos, vec, 1, &is_valid_position);
|
||||
if (!is_valid_position || w == nodemgr->get(node).walkable)
|
||||
// Get position of current standing node
|
||||
const v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
|
||||
|
||||
if (current_node != m_sneak_node) {
|
||||
new_sneak_node_exists = false;
|
||||
} else {
|
||||
node = map->getNodeNoEx(current_node, &is_valid_position);
|
||||
if (!is_valid_position || !nodemgr->get(node).walkable)
|
||||
new_sneak_node_exists = false;
|
||||
}
|
||||
|
||||
// Keep old sneak node
|
||||
if (new_sneak_node_exists)
|
||||
return true;
|
||||
|
||||
// Get new sneak node
|
||||
m_sneak_ladder_detected = false;
|
||||
f32 min_distance_f = 100000.0 * BS;
|
||||
|
||||
for (s16 d = 0; d < 9; d++) {
|
||||
const v3s16 p = current_node + dir9_center[d];
|
||||
const v3f pf = intToFloat(p, BS);
|
||||
const v2f diff(position.X - pf.X, position.Z - pf.Z);
|
||||
f32 distance_f = diff.getLength();
|
||||
|
||||
if (distance_f > min_distance_f ||
|
||||
fabs(diff.X) > (.5 + .1) * BS + sneak_max.X ||
|
||||
fabs(diff.Y) > (.5 + .1) * BS + sneak_max.Z)
|
||||
continue;
|
||||
|
||||
// check one more node above OR below with corresponding walkability
|
||||
node = GETNODE(map, pos, vec, -1, &is_valid_position);
|
||||
bool ok = is_valid_position && w != nodemgr->get(node).walkable;
|
||||
if (!ok) {
|
||||
node = GETNODE(map, pos, vec, 2, &is_valid_position);
|
||||
ok = is_valid_position && w == nodemgr->get(node).walkable;
|
||||
|
||||
// The node to be sneaked on has to be walkable
|
||||
node = map->getNodeNoEx(p, &is_valid_position);
|
||||
if (!is_valid_position || !nodemgr->get(node).walkable)
|
||||
continue;
|
||||
// And the node(s) above have to be nonwalkable
|
||||
bool ok = true;
|
||||
if (!physics_override_sneak_glitch) {
|
||||
u16 height = ceilf(
|
||||
(m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
|
||||
);
|
||||
for (u16 y = 1; y <= height; y++) {
|
||||
node = map->getNodeNoEx(p + v3s16(0, y, 0), &is_valid_position);
|
||||
if (!is_valid_position || nodemgr->get(node).walkable) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// legacy behaviour: check just one node
|
||||
node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
|
||||
ok = is_valid_position && !nodemgr->get(node).walkable;
|
||||
}
|
||||
if (!ok)
|
||||
continue;
|
||||
|
||||
if (ok)
|
||||
return true;
|
||||
min_distance_f = distance_f;
|
||||
m_sneak_node = p;
|
||||
new_sneak_node_exists = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!new_sneak_node_exists)
|
||||
return false;
|
||||
|
||||
static bool detectLedge(Map *map, INodeDefManager *nodemgr, v3s16 pos)
|
||||
{
|
||||
bool is_valid_position;
|
||||
MapNode node;
|
||||
// X/Z vectors for 4 neighboring nodes
|
||||
static const v2s16 vecs[] = {v2s16(-1, 0), v2s16(1, 0), v2s16(0, -1), v2s16(0, 1)};
|
||||
// Update saved top bounding box of sneak node
|
||||
node = map->getNodeNoEx(m_sneak_node);
|
||||
std::vector<aabb3f> nodeboxes;
|
||||
node.getCollisionBoxes(nodemgr, &nodeboxes);
|
||||
m_sneak_node_bb_top = getNodeBoundingBox(nodeboxes);
|
||||
|
||||
for (u16 i = 0; i < ARRLEN(vecs); i++) {
|
||||
const v2s16 vec = vecs[i];
|
||||
|
||||
node = GETNODE(map, pos, vec, 1, &is_valid_position);
|
||||
if (physics_override_sneak_glitch) {
|
||||
// Detect sneak ladder:
|
||||
// Node two meters above sneak node must be solid
|
||||
node = map->getNodeNoEx(m_sneak_node + v3s16(0, 2, 0),
|
||||
&is_valid_position);
|
||||
if (is_valid_position && nodemgr->get(node).walkable) {
|
||||
// Ledge exists
|
||||
node = GETNODE(map, pos, vec, 2, &is_valid_position);
|
||||
if (is_valid_position && !nodemgr->get(node).walkable)
|
||||
// Space above ledge exists
|
||||
return true;
|
||||
// Node three meters above: must be non-solid
|
||||
node = map->getNodeNoEx(m_sneak_node + v3s16(0, 3, 0),
|
||||
&is_valid_position);
|
||||
m_sneak_ladder_detected = is_valid_position &&
|
||||
!nodemgr->get(node).walkable;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef GETNODE
|
||||
|
||||
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
std::vector<CollisionInfo> *collision_info)
|
||||
{
|
||||
if (!collision_info || collision_info->empty()) {
|
||||
// Node below the feet, update each ClientEnvironment::step()
|
||||
m_standing_node = floatToInt(m_position, BS) - v3s16(0, 1, 0);
|
||||
}
|
||||
|
||||
// Temporary option for old move code
|
||||
if (!physics_override_new_move) {
|
||||
old_move(dtime, env, pos_max_d, collision_info);
|
||||
@ -193,10 +243,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
v3f position = getPosition();
|
||||
|
||||
// Copy parent position if local player is attached
|
||||
if(isAttached)
|
||||
{
|
||||
if (isAttached) {
|
||||
setPosition(overridePosition);
|
||||
m_sneak_node_exists = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -204,11 +252,11 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
bool fly_allowed = m_client->checkLocalPrivilege("fly");
|
||||
bool noclip = m_client->checkLocalPrivilege("noclip") &&
|
||||
g_settings->getBool("noclip");
|
||||
bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
|
||||
if (free_move) {
|
||||
bool free_move = g_settings->getBool("free_move") && fly_allowed;
|
||||
|
||||
if (noclip && free_move) {
|
||||
position += m_speed * dtime;
|
||||
setPosition(position);
|
||||
m_sneak_node_exists = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -279,7 +327,6 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
|| nodemgr->get(node2.getContent()).climbable) && !free_move;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Collision uncertainty radius
|
||||
Make it a bit larger than the maximum distance of movement
|
||||
@ -291,49 +338,109 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
// This should always apply, otherwise there are glitches
|
||||
sanity_check(d > pos_max_d);
|
||||
|
||||
// TODO: this shouldn't be hardcoded but transmitted from server
|
||||
float player_stepheight = (touching_ground) ? (BS * 0.6f) : (BS * 0.2f);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (touching_ground)
|
||||
player_stepheight += (0.6f * BS);
|
||||
#endif
|
||||
|
||||
v3f accel_f = v3f(0,0,0);
|
||||
|
||||
collisionMoveResult result = collisionMoveSimple(env, m_client,
|
||||
pos_max_d, m_collisionbox, player_stepheight, dtime,
|
||||
&position, &m_speed, accel_f);
|
||||
|
||||
bool could_sneak = control.sneak && !free_move && !in_liquid &&
|
||||
!is_climbing && physics_override_sneak;
|
||||
|
||||
// Add new collisions to the vector
|
||||
if (collision_info && !free_move) {
|
||||
v3f diff = intToFloat(m_standing_node, BS) - position;
|
||||
f32 distance = diff.getLength();
|
||||
// Force update each ClientEnvironment::step()
|
||||
bool is_first = collision_info->empty();
|
||||
|
||||
for (std::vector<CollisionInfo>::const_iterator
|
||||
colinfo = result.collisions.begin();
|
||||
colinfo != result.collisions.end(); ++colinfo) {
|
||||
collision_info->push_back(*colinfo);
|
||||
|
||||
if (colinfo->type != COLLISION_NODE ||
|
||||
colinfo->new_speed.Y != 0 ||
|
||||
(could_sneak && m_sneak_node_exists))
|
||||
continue;
|
||||
|
||||
diff = intToFloat(colinfo->node_p, BS) - position;
|
||||
|
||||
// Find nearest colliding node
|
||||
f32 len = diff.getLength();
|
||||
if (is_first || len < distance) {
|
||||
m_standing_node = colinfo->node_p;
|
||||
distance = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If the player's feet touch the topside of any node, this is
|
||||
set to true.
|
||||
|
||||
Player is allowed to jump when this is true.
|
||||
*/
|
||||
bool touching_ground_was = touching_ground;
|
||||
touching_ground = result.touching_ground;
|
||||
bool sneak_can_jump = false;
|
||||
|
||||
// Max. distance (X, Z) over border for sneaking determined by collision box
|
||||
// * 0.49 to keep the center just barely on the node
|
||||
v3f sneak_max = m_collisionbox.getExtent() * 0.49;
|
||||
|
||||
if (m_sneak_ladder_detected) {
|
||||
// restore legacy behaviour (this makes the m_speed.Y hack necessary)
|
||||
sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
|
||||
}
|
||||
|
||||
/*
|
||||
If sneaking, keep in range from the last walked node and don't
|
||||
fall off from it
|
||||
If sneaking, keep on top of last walked node and don't fall off
|
||||
*/
|
||||
if (control.sneak && m_sneak_node_exists &&
|
||||
!(fly_allowed && g_settings->getBool("free_move")) &&
|
||||
!in_liquid && !is_climbing &&
|
||||
physics_override_sneak) {
|
||||
if (could_sneak && m_sneak_node_exists) {
|
||||
const v3f sn_f = intToFloat(m_sneak_node, BS);
|
||||
const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge;
|
||||
const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge;
|
||||
const v3f old_pos = position;
|
||||
const v3f old_speed = m_speed;
|
||||
f32 y_diff = bmax.Y - position.Y;
|
||||
m_standing_node = m_sneak_node;
|
||||
|
||||
position.X = rangelim(position.X,
|
||||
// (BS * 0.6f) is the basic stepheight while standing on ground
|
||||
if (y_diff < BS * 0.6f) {
|
||||
// Only center player when they're on the node
|
||||
position.X = rangelim(position.X,
|
||||
bmin.X - sneak_max.X, bmax.X + sneak_max.X);
|
||||
position.Z = rangelim(position.Z,
|
||||
position.Z = rangelim(position.Z,
|
||||
bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
|
||||
|
||||
if (position.X != old_pos.X)
|
||||
m_speed.X = 0;
|
||||
if (position.Z != old_pos.Z)
|
||||
m_speed.Z = 0;
|
||||
|
||||
// Because we keep the player collision box on the node, limiting
|
||||
// position.Y is not necessary but useful to prevent players from
|
||||
// being inside a node if sneaking on e.g. the lower part of a stair
|
||||
if (!m_sneak_ladder_detected) {
|
||||
position.Y = MYMAX(position.Y, bmax.Y);
|
||||
} else {
|
||||
// legacy behaviour that sometimes causes some weird slow sinking
|
||||
m_speed.Y = MYMAX(m_speed.Y, 0);
|
||||
if (position.X != old_pos.X)
|
||||
m_speed.X = 0;
|
||||
if (position.Z != old_pos.Z)
|
||||
m_speed.Z = 0;
|
||||
}
|
||||
|
||||
if (collision_info != NULL &&
|
||||
if (y_diff > 0 && m_speed.Y < 0 &&
|
||||
(physics_override_sneak_glitch || y_diff < BS * 0.6f)) {
|
||||
// Move player to the maximal height when falling or when
|
||||
// the ledge is climbed on the next step.
|
||||
position.Y = bmax.Y;
|
||||
m_speed.Y = 0;
|
||||
}
|
||||
|
||||
// Allow jumping on node edges while sneaking
|
||||
if (m_speed.Y == 0 || m_sneak_ladder_detected)
|
||||
sneak_can_jump = true;
|
||||
|
||||
if (collision_info &&
|
||||
m_speed.Y - old_speed.Y > BS) {
|
||||
// Collide with sneak node, report fall damage
|
||||
CollisionInfo sn_info;
|
||||
@ -344,144 +451,24 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this shouldn't be hardcoded but transmitted from server
|
||||
float player_stepheight = (touching_ground) ? (BS * 0.6f) : (BS * 0.2f);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
player_stepheight += (0.6f * BS);
|
||||
#endif
|
||||
|
||||
v3f accel_f = v3f(0,0,0);
|
||||
|
||||
collisionMoveResult result = collisionMoveSimple(env, m_client,
|
||||
pos_max_d, m_collisionbox, player_stepheight, dtime,
|
||||
&position, &m_speed, accel_f);
|
||||
|
||||
/*
|
||||
If the player's feet touch the topside of any node, this is
|
||||
set to true.
|
||||
|
||||
Player is allowed to jump when this is true.
|
||||
Find the next sneak node if necessary
|
||||
*/
|
||||
bool touching_ground_was = touching_ground;
|
||||
touching_ground = result.touching_ground;
|
||||
bool new_sneak_node_exists = false;
|
||||
|
||||
// We want the top of the sneak node to be below the players feet
|
||||
f32 position_y_mod;
|
||||
if (m_sneak_node_exists)
|
||||
position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - 0.05 * BS;
|
||||
else
|
||||
position_y_mod = (0.5 - 0.05) * BS;
|
||||
v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
|
||||
/*
|
||||
Check the nodes under the player to see from which node the
|
||||
player is sneaking from, if any. If the node from under
|
||||
the player has been removed, the player falls.
|
||||
*/
|
||||
if (m_sneak_node_exists &&
|
||||
nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
|
||||
m_old_node_below_type != "air") {
|
||||
// Old node appears to have been removed; that is,
|
||||
// it wasn't air before but now it is
|
||||
m_need_to_get_new_sneak_node = false;
|
||||
m_sneak_node_exists = false;
|
||||
} else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
|
||||
// We are on something, so make sure to recalculate the sneak
|
||||
// node.
|
||||
m_need_to_get_new_sneak_node = true;
|
||||
}
|
||||
|
||||
if (m_need_to_get_new_sneak_node && physics_override_sneak) {
|
||||
v2f player_p2df(position.X, position.Z);
|
||||
f32 min_distance_f = 100000.0 * BS;
|
||||
v3s16 new_sneak_node = m_sneak_node;
|
||||
for(s16 x=-1; x<=1; x++)
|
||||
for(s16 z=-1; z<=1; z++)
|
||||
{
|
||||
v3s16 p = current_node + v3s16(x,0,z);
|
||||
v3f pf = intToFloat(p, BS);
|
||||
v2f node_p2df(pf.X, pf.Z);
|
||||
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
|
||||
|
||||
if (distance_f > min_distance_f ||
|
||||
fabs(player_p2df.X-node_p2df.X) > (.5+.1)*BS + sneak_max.X ||
|
||||
fabs(player_p2df.Y-node_p2df.Y) > (.5+.1)*BS + sneak_max.Z)
|
||||
continue;
|
||||
|
||||
|
||||
// The node to be sneaked on has to be walkable
|
||||
node = map->getNodeNoEx(p, &is_valid_position);
|
||||
if (!is_valid_position || !nodemgr->get(node).walkable)
|
||||
continue;
|
||||
// And the node(s) above have to be nonwalkable
|
||||
bool ok = true;
|
||||
if (!physics_override_sneak_glitch) {
|
||||
u16 height = ceilf(
|
||||
(m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
|
||||
);
|
||||
for (u16 y = 1; y <= height; y++) {
|
||||
node = map->getNodeNoEx(p + v3s16(0,y,0), &is_valid_position);
|
||||
if (!is_valid_position || nodemgr->get(node).walkable) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// legacy behaviour: check just one node
|
||||
node = map->getNodeNoEx(p + v3s16(0,1,0), &is_valid_position);
|
||||
ok = is_valid_position && !nodemgr->get(node).walkable;
|
||||
}
|
||||
if (!ok)
|
||||
continue;
|
||||
|
||||
min_distance_f = distance_f;
|
||||
new_sneak_node = p;
|
||||
}
|
||||
|
||||
bool sneak_node_found = (min_distance_f < 100000.0 * BS);
|
||||
m_sneak_node = new_sneak_node;
|
||||
m_sneak_node_exists = sneak_node_found;
|
||||
|
||||
if (sneak_node_found) {
|
||||
// Update saved top bounding box of sneak node
|
||||
MapNode n = map->getNodeNoEx(m_sneak_node);
|
||||
std::vector<aabb3f> nodeboxes;
|
||||
n.getCollisionBoxes(nodemgr, &nodeboxes);
|
||||
m_sneak_node_bb_top = getTopBoundingBox(nodeboxes);
|
||||
|
||||
m_sneak_ladder_detected = physics_override_sneak_glitch &&
|
||||
detectSneakLadder(map, nodemgr, floatToInt(position, BS));
|
||||
} else {
|
||||
m_sneak_ladder_detected = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If 'sneak glitch' enabled detect ledge for old sneak-jump
|
||||
behaviour of climbing onto a ledge 2 nodes up.
|
||||
*/
|
||||
if (physics_override_sneak_glitch && control.sneak && control.jump)
|
||||
m_ledge_detected = detectLedge(map, nodemgr, floatToInt(position, BS));
|
||||
if (could_sneak)
|
||||
new_sneak_node_exists = updateSneakNode(map, position, sneak_max);
|
||||
|
||||
/*
|
||||
Set new position but keep sneak node set
|
||||
*/
|
||||
bool sneak_node_exists = m_sneak_node_exists;
|
||||
setPosition(position);
|
||||
m_sneak_node_exists = sneak_node_exists;
|
||||
m_sneak_node_exists = new_sneak_node_exists;
|
||||
|
||||
/*
|
||||
Report collisions
|
||||
*/
|
||||
|
||||
// Dont report if flying
|
||||
if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) {
|
||||
for(size_t i=0; i<result.collisions.size(); i++) {
|
||||
const CollisionInfo &info = result.collisions[i];
|
||||
collision_info->push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
if(!result.standing_on_object && !touching_ground_was && touching_ground) {
|
||||
MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
|
||||
m_client->event()->put(e);
|
||||
@ -501,22 +488,15 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Update the node last under the player
|
||||
*/
|
||||
m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
|
||||
m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
|
||||
|
||||
/*
|
||||
Check properties of the node on which the player is standing
|
||||
*/
|
||||
const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
|
||||
const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(m_standing_node));
|
||||
// Determine if jumping is possible
|
||||
m_can_jump = touching_ground && !in_liquid;
|
||||
m_can_jump = (touching_ground && !in_liquid && !is_climbing)
|
||||
|| sneak_can_jump;
|
||||
if (itemgroup_get(f.groups, "disable_jump"))
|
||||
m_can_jump = false;
|
||||
else if (control.sneak && m_sneak_ladder_detected && !in_liquid && !is_climbing)
|
||||
m_can_jump = true;
|
||||
|
||||
// Jump key pressed while jumping off from a bouncy block
|
||||
if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
|
||||
@ -705,17 +685,8 @@ void LocalPlayer::applyControl(float dtime)
|
||||
*/
|
||||
v3f speedJ = getSpeed();
|
||||
if(speedJ.Y >= -0.5 * BS) {
|
||||
if (m_ledge_detected) {
|
||||
// Limit jump speed to a minimum that allows
|
||||
// jumping up onto a ledge 2 nodes up.
|
||||
speedJ.Y = movement_speed_jump *
|
||||
MYMAX(physics_override_jump, 1.3f);
|
||||
setSpeed(speedJ);
|
||||
m_ledge_detected = false;
|
||||
} else {
|
||||
speedJ.Y = movement_speed_jump * physics_override_jump;
|
||||
setSpeed(speedJ);
|
||||
}
|
||||
speedJ.Y = movement_speed_jump * physics_override_jump;
|
||||
setSpeed(speedJ);
|
||||
|
||||
MtEvent *e = new SimpleTriggerEvent("PlayerJump");
|
||||
m_client->event()->put(e);
|
||||
@ -772,7 +743,7 @@ v3s16 LocalPlayer::getStandingNodePos()
|
||||
{
|
||||
if(m_sneak_node_exists)
|
||||
return m_sneak_node;
|
||||
return floatToInt(getPosition() - v3f(0, BS, 0), BS);
|
||||
return m_standing_node;
|
||||
}
|
||||
|
||||
v3s16 LocalPlayer::getFootstepNodePos()
|
||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "player.h"
|
||||
#include "environment.h"
|
||||
#include "constants.h"
|
||||
#include <list>
|
||||
|
||||
class Client;
|
||||
@ -46,6 +47,8 @@ public:
|
||||
|
||||
ClientActiveObject *parent;
|
||||
|
||||
// Initialize hp to 0, so that no hearts will be shown if server
|
||||
// doesn't support health points
|
||||
u16 hp;
|
||||
bool isAttached;
|
||||
bool touching_ground;
|
||||
@ -108,7 +111,7 @@ public:
|
||||
|
||||
void setCAO(GenericCAO *toset)
|
||||
{
|
||||
assert(m_cao == NULL); // Pre-condition
|
||||
assert(!m_cao); // Pre-condition
|
||||
m_cao = toset;
|
||||
}
|
||||
|
||||
@ -140,30 +143,31 @@ public:
|
||||
private:
|
||||
void accelerateHorizontal(const v3f &target_speed, const f32 max_increase);
|
||||
void accelerateVertical(const v3f &target_speed, const f32 max_increase);
|
||||
bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max);
|
||||
|
||||
v3f m_position;
|
||||
v3s16 m_standing_node;
|
||||
|
||||
v3s16 m_sneak_node;
|
||||
// Stores the max player uplift by m_sneak_node
|
||||
// To support temporary option for old move code
|
||||
f32 m_sneak_node_bb_ymax;
|
||||
// Stores the top bounding box of m_sneak_node
|
||||
aabb3f m_sneak_node_bb_top;
|
||||
// Whether the player is allowed to sneak
|
||||
bool m_sneak_node_exists;
|
||||
// Whether recalculation of m_sneak_node and its top bbox is needed
|
||||
bool m_need_to_get_new_sneak_node;
|
||||
// Whether a "sneak ladder" structure is detected at the players pos
|
||||
// see detectSneakLadder() in the .cpp for more info (always false if disabled)
|
||||
bool m_sneak_ladder_detected;
|
||||
// Whether a 2-node-up ledge is detected at the players pos,
|
||||
// see detectLedge() in the .cpp for more info (always false if disabled).
|
||||
bool m_ledge_detected;
|
||||
|
||||
// ***** Variables for temporary option of the old move code *****
|
||||
// Stores the max player uplift by m_sneak_node
|
||||
f32 m_sneak_node_bb_ymax;
|
||||
// Whether recalculation of m_sneak_node and its top bbox is needed
|
||||
bool m_need_to_get_new_sneak_node;
|
||||
// Node below player, used to determine whether it has been removed,
|
||||
// and its old type
|
||||
v3s16 m_old_node_below;
|
||||
std::string m_old_node_below_type;
|
||||
// ***** End of variables for temporary option *****
|
||||
|
||||
bool m_can_jump;
|
||||
u16 m_breath;
|
||||
f32 m_yaw;
|
||||
|
@ -347,13 +347,10 @@ void StringBuffer::push_back(char c)
|
||||
flush(std::string(buffer, buffer_index));
|
||||
buffer_index = 0;
|
||||
} else {
|
||||
int index = buffer_index;
|
||||
buffer[index++] = c;
|
||||
if (index >= BUFFER_LENGTH) {
|
||||
buffer[buffer_index++] = c;
|
||||
if (buffer_index >= BUFFER_LENGTH) {
|
||||
flush(std::string(buffer, buffer_index));
|
||||
buffer_index = 0;
|
||||
} else {
|
||||
buffer_index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1378,11 +1378,6 @@ s16 ServerMap::getWaterLevel()
|
||||
return getMapgenParams()->water_level;
|
||||
}
|
||||
|
||||
bool ServerMap::saoPositionOverLimit(const v3f &p)
|
||||
{
|
||||
return getMapgenParams()->saoPosOverLimit(p);
|
||||
}
|
||||
|
||||
bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
|
||||
{
|
||||
const s16 mapgen_limit_bp = rangelim(
|
||||
@ -2737,6 +2732,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
|
||||
continue;
|
||||
|
||||
block->copyFrom(*this);
|
||||
block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
|
||||
|
||||
if(modified_blocks)
|
||||
(*modified_blocks)[p] = block;
|
||||
|
@ -377,8 +377,6 @@ public:
|
||||
*/
|
||||
ServerMapSector *createSector(v2s16 p);
|
||||
|
||||
bool saoPositionOverLimit(const v3f &p);
|
||||
|
||||
/*
|
||||
Blocks are generated by using these and makeBlock().
|
||||
*/
|
||||
|
@ -122,7 +122,8 @@ public:
|
||||
#define MOD_REASON_STATIC_DATA_REMOVED (1 << 16)
|
||||
#define MOD_REASON_STATIC_DATA_CHANGED (1 << 17)
|
||||
#define MOD_REASON_EXPIRE_DAYNIGHTDIFF (1 << 18)
|
||||
#define MOD_REASON_UNKNOWN (1 << 19)
|
||||
#define MOD_REASON_VMANIP (1 << 19)
|
||||
#define MOD_REASON_UNKNOWN (1 << 20)
|
||||
|
||||
////
|
||||
//// MapBlock itself
|
||||
|
@ -809,7 +809,16 @@ void MapgenBasic::dustTopNodes()
|
||||
}
|
||||
|
||||
content_t c = vm->m_data[vi].getContent();
|
||||
if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
|
||||
NodeDrawType dtype = ndef->get(c).drawtype;
|
||||
// Only place on walkable cubic non-liquid nodes
|
||||
// Dust check needed due to vertical overgeneration
|
||||
if ((dtype == NDT_NORMAL ||
|
||||
dtype == NDT_ALLFACES_OPTIONAL ||
|
||||
dtype == NDT_GLASSLIKE_FRAMED_OPTIONAL ||
|
||||
dtype == NDT_GLASSLIKE ||
|
||||
dtype == NDT_GLASSLIKE_FRAMED ||
|
||||
dtype == NDT_ALLFACES) &&
|
||||
ndef->get(c).walkable && c != biome->c_dust) {
|
||||
vm->m_area.add_y(em, vi, 1);
|
||||
vm->m_data[vi] = MapNode(biome->c_dust);
|
||||
}
|
||||
@ -973,8 +982,7 @@ bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
|
||||
|
||||
|
||||
void GenerateNotifier::getEvents(
|
||||
std::map<std::string, std::vector<v3s16> > &event_map,
|
||||
bool peek_events)
|
||||
std::map<std::string, std::vector<v3s16> > &event_map)
|
||||
{
|
||||
std::list<GenNotifyEvent>::iterator it;
|
||||
|
||||
@ -986,9 +994,12 @@ void GenerateNotifier::getEvents(
|
||||
|
||||
event_map[name].push_back(gn.pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (!peek_events)
|
||||
m_notify_events.clear();
|
||||
|
||||
void GenerateNotifier::clearEvents()
|
||||
{
|
||||
m_notify_events.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -1049,16 +1060,15 @@ void MapgenParams::writeParams(Settings *settings) const
|
||||
bparams->writeParams(settings);
|
||||
}
|
||||
|
||||
// Calculate edges of outermost generated mapchunks (less than
|
||||
// 'mapgen_limit'), and corresponding exact limits for SAO entities.
|
||||
|
||||
// Calculate exact edges of the outermost mapchunks that are within the
|
||||
// set 'mapgen_limit'.
|
||||
void MapgenParams::calcMapgenEdges()
|
||||
{
|
||||
// Central chunk offset, in blocks
|
||||
s16 ccoff_b = -chunksize / 2;
|
||||
|
||||
// Chunksize, in nodes
|
||||
s32 csize_n = chunksize * MAP_BLOCKSIZE;
|
||||
|
||||
// Minp/maxp of central chunk, in nodes
|
||||
s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
|
||||
s16 ccmax = ccmin + csize_n - 1;
|
||||
@ -1077,25 +1087,17 @@ void MapgenParams::calcMapgenEdges()
|
||||
s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
|
||||
s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
|
||||
// Mapgen edges, in nodes
|
||||
// These values may be useful later as additional class members
|
||||
s16 mapgen_edge_min = ccmin - numcmin * csize_n;
|
||||
s16 mapgen_edge_max = ccmax + numcmax * csize_n;
|
||||
// SAO position limits, in Irrlicht units
|
||||
m_sao_limit_min = mapgen_edge_min * BS - 3.0f;
|
||||
m_sao_limit_max = mapgen_edge_max * BS + 3.0f;
|
||||
mapgen_edge_min = ccmin - numcmin * csize_n;
|
||||
mapgen_edge_max = ccmax + numcmax * csize_n;
|
||||
|
||||
m_mapgen_edges_calculated = true;
|
||||
}
|
||||
|
||||
|
||||
bool MapgenParams::saoPosOverLimit(const v3f &p)
|
||||
s32 MapgenParams::getSpawnRangeMax()
|
||||
{
|
||||
if (!m_sao_limit_calculated) {
|
||||
if (!m_mapgen_edges_calculated)
|
||||
calcMapgenEdges();
|
||||
m_sao_limit_calculated = true;
|
||||
}
|
||||
return p.X < m_sao_limit_min ||
|
||||
p.X > m_sao_limit_max ||
|
||||
p.Y < m_sao_limit_min ||
|
||||
p.Y > m_sao_limit_max ||
|
||||
p.Z < m_sao_limit_min ||
|
||||
p.Z > m_sao_limit_max;
|
||||
|
||||
return MYMIN(-mapgen_edge_min, mapgen_edge_max);
|
||||
}
|
||||
|
21
src/mapgen.h
21
src/mapgen.h
@ -101,8 +101,8 @@ public:
|
||||
void setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids);
|
||||
|
||||
bool addEvent(GenNotifyType type, v3s16 pos, u32 id=0);
|
||||
void getEvents(std::map<std::string, std::vector<v3s16> > &event_map,
|
||||
bool peek_events=false);
|
||||
void getEvents(std::map<std::string, std::vector<v3s16> > &event_map);
|
||||
void clearEvents();
|
||||
|
||||
private:
|
||||
u32 m_notify_on;
|
||||
@ -131,6 +131,9 @@ struct MapgenParams {
|
||||
|
||||
BiomeParams *bparams;
|
||||
|
||||
s16 mapgen_edge_min;
|
||||
s16 mapgen_edge_max;
|
||||
|
||||
MapgenParams() :
|
||||
mgtype(MAPGEN_DEFAULT),
|
||||
chunksize(5),
|
||||
@ -139,9 +142,10 @@ struct MapgenParams {
|
||||
mapgen_limit(MAX_MAP_GENERATION_LIMIT),
|
||||
flags(MG_CAVES | MG_LIGHT | MG_DECORATIONS),
|
||||
bparams(NULL),
|
||||
m_sao_limit_min(MAX_MAP_GENERATION_LIMIT * BS),
|
||||
m_sao_limit_max(MAX_MAP_GENERATION_LIMIT * BS),
|
||||
m_sao_limit_calculated(false)
|
||||
|
||||
mapgen_edge_min(-MAX_MAP_GENERATION_LIMIT),
|
||||
mapgen_edge_max(MAX_MAP_GENERATION_LIMIT),
|
||||
m_mapgen_edges_calculated(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -150,13 +154,12 @@ struct MapgenParams {
|
||||
virtual void readParams(const Settings *settings);
|
||||
virtual void writeParams(Settings *settings) const;
|
||||
|
||||
bool saoPosOverLimit(const v3f &p);
|
||||
s32 getSpawnRangeMax();
|
||||
|
||||
private:
|
||||
void calcMapgenEdges();
|
||||
|
||||
float m_sao_limit_min;
|
||||
float m_sao_limit_max;
|
||||
bool m_sao_limit_calculated;
|
||||
bool m_mapgen_edges_calculated;
|
||||
};
|
||||
|
||||
|
||||
|
@ -57,13 +57,17 @@ MapgenV7::MapgenV7(int mapgenid, MapgenV7Params *params, EmergeManager *emerge)
|
||||
this->spflags = params->spflags;
|
||||
this->cave_width = params->cave_width;
|
||||
this->float_mount_density = params->float_mount_density;
|
||||
this->float_mount_height = params->float_mount_height;
|
||||
this->floatland_level = params->floatland_level;
|
||||
this->shadow_limit = params->shadow_limit;
|
||||
this->cavern_limit = params->cavern_limit;
|
||||
this->cavern_taper = params->cavern_taper;
|
||||
this->cavern_threshold = params->cavern_threshold;
|
||||
|
||||
// This is to avoid a divide-by-zero.
|
||||
// Parameter will be saved to map_meta.txt in limited form.
|
||||
params->float_mount_height = MYMAX(params->float_mount_height, 1.0f);
|
||||
this->float_mount_height = params->float_mount_height;
|
||||
|
||||
// 2D noise
|
||||
noise_terrain_base = new Noise(¶ms->np_terrain_base, seed, csize.X, csize.Z);
|
||||
noise_terrain_alt = new Noise(¶ms->np_terrain_alt, seed, csize.X, csize.Z);
|
||||
@ -376,7 +380,8 @@ float MapgenV7::baseTerrainLevelFromMap(int index)
|
||||
|
||||
bool MapgenV7::getMountainTerrainAtPoint(s16 x, s16 y, s16 z)
|
||||
{
|
||||
float mnt_h_n = NoisePerlin2D(&noise_mount_height->np, x, z, seed);
|
||||
float mnt_h_n =
|
||||
MYMAX(NoisePerlin2D(&noise_mount_height->np, x, z, seed), 1.0f);
|
||||
float density_gradient = -((float)y / mnt_h_n);
|
||||
float mnt_n = NoisePerlin3D(&noise_mountain->np, x, y, z, seed);
|
||||
|
||||
@ -386,7 +391,7 @@ bool MapgenV7::getMountainTerrainAtPoint(s16 x, s16 y, s16 z)
|
||||
|
||||
bool MapgenV7::getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y)
|
||||
{
|
||||
float mounthn = noise_mount_height->result[idx_xz];
|
||||
float mounthn = MYMAX(noise_mount_height->result[idx_xz], 1.0f);
|
||||
float density_gradient = -((float)y / mounthn);
|
||||
float mountn = noise_mountain->result[idx_xyz];
|
||||
|
||||
@ -415,7 +420,8 @@ void MapgenV7::floatBaseExtentFromMap(s16 *float_base_min, s16 *float_base_max,
|
||||
|
||||
float n_base = noise_floatland_base->result[idx_xz];
|
||||
if (n_base > 0.0f) {
|
||||
float n_base_height = noise_float_base_height->result[idx_xz];
|
||||
float n_base_height =
|
||||
MYMAX(noise_float_base_height->result[idx_xz], 1.0f);
|
||||
float amp = n_base * n_base_height;
|
||||
float ridge = n_base_height / 3.0f;
|
||||
base_min = floatland_level - amp / 1.5f;
|
||||
|
@ -249,18 +249,15 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
|
||||
int facedir = n.getFaceDir(nodemgr);
|
||||
u8 axisdir = facedir>>2;
|
||||
facedir&=0x03;
|
||||
for(std::vector<aabb3f>::const_iterator
|
||||
for (std::vector<aabb3f>::const_iterator
|
||||
i = fixed.begin();
|
||||
i != fixed.end(); ++i)
|
||||
{
|
||||
i != fixed.end(); ++i) {
|
||||
aabb3f box = *i;
|
||||
|
||||
if (nodebox.type == NODEBOX_LEVELED) {
|
||||
box.MaxEdge.Y = -BS/2 + BS*((float)1/LEVELED_MAX) * n.getLevel(nodemgr);
|
||||
}
|
||||
if (nodebox.type == NODEBOX_LEVELED)
|
||||
box.MaxEdge.Y = (-0.5f + n.getLevel(nodemgr) / 64.0f) * BS;
|
||||
|
||||
switch (axisdir)
|
||||
{
|
||||
switch (axisdir) {
|
||||
case 0:
|
||||
if(facedir == 1)
|
||||
{
|
||||
|
@ -103,8 +103,8 @@ enum Rotation {
|
||||
|
||||
#define LIQUID_INFINITY_MASK 0x80 //0b10000000
|
||||
|
||||
// mask for param2, now as for liquid
|
||||
#define LEVELED_MASK 0x3F
|
||||
// mask for leveled nodebox param2
|
||||
#define LEVELED_MASK 0x7F
|
||||
#define LEVELED_MAX LEVELED_MASK
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user