Compare commits
122 Commits
cheat-simp
...
cheat-mast
Author | SHA1 | Date | |
---|---|---|---|
|
094097ee71 | ||
|
87e08b1b3a | ||
|
b7ff40eea2 | ||
|
520293b4cb | ||
|
7b2687ffc6 | ||
|
4f5090ff68 | ||
|
735fc2a1f2 | ||
|
cf0bcebc76 | ||
|
49b65a5593 | ||
|
cc400581e2 | ||
|
584d00a01c | ||
|
3b4df956b1 | ||
|
de2c40c8fc | ||
|
7d3295e21f | ||
|
4f688d5616 | ||
|
3a5959ae6b | ||
|
62c10e3d08 | ||
|
04e5a65c65 | ||
|
01bc817fe0 | ||
|
0425c6b8c8 | ||
|
d6050bee51 | ||
|
684e70477d | ||
|
49ff1d2ea8 | ||
|
5dab742645 | ||
|
da80e8af8a | ||
|
99c9e7a986 | ||
|
f5a006dce7 | ||
|
64fe79b53b | ||
|
362323cdc2 | ||
|
9649e47214 | ||
|
d45e5da8ca | ||
|
4c0d4e4105 | ||
|
70a90bc83a | ||
|
142474196a | ||
|
5435b07d4e | ||
|
670f8afd18 | ||
|
8349a3db10 | ||
|
792752997c | ||
|
fad263dec9 | ||
|
7e50529867 | ||
|
6f2fe8a554 | ||
|
62872dabac | ||
|
05e9e128b9 | ||
|
b8fc6a1955 | ||
|
b4df0d67dd | ||
|
f77f19a941 | ||
|
63f4ee21b0 | ||
|
2992b774fe | ||
|
0a83c42dfd | ||
|
9146c6a50f | ||
|
f40f4143df | ||
|
02f82eca0b | ||
|
326b0faa5e | ||
|
fe510d90c1 | ||
|
aab3b18e4b | ||
|
3a772e7ed6 | ||
|
0ebaed430a | ||
|
549cfd9db8 | ||
|
ff2ceed381 | ||
|
e7b44c3295 | ||
|
30821ad8de | ||
|
e7396a0c50 | ||
|
2af47e6f5f | ||
|
2aad3be2cb | ||
|
f3b9d87076 | ||
|
345e1041a2 | ||
|
d7c1f6c92e | ||
|
0d6b58a772 | ||
|
9f6d84aee3 | ||
|
f6a97c5c8a | ||
|
4e652ea9dd | ||
|
026ad912af | ||
|
0bcc2f33eb | ||
|
2153965cf9 | ||
|
ca64f564cd | ||
|
189daf87a0 | ||
|
787cd15c14 | ||
|
8037eda42c | ||
|
7354d0f3d8 | ||
|
257626ceed | ||
|
d04c41ad80 | ||
|
18b921015a | ||
|
26c7e98e3d | ||
|
649eef9e4f | ||
|
770eb09adc | ||
|
fd71a7c163 | ||
|
f1d2bc0965 | ||
|
8a99c8c94a | ||
|
abd8a30c05 | ||
|
6e5109fd46 | ||
|
551c12391a | ||
|
2d9f0d344e | ||
|
b19241b9bc | ||
|
308bb69eef | ||
|
02cc257fe0 | ||
|
419799b831 | ||
|
03caa1e319 | ||
|
d677f292cc | ||
|
da298a26ff | ||
|
9c669016d1 | ||
|
e049405fdc | ||
|
4edf087090 | ||
|
2b5341c518 | ||
|
fd9f195fcc | ||
|
f470cb7270 | ||
|
2507d32afe | ||
|
2174298ffa | ||
|
5a03b1f5f9 | ||
|
83b12ed481 | ||
|
ab947bd582 | ||
|
36838ea22f | ||
|
6efb453cdb | ||
|
089f594582 | ||
|
f4fedfed07 | ||
|
8b1a844e69 | ||
|
18b914ac74 | ||
|
b312ab4455 | ||
|
c0dd4ea46a | ||
|
ea1ae07beb | ||
|
813d819d15 | ||
|
03c11a73d8 | ||
|
76eb3f2b7a |
31
.github/ISSUE_TEMPLATE.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
##### Issue type
|
||||||
|
<!-- Pick one below and delete others -->
|
||||||
|
- Bug report
|
||||||
|
- Feature request
|
||||||
|
- Documentation issue
|
||||||
|
- Build issue
|
||||||
|
|
||||||
|
##### Minetest version
|
||||||
|
<!--
|
||||||
|
Paste Minetest version between quotes below
|
||||||
|
If you are on a devel version, please add git commit hash
|
||||||
|
You can use `minetest --version` to find it.
|
||||||
|
-->
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
##### OS / Hardware
|
||||||
|
<!-- General information about your hardware and operating system -->
|
||||||
|
Operating system:
|
||||||
|
CPU:
|
||||||
|
|
||||||
|
<!-- For graphical issues only -->
|
||||||
|
GPU model:
|
||||||
|
OpenGL version:
|
||||||
|
|
||||||
|
##### Summary
|
||||||
|
<!-- Describe your problem here -->
|
||||||
|
|
||||||
|
##### Steps to reproduce
|
||||||
|
<!-- For bug reports or build issues, explain how the problem happened -->
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -86,6 +86,8 @@ locale/
|
|||||||
*.gch
|
*.gch
|
||||||
cmake-build-debug/
|
cmake-build-debug/
|
||||||
cmake-build-release/
|
cmake-build-release/
|
||||||
|
cmake_config.h
|
||||||
|
cmake_config_githash.h
|
||||||
|
|
||||||
## Android build files
|
## Android build files
|
||||||
build/android/src/main/assets
|
build/android/src/main/assets
|
||||||
|
@ -70,6 +70,15 @@ matrix:
|
|||||||
sources: &sources
|
sources: &sources
|
||||||
- llvm-toolchain-trusty-5.0
|
- llvm-toolchain-trusty-5.0
|
||||||
|
|
||||||
|
- env: PLATFORM=Unix COMPILER=clang-5.0 FREETYPE=0
|
||||||
|
compiler: clang
|
||||||
|
os: linux
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages: ['clang-5.0', 'clang++-5.0']
|
||||||
|
sources: &sources
|
||||||
|
- llvm-toolchain-trusty-5.0
|
||||||
|
|
||||||
- env: PLATFORM=Unix COMPILER=clang-5.0 VALGRIND=1
|
- env: PLATFORM=Unix COMPILER=clang-5.0 VALGRIND=1
|
||||||
compiler: clang
|
compiler: clang
|
||||||
os: linux
|
os: linux
|
||||||
|
@ -32,7 +32,7 @@ License of Minetest source code
|
|||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2017 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -7,7 +7,7 @@ Minetest
|
|||||||
|
|
||||||
An InfiniMiner/Minecraft inspired game.
|
An InfiniMiner/Minecraft inspired game.
|
||||||
|
|
||||||
Copyright (c) 2010-2017 Perttu Ahola <celeron55@gmail.com>
|
Copyright (c) 2010-2018 Perttu Ahola <celeron55@gmail.com>
|
||||||
and contributors (see source file comments and the version control log)
|
and contributors (see source file comments and the version control log)
|
||||||
|
|
||||||
In case you downloaded the source code:
|
In case you downloaded the source code:
|
||||||
|
@ -6,7 +6,8 @@ OS := $(shell uname)
|
|||||||
# GPROF = 1
|
# GPROF = 1
|
||||||
|
|
||||||
# build for build platform
|
# build for build platform
|
||||||
APP_PLATFORM = android-9
|
API = 14
|
||||||
|
APP_PLATFORM = android-$(API)
|
||||||
|
|
||||||
ANDR_ROOT = $(shell pwd)
|
ANDR_ROOT = $(shell pwd)
|
||||||
PROJ_ROOT = $(shell realpath $(ANDR_ROOT)/../..)
|
PROJ_ROOT = $(shell realpath $(ANDR_ROOT)/../..)
|
||||||
@ -30,7 +31,7 @@ TARGET_HOST = arm-linux
|
|||||||
TARGET_ABI = armeabi-v7a
|
TARGET_ABI = armeabi-v7a
|
||||||
TARGET_LIBDIR = armeabi-v7a
|
TARGET_LIBDIR = armeabi-v7a
|
||||||
TARGET_TOOLCHAIN = arm-linux-androideabi-
|
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_CXXFLAGS_ADDON = $(TARGET_CFLAGS_ADDON)
|
||||||
TARGET_ARCH = armv7
|
TARGET_ARCH = armv7
|
||||||
CROSS_PREFIX = arm-linux-androideabi-
|
CROSS_PREFIX = arm-linux-androideabi-
|
||||||
@ -131,7 +132,6 @@ SQLITE3_URL = https://www.sqlite.org/2017/$(SQLITE3_FOLDER).zip
|
|||||||
|
|
||||||
ANDROID_SDK = $(shell grep '^sdk\.dir' local.properties | sed 's/^.*=[[:space:]]*//')
|
ANDROID_SDK = $(shell grep '^sdk\.dir' local.properties | sed 's/^.*=[[:space:]]*//')
|
||||||
ANDROID_NDK = $(shell grep '^ndk\.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
|
#use interim target variable to switch leveldb on or off
|
||||||
ifeq ($(HAVE_LEVELDB),1)
|
ifeq ($(HAVE_LEVELDB),1)
|
||||||
@ -217,14 +217,10 @@ $(OPENAL_LIB): $(OPENAL_TIMESTAMP)
|
|||||||
if [ $$REFRESH -ne 0 ] ; then \
|
if [ $$REFRESH -ne 0 ] ; then \
|
||||||
echo "changed timestamp for openal detected building..."; \
|
echo "changed timestamp for openal detected building..."; \
|
||||||
cd ${OPENAL_DIR}; \
|
cd ${OPENAL_DIR}; \
|
||||||
|
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||||
|
export TARGET_ABI=${TARGET_ABI}; \
|
||||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} APP_ABI=${TARGET_ABI} \
|
NDK_APPLICATION_MK=${ANDR_ROOT}/jni/Deps.mk || exit 1; \
|
||||||
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; \
|
|
||||||
touch ${OPENAL_TIMESTAMP}; \
|
touch ${OPENAL_TIMESTAMP}; \
|
||||||
touch ${OPENAL_TIMESTAMP_INT}; \
|
touch ${OPENAL_TIMESTAMP_INT}; \
|
||||||
else \
|
else \
|
||||||
@ -248,7 +244,6 @@ ogg_download :
|
|||||||
git clone ${OGG_URL_GIT}|| exit 1; \
|
git clone ${OGG_URL_GIT}|| exit 1; \
|
||||||
cd libvorbis-libogg-android ; \
|
cd libvorbis-libogg-android ; \
|
||||||
patch -p1 < ${ANDR_ROOT}/patches/libvorbis-libogg-fpu.patch || exit 1; \
|
patch -p1 < ${ANDR_ROOT}/patches/libvorbis-libogg-fpu.patch || exit 1; \
|
||||||
sed -i 's-:-?-' jni/Application.mk; \
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ogg : $(OGG_LIB)
|
ogg : $(OGG_LIB)
|
||||||
@ -265,14 +260,10 @@ $(OGG_LIB): $(OGG_TIMESTAMP)
|
|||||||
if [ $$REFRESH -ne 0 ] ; then \
|
if [ $$REFRESH -ne 0 ] ; then \
|
||||||
echo "changed timestamp for ogg detected building..."; \
|
echo "changed timestamp for ogg detected building..."; \
|
||||||
cd ${OGG_DIR}; \
|
cd ${OGG_DIR}; \
|
||||||
|
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||||
|
export TARGET_ABI=${TARGET_ABI}; \
|
||||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
NDK_APPLICATION_MK=${ANDR_ROOT}/jni/Deps.mk || exit 1; \
|
||||||
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; \
|
|
||||||
touch ${OGG_TIMESTAMP}; \
|
touch ${OGG_TIMESTAMP}; \
|
||||||
touch ${OGG_TIMESTAMP_INT}; \
|
touch ${OGG_TIMESTAMP_INT}; \
|
||||||
else \
|
else \
|
||||||
@ -317,7 +308,7 @@ $(OPENSSL_LIB): $(OPENSSL_TIMESTAMP) $(GMP_LIB)
|
|||||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-openssl; \
|
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-openssl; \
|
||||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||||
--platform=android-9 \
|
--platform=${APP_PLATFORM} \
|
||||||
--install-dir=$${TOOLCHAIN}; \
|
--install-dir=$${TOOLCHAIN}; \
|
||||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
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 enable-gmp -DL_ENDIAN -I${GMP_DIR} -L${GMP_DIR}/usr/lib android-${TARGET_ARCH};\
|
||||||
@ -368,7 +359,7 @@ $(LEVELDB_LIB): $(LEVELDB_TIMESTAMP)
|
|||||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-leveldb; \
|
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-leveldb; \
|
||||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||||
--platform=android-9 \
|
--platform=${APP_PLATFORM} \
|
||||||
--install-dir=$${TOOLCHAIN}; \
|
--install-dir=$${TOOLCHAIN}; \
|
||||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||||
export CC=${CROSS_PREFIX}gcc; \
|
export CC=${CROSS_PREFIX}gcc; \
|
||||||
@ -420,14 +411,10 @@ $(FREETYPE_LIB) : $(FREETYPE_TIMESTAMP)
|
|||||||
mkdir -p ${FREETYPE_DIR}; \
|
mkdir -p ${FREETYPE_DIR}; \
|
||||||
echo "changed timestamp for freetype detected building..."; \
|
echo "changed timestamp for freetype detected building..."; \
|
||||||
cd ${FREETYPE_DIR}/Android/jni; \
|
cd ${FREETYPE_DIR}/Android/jni; \
|
||||||
|
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||||
|
export TARGET_ABI=${TARGET_ABI}; \
|
||||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
NDK_APPLICATION_MK=${ANDR_ROOT}/jni/Deps.mk || exit 1; \
|
||||||
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; \
|
|
||||||
touch ${FREETYPE_TIMESTAMP}; \
|
touch ${FREETYPE_TIMESTAMP}; \
|
||||||
touch ${FREETYPE_TIMESTAMP_INT}; \
|
touch ${FREETYPE_TIMESTAMP_INT}; \
|
||||||
else \
|
else \
|
||||||
@ -478,9 +465,10 @@ $(ICONV_LIB) : $(ICONV_TIMESTAMP)
|
|||||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-iconv; \
|
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-iconv; \
|
||||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||||
--platform=android-9 \
|
--platform=${APP_PLATFORM} \
|
||||||
--install-dir=$${TOOLCHAIN}; \
|
--install-dir=$${TOOLCHAIN}; \
|
||||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||||
|
export CFLAGS="$${CFLAGS} ${TARGET_CFLAGS_ADDON}"; \
|
||||||
export CC=${CROSS_PREFIX}gcc; \
|
export CC=${CROSS_PREFIX}gcc; \
|
||||||
export CXX=${CROSS_PREFIX}g++; \
|
export CXX=${CROSS_PREFIX}g++; \
|
||||||
export TARGET_OS=OS_ANDROID_CROSSCOMPILE; \
|
export TARGET_OS=OS_ANDROID_CROSSCOMPILE; \
|
||||||
@ -513,6 +501,7 @@ irrlicht_download :
|
|||||||
patch -p1 < ${ANDR_ROOT}/patches/irrlicht-touchcount.patch || exit 1; \
|
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-back_button.patch || exit 1; \
|
||||||
patch -p1 < ${ANDR_ROOT}/patches/irrlicht-texturehack.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
|
fi
|
||||||
|
|
||||||
$(IRRLICHT_TIMESTAMP) : irrlicht_download
|
$(IRRLICHT_TIMESTAMP) : irrlicht_download
|
||||||
@ -538,14 +527,10 @@ $(IRRLICHT_LIB): $(IRRLICHT_TIMESTAMP) $(FREETYPE_LIB)
|
|||||||
mkdir -p ${IRRLICHT_DIR}; \
|
mkdir -p ${IRRLICHT_DIR}; \
|
||||||
echo "changed timestamp for irrlicht detected building..."; \
|
echo "changed timestamp for irrlicht detected building..."; \
|
||||||
cd deps/irrlicht/source/Irrlicht/Android; \
|
cd deps/irrlicht/source/Irrlicht/Android; \
|
||||||
|
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||||
|
export TARGET_ABI=${TARGET_ABI}; \
|
||||||
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
${ANDROID_NDK}/ndk-build NDEBUG=${NDEBUG} \
|
||||||
NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
NDK_APPLICATION_MK=${ANDR_ROOT}/jni/Irrlicht.mk || exit 1; \
|
||||||
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; \
|
|
||||||
touch ${IRRLICHT_TIMESTAMP}; \
|
touch ${IRRLICHT_TIMESTAMP}; \
|
||||||
touch ${IRRLICHT_TIMESTAMP_INT}; \
|
touch ${IRRLICHT_TIMESTAMP_INT}; \
|
||||||
else \
|
else \
|
||||||
@ -593,7 +578,7 @@ $(CURL_LIB): $(CURL_TIMESTAMP) $(OPENSSL_LIB)
|
|||||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-curl; \
|
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-curl; \
|
||||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||||
--platform=android-9 \
|
--platform=${APP_PLATFORM} \
|
||||||
--install-dir=$${TOOLCHAIN}; \
|
--install-dir=$${TOOLCHAIN}; \
|
||||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||||
export CC=${CROSS_PREFIX}gcc; \
|
export CC=${CROSS_PREFIX}gcc; \
|
||||||
@ -653,7 +638,7 @@ $(GMP_LIB): $(GMP_TIMESTAMP)
|
|||||||
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-gmp; \
|
export TOOLCHAIN=/tmp/ndk-${TARGET_HOST}-gmp; \
|
||||||
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh \
|
||||||
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
|
||||||
--platform=android-9 \
|
--platform=${APP_PLATFORM} \
|
||||||
--install-dir=$${TOOLCHAIN}; \
|
--install-dir=$${TOOLCHAIN}; \
|
||||||
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
|
||||||
export CC=${CROSS_PREFIX}gcc; \
|
export CC=${CROSS_PREFIX}gcc; \
|
||||||
@ -767,15 +752,11 @@ clean_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) $(GMP_LIB) $(LEVELDB_TARGET) \
|
||||||
$(OPENAL_LIB) $(OGG_LIB) prep_srcdir $(ANDR_ROOT)/jni/src/android_version.h \
|
$(OPENAL_LIB) $(OGG_LIB) prep_srcdir $(ANDR_ROOT)/jni/src/android_version.h \
|
||||||
$(ANDR_ROOT)/jni/src/android_version_githash.h sqlite3_download
|
$(ANDR_ROOT)/jni/src/android_version_githash.h sqlite3_download
|
||||||
+ @${ANDROID_NDK}/ndk-build NDK_MODULE_PATH=${NDK_MODULE_PATH} \
|
+ @export TARGET_LIBDIR=${TARGET_LIBDIR}; \
|
||||||
GPROF=${GPROF} APP_ABI=${TARGET_ABI} HAVE_LEVELDB=${HAVE_LEVELDB} \
|
export HAVE_LEVELDB=${HAVE_LEVELDB}; \
|
||||||
APP_PLATFORM=${APP_PLATFORM} \
|
export APP_PLATFORM=${APP_PLATFORM}; \
|
||||||
PRIVATE_CC=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}gcc \
|
export TARGET_ABI=${TARGET_ABI}; \
|
||||||
PRIVATE_CXX=${NDK_MODULE_PATH}/${TARGET_TOOLCHAIN}${COMPILER_VERSION}/prebuilt/linux-x86_64/bin/${TARGET_TOOLCHAIN}g++ \
|
${ANDROID_NDK}/ndk-build || exit 1; \
|
||||||
TARGET_LIBDIR=${TARGET_LIBDIR} \
|
|
||||||
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
|
|
||||||
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
|
|
||||||
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" || exit 1; \
|
|
||||||
if [ ! -e ${APP_ROOT}/jniLibs ]; then \
|
if [ ! -e ${APP_ROOT}/jniLibs ]; then \
|
||||||
ln -s ${ANDR_ROOT}/libs ${APP_ROOT}/jniLibs || exit 1; \
|
ln -s ${ANDR_ROOT}/libs ${APP_ROOT}/jniLibs || exit 1; \
|
||||||
fi; \
|
fi; \
|
||||||
|
@ -16,8 +16,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
versionCode 17
|
versionCode 17
|
||||||
versionName "${System.env.VERSION_STR}.${versionCode}"
|
versionName "${System.env.VERSION_STR}.${versionCode}"
|
||||||
minSdkVersion 9
|
minSdkVersion 14
|
||||||
targetSdkVersion 9
|
targetSdkVersion 14
|
||||||
applicationId "net.minetest.minetest"
|
applicationId "net.minetest.minetest"
|
||||||
manifestPlaceholders = [ package: "net.minetest.minetest", project: project.name ]
|
manifestPlaceholders = [ package: "net.minetest.minetest", project: project.name ]
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,7 @@ LOCAL_SRC_FILES := \
|
|||||||
jni/src/gui/guiTable.cpp \
|
jni/src/gui/guiTable.cpp \
|
||||||
jni/src/guiscalingfilter.cpp \
|
jni/src/guiscalingfilter.cpp \
|
||||||
jni/src/gui/guiVolumeChange.cpp \
|
jni/src/gui/guiVolumeChange.cpp \
|
||||||
|
jni/src/gui/profilergraph.cpp \
|
||||||
jni/src/httpfetch.cpp \
|
jni/src/httpfetch.cpp \
|
||||||
jni/src/hud.cpp \
|
jni/src/hud.cpp \
|
||||||
jni/src/imagefilters.cpp \
|
jni/src/imagefilters.cpp \
|
||||||
@ -270,6 +271,7 @@ LOCAL_SRC_FILES := \
|
|||||||
jni/src/settings.cpp \
|
jni/src/settings.cpp \
|
||||||
jni/src/wieldmesh.cpp \
|
jni/src/wieldmesh.cpp \
|
||||||
jni/src/client/clientlauncher.cpp \
|
jni/src/client/clientlauncher.cpp \
|
||||||
|
jni/src/client/hud.cpp \
|
||||||
jni/src/client/inputhandler.cpp \
|
jni/src/client/inputhandler.cpp \
|
||||||
jni/src/client/renderingengine.cpp \
|
jni/src/client/renderingengine.cpp \
|
||||||
jni/src/client/tile.cpp \
|
jni/src/client/tile.cpp \
|
||||||
@ -325,6 +327,7 @@ LOCAL_SRC_FILES += \
|
|||||||
jni/src/script/lua_api/l_noise.cpp \
|
jni/src/script/lua_api/l_noise.cpp \
|
||||||
jni/src/script/lua_api/l_object.cpp \
|
jni/src/script/lua_api/l_object.cpp \
|
||||||
jni/src/script/lua_api/l_particles.cpp \
|
jni/src/script/lua_api/l_particles.cpp \
|
||||||
|
jni/src/script/lua_api/l_particles_local.cpp\
|
||||||
jni/src/script/lua_api/l_rollback.cpp \
|
jni/src/script/lua_api/l_rollback.cpp \
|
||||||
jni/src/script/lua_api/l_server.cpp \
|
jni/src/script/lua_api/l_server.cpp \
|
||||||
jni/src/script/lua_api/l_settings.cpp \
|
jni/src/script/lua_api/l_settings.cpp \
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# NDK_TOOLCHAIN_VERSION := clang3.8
|
APP_PLATFORM := ${APP_PLATFORM}
|
||||||
|
APP_ABI := ${TARGET_ABI}
|
||||||
APP_PLATFORM := android-9
|
|
||||||
APP_MODULES := minetest
|
|
||||||
APP_STL := gnustl_static
|
APP_STL := gnustl_static
|
||||||
|
NDK_TOOLCHAIN_VERSION := 4.9
|
||||||
|
APP_DEPRECATED_HEADERS := true
|
||||||
|
APP_MODULES := minetest
|
||||||
|
|
||||||
APP_CPPFLAGS += -fexceptions
|
APP_CPPFLAGS += -fexceptions
|
||||||
APP_GNUSTL_FORCE_CPP_FEATURES := rtti
|
APP_GNUSTL_FORCE_CPP_FEATURES := rtti
|
||||||
|
|
||||||
|
8
build/android/jni/Deps.mk
Normal file
8
build/android/jni/Deps.mk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
APP_PLATFORM := ${APP_PLATFORM}
|
||||||
|
APP_ABI := ${TARGET_ABI}
|
||||||
|
APP_STL := gnustl_static
|
||||||
|
NDK_TOOLCHAIN_VERSION := 4.9
|
||||||
|
APP_DEPRECATED_HEADERS := true
|
||||||
|
|
||||||
|
APP_CLAFGS += -mfloat-abi=softfp -mfpu=vfpv3 -O3
|
||||||
|
APP_CPPFLAGS += -fexceptions
|
9
build/android/jni/Irrlicht.mk
Normal file
9
build/android/jni/Irrlicht.mk
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
APP_PLATFORM := ${APP_PLATFORM}
|
||||||
|
APP_ABI := ${TARGET_ABI}
|
||||||
|
APP_STL := gnustl_static
|
||||||
|
NDK_TOOLCHAIN_VERSION := 4.9
|
||||||
|
APP_DEPRECATED_HEADERS := true
|
||||||
|
APP_MODULES := Irrlicht
|
||||||
|
|
||||||
|
APP_CLAFGS += -mfloat-abi=softfp -mfpu=vfpv3 -O3
|
||||||
|
APP_CPPFLAGS += -fexceptions
|
12
build/android/patches/irrlicht-native_activity.patch
Normal file
12
build/android/patches/irrlicht-native_activity.patch
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
--- irrlicht/source/Irrlicht/CEGLManager.cpp.orig 2017-11-15 18:19:58.467279274 +0000
|
||||||
|
+++ irrlicht/source/Irrlicht/CEGLManager.cpp 2017-11-15 18:19:54.175279087 +0000
|
||||||
|
@@ -8,6 +8,9 @@
|
||||||
|
|
||||||
|
#include "irrString.h"
|
||||||
|
#include "os.h"
|
||||||
|
+#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
|
||||||
|
+#include <android/native_activity.h>
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
namespace irr
|
||||||
|
{
|
@ -10,6 +10,7 @@ public class MtNativeActivity extends NativeActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
m_MessagReturnCode = -1;
|
m_MessagReturnCode = -1;
|
||||||
m_MessageReturnValue = "";
|
m_MessageReturnValue = "";
|
||||||
|
|
||||||
|
@ -60,7 +60,6 @@ end
|
|||||||
|
|
||||||
core.registered_globalsteps, core.register_globalstep = make_registration()
|
core.registered_globalsteps, core.register_globalstep = make_registration()
|
||||||
core.registered_on_shutdown, core.register_on_shutdown = make_registration()
|
core.registered_on_shutdown, core.register_on_shutdown = make_registration()
|
||||||
core.registered_on_connect, core.register_on_connect = make_registration()
|
|
||||||
core.registered_on_receiving_chat_message, core.register_on_receiving_chat_message = make_registration()
|
core.registered_on_receiving_chat_message, core.register_on_receiving_chat_message = make_registration()
|
||||||
core.registered_on_sending_chat_message, core.register_on_sending_chat_message = make_registration()
|
core.registered_on_sending_chat_message, core.register_on_sending_chat_message = make_registration()
|
||||||
core.registered_on_death, core.register_on_death = make_registration()
|
core.registered_on_death, core.register_on_death = make_registration()
|
||||||
|
@ -551,7 +551,7 @@ end
|
|||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
if INIT == "mainmenu" then
|
if INIT == "mainmenu" then
|
||||||
function core.get_game(index)
|
function core.get_game(index)
|
||||||
local games = game.get_games()
|
local games = core.get_games()
|
||||||
|
|
||||||
if index > 0 and index <= #games then
|
if index > 0 and index <= #games then
|
||||||
return games[index]
|
return games[index]
|
||||||
@ -670,6 +670,7 @@ end
|
|||||||
-- Returns the exact coordinate of a pointed surface
|
-- Returns the exact coordinate of a pointed surface
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
function core.pointed_thing_to_face_pos(placer, pointed_thing)
|
function core.pointed_thing_to_face_pos(placer, pointed_thing)
|
||||||
|
local eye_height = placer:get_properties().eye_height
|
||||||
local eye_offset_first = placer:get_eye_offset()
|
local eye_offset_first = placer:get_eye_offset()
|
||||||
local node_pos = pointed_thing.under
|
local node_pos = pointed_thing.under
|
||||||
local camera_pos = placer:get_pos()
|
local camera_pos = placer:get_pos()
|
||||||
@ -689,7 +690,7 @@ function core.pointed_thing_to_face_pos(placer, pointed_thing)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local fine_pos = {[nc] = node_pos[nc] + offset}
|
local fine_pos = {[nc] = node_pos[nc] + offset}
|
||||||
camera_pos.y = camera_pos.y + 1.625 + eye_offset_first.y / 10
|
camera_pos.y = camera_pos.y + eye_height + eye_offset_first.y / 10
|
||||||
local f = (node_pos[nc] + offset - camera_pos[nc]) / look_dir[nc]
|
local f = (node_pos[nc] + offset - camera_pos[nc]) / look_dir[nc]
|
||||||
|
|
||||||
for i = 1, #oc do
|
for i = 1, #oc do
|
||||||
|
@ -63,34 +63,13 @@ function vector.distance(a, b)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vector.direction(pos1, pos2)
|
function vector.direction(pos1, pos2)
|
||||||
local x_raw = pos2.x - pos1.x
|
return vector.normalize({
|
||||||
local y_raw = pos2.y - pos1.y
|
x = pos2.x - pos1.x,
|
||||||
local z_raw = pos2.z - pos1.z
|
y = pos2.y - pos1.y,
|
||||||
local x_abs = math.abs(x_raw)
|
z = pos2.z - pos1.z
|
||||||
local y_abs = math.abs(y_raw)
|
})
|
||||||
local z_abs = math.abs(z_raw)
|
|
||||||
if x_abs >= y_abs and
|
|
||||||
x_abs >= z_abs then
|
|
||||||
y_raw = y_raw * (1 / x_abs)
|
|
||||||
z_raw = z_raw * (1 / x_abs)
|
|
||||||
x_raw = x_raw / x_abs
|
|
||||||
end
|
|
||||||
if y_abs >= x_abs and
|
|
||||||
y_abs >= z_abs then
|
|
||||||
x_raw = x_raw * (1 / y_abs)
|
|
||||||
z_raw = z_raw * (1 / y_abs)
|
|
||||||
y_raw = y_raw / y_abs
|
|
||||||
end
|
|
||||||
if z_abs >= y_abs and
|
|
||||||
z_abs >= x_abs then
|
|
||||||
x_raw = x_raw * (1 / z_abs)
|
|
||||||
y_raw = y_raw * (1 / z_abs)
|
|
||||||
z_raw = z_raw / z_abs
|
|
||||||
end
|
|
||||||
return {x=x_raw, y=y_raw, z=z_raw}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function vector.add(a, b)
|
function vector.add(a, b)
|
||||||
if type(b) == "table" then
|
if type(b) == "table" then
|
||||||
return {x = a.x + b.x,
|
return {x = a.x + b.x,
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
-- Minetest: builtin/auth.lua
|
-- Minetest: builtin/auth.lua
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Authentication handler
|
-- Builtin authentication handler
|
||||||
--
|
--
|
||||||
|
|
||||||
core.auth_file_path = core.get_worldpath().."/auth.txt"
|
local auth_file_path = core.get_worldpath().."/auth.txt"
|
||||||
core.auth_table = {}
|
local auth_table = {}
|
||||||
|
|
||||||
local function read_auth_file()
|
local function read_auth_file()
|
||||||
local newtable = {}
|
local newtable = {}
|
||||||
local file, errmsg = io.open(core.auth_file_path, 'rb')
|
local file, errmsg = io.open(auth_file_path, 'rb')
|
||||||
if not file then
|
if not file then
|
||||||
core.log("info", core.auth_file_path.." could not be opened for reading ("..errmsg.."); assuming new world")
|
core.log("info", auth_file_path.." could not be opened for reading ("..errmsg.."); assuming new world")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for line in file:lines() do
|
for line in file:lines() do
|
||||||
@ -27,14 +27,14 @@ local function read_auth_file()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
io.close(file)
|
io.close(file)
|
||||||
core.auth_table = newtable
|
auth_table = newtable
|
||||||
core.notify_authentication_modified()
|
core.notify_authentication_modified()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function save_auth_file()
|
local function save_auth_file()
|
||||||
local newtable = {}
|
local newtable = {}
|
||||||
-- Check table for validness before attempting to save
|
-- Check table for validness before attempting to save
|
||||||
for name, stuff in pairs(core.auth_table) do
|
for name, stuff in pairs(auth_table) do
|
||||||
assert(type(name) == "string")
|
assert(type(name) == "string")
|
||||||
assert(name ~= "")
|
assert(name ~= "")
|
||||||
assert(type(stuff) == "table")
|
assert(type(stuff) == "table")
|
||||||
@ -43,13 +43,13 @@ local function save_auth_file()
|
|||||||
assert(stuff.last_login == nil or type(stuff.last_login) == "number")
|
assert(stuff.last_login == nil or type(stuff.last_login) == "number")
|
||||||
end
|
end
|
||||||
local content = ""
|
local content = ""
|
||||||
for name, stuff in pairs(core.auth_table) do
|
for name, stuff in pairs(auth_table) do
|
||||||
local priv_string = core.privs_to_string(stuff.privileges)
|
local priv_string = core.privs_to_string(stuff.privileges)
|
||||||
local parts = {name, stuff.password, priv_string, stuff.last_login or ""}
|
local parts = {name, stuff.password, priv_string, stuff.last_login or ""}
|
||||||
content = content .. table.concat(parts, ":") .. "\n"
|
content = content .. table.concat(parts, ":") .. "\n"
|
||||||
end
|
end
|
||||||
if not core.safe_file_write(core.auth_file_path, content) then
|
if not core.safe_file_write(auth_file_path, content) then
|
||||||
error(core.auth_file_path.." could not be written to")
|
error(auth_file_path.." could not be written to")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -63,13 +63,13 @@ core.builtin_auth_handler = {
|
|||||||
-- usually empty too)
|
-- usually empty too)
|
||||||
local new_password_hash = ""
|
local new_password_hash = ""
|
||||||
-- If not in authentication table, return nil
|
-- If not in authentication table, return nil
|
||||||
if not core.auth_table[name] then
|
if not auth_table[name] then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
-- Figure out what privileges the player should have.
|
-- Figure out what privileges the player should have.
|
||||||
-- Take a copy of the privilege table
|
-- Take a copy of the privilege table
|
||||||
local privileges = {}
|
local privileges = {}
|
||||||
for priv, _ in pairs(core.auth_table[name].privileges) do
|
for priv, _ in pairs(auth_table[name].privileges) do
|
||||||
privileges[priv] = true
|
privileges[priv] = true
|
||||||
end
|
end
|
||||||
-- If singleplayer, give all privileges except those marked as give_to_singleplayer = false
|
-- If singleplayer, give all privileges except those marked as give_to_singleplayer = false
|
||||||
@ -89,31 +89,41 @@ core.builtin_auth_handler = {
|
|||||||
end
|
end
|
||||||
-- All done
|
-- All done
|
||||||
return {
|
return {
|
||||||
password = core.auth_table[name].password,
|
password = auth_table[name].password,
|
||||||
privileges = privileges,
|
privileges = privileges,
|
||||||
-- Is set to nil if unknown
|
-- Is set to nil if unknown
|
||||||
last_login = core.auth_table[name].last_login,
|
last_login = auth_table[name].last_login,
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
create_auth = function(name, password)
|
create_auth = function(name, password)
|
||||||
assert(type(name) == "string")
|
assert(type(name) == "string")
|
||||||
assert(type(password) == "string")
|
assert(type(password) == "string")
|
||||||
core.log('info', "Built-in authentication handler adding player '"..name.."'")
|
core.log('info', "Built-in authentication handler adding player '"..name.."'")
|
||||||
core.auth_table[name] = {
|
auth_table[name] = {
|
||||||
password = password,
|
password = password,
|
||||||
privileges = core.string_to_privs(core.settings:get("default_privs")),
|
privileges = core.string_to_privs(core.settings:get("default_privs")),
|
||||||
last_login = os.time(),
|
last_login = os.time(),
|
||||||
}
|
}
|
||||||
save_auth_file()
|
save_auth_file()
|
||||||
end,
|
end,
|
||||||
|
delete_auth = function(name)
|
||||||
|
assert(type(name) == "string")
|
||||||
|
if not auth_table[name] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
core.log('info', "Built-in authentication handler deleting player '"..name.."'")
|
||||||
|
auth_table[name] = nil
|
||||||
|
save_auth_file()
|
||||||
|
return true
|
||||||
|
end,
|
||||||
set_password = function(name, password)
|
set_password = function(name, password)
|
||||||
assert(type(name) == "string")
|
assert(type(name) == "string")
|
||||||
assert(type(password) == "string")
|
assert(type(password) == "string")
|
||||||
if not core.auth_table[name] then
|
if not auth_table[name] then
|
||||||
core.builtin_auth_handler.create_auth(name, password)
|
core.builtin_auth_handler.create_auth(name, password)
|
||||||
else
|
else
|
||||||
core.log('info', "Built-in authentication handler setting password of player '"..name.."'")
|
core.log('info', "Built-in authentication handler setting password of player '"..name.."'")
|
||||||
core.auth_table[name].password = password
|
auth_table[name].password = password
|
||||||
save_auth_file()
|
save_auth_file()
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
@ -121,7 +131,7 @@ core.builtin_auth_handler = {
|
|||||||
set_privileges = function(name, privileges)
|
set_privileges = function(name, privileges)
|
||||||
assert(type(name) == "string")
|
assert(type(name) == "string")
|
||||||
assert(type(privileges) == "table")
|
assert(type(privileges) == "table")
|
||||||
if not core.auth_table[name] then
|
if not auth_table[name] then
|
||||||
core.builtin_auth_handler.create_auth(name,
|
core.builtin_auth_handler.create_auth(name,
|
||||||
core.get_password_hash(name,
|
core.get_password_hash(name,
|
||||||
core.settings:get("default_password")))
|
core.settings:get("default_password")))
|
||||||
@ -129,19 +139,19 @@ core.builtin_auth_handler = {
|
|||||||
|
|
||||||
-- Run grant callbacks
|
-- Run grant callbacks
|
||||||
for priv, _ in pairs(privileges) do
|
for priv, _ in pairs(privileges) do
|
||||||
if not core.auth_table[name].privileges[priv] then
|
if not auth_table[name].privileges[priv] then
|
||||||
core.run_priv_callbacks(name, priv, nil, "grant")
|
core.run_priv_callbacks(name, priv, nil, "grant")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Run revoke callbacks
|
-- Run revoke callbacks
|
||||||
for priv, _ in pairs(core.auth_table[name].privileges) do
|
for priv, _ in pairs(auth_table[name].privileges) do
|
||||||
if not privileges[priv] then
|
if not privileges[priv] then
|
||||||
core.run_priv_callbacks(name, priv, nil, "revoke")
|
core.run_priv_callbacks(name, priv, nil, "revoke")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
core.auth_table[name].privileges = privileges
|
auth_table[name].privileges = privileges
|
||||||
core.notify_authentication_modified(name)
|
core.notify_authentication_modified(name)
|
||||||
save_auth_file()
|
save_auth_file()
|
||||||
end,
|
end,
|
||||||
@ -151,11 +161,41 @@ core.builtin_auth_handler = {
|
|||||||
end,
|
end,
|
||||||
record_login = function(name)
|
record_login = function(name)
|
||||||
assert(type(name) == "string")
|
assert(type(name) == "string")
|
||||||
assert(core.auth_table[name]).last_login = os.time()
|
assert(auth_table[name]).last_login = os.time()
|
||||||
save_auth_file()
|
save_auth_file()
|
||||||
end,
|
end,
|
||||||
|
iterate = function()
|
||||||
|
local names = {}
|
||||||
|
for k in pairs(auth_table) do
|
||||||
|
names[k] = true
|
||||||
|
end
|
||||||
|
return pairs(names)
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core.register_on_prejoinplayer(function(name, ip)
|
||||||
|
if core.registered_auth_handler ~= nil then
|
||||||
|
return -- Don't do anything if custom auth handler registered
|
||||||
|
end
|
||||||
|
if auth_table[name] ~= nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local name_lower = name:lower()
|
||||||
|
for k in pairs(auth_table) do
|
||||||
|
if k:lower() == name_lower then
|
||||||
|
return string.format("\nCannot create new player called '%s'. "..
|
||||||
|
"Another account called '%s' is already registered. "..
|
||||||
|
"Please check the spelling if it's your account "..
|
||||||
|
"or use a different nickname.", name, k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Authentication API
|
||||||
|
--
|
||||||
|
|
||||||
function core.register_authentication_handler(handler)
|
function core.register_authentication_handler(handler)
|
||||||
if core.registered_auth_handler then
|
if core.registered_auth_handler then
|
||||||
error("Add-on authentication handler already registered by "..core.registered_auth_handler_modname)
|
error("Add-on authentication handler already registered by "..core.registered_auth_handler_modname)
|
||||||
@ -181,28 +221,10 @@ end
|
|||||||
|
|
||||||
core.set_player_password = auth_pass("set_password")
|
core.set_player_password = auth_pass("set_password")
|
||||||
core.set_player_privs = auth_pass("set_privileges")
|
core.set_player_privs = auth_pass("set_privileges")
|
||||||
|
core.remove_player_auth = auth_pass("delete_auth")
|
||||||
core.auth_reload = auth_pass("reload")
|
core.auth_reload = auth_pass("reload")
|
||||||
|
|
||||||
|
|
||||||
local record_login = auth_pass("record_login")
|
local record_login = auth_pass("record_login")
|
||||||
|
|
||||||
core.register_on_joinplayer(function(player)
|
core.register_on_joinplayer(function(player)
|
||||||
record_login(player:get_player_name())
|
record_login(player:get_player_name())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
core.register_on_prejoinplayer(function(name, ip)
|
|
||||||
local auth = core.auth_table
|
|
||||||
if auth[name] ~= nil then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local name_lower = name:lower()
|
|
||||||
for k in pairs(auth) do
|
|
||||||
if k:lower() == name_lower then
|
|
||||||
return string.format("\nCannot create new player called '%s'. "..
|
|
||||||
"Another account called '%s' is already registered. "..
|
|
||||||
"Please check the spelling if it's your account "..
|
|
||||||
"or use a different nickname.", name, k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
@ -71,7 +71,7 @@ end
|
|||||||
--
|
--
|
||||||
core.register_chatcommand("me", {
|
core.register_chatcommand("me", {
|
||||||
params = "<action>",
|
params = "<action>",
|
||||||
description = "Display chat action (e.g., '/me orders a pizza' displays"
|
description = "Show chat action (e.g., '/me orders a pizza' displays"
|
||||||
.. " '<player name> orders a pizza')",
|
.. " '<player name> orders a pizza')",
|
||||||
privs = {shout=true},
|
privs = {shout=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
@ -82,7 +82,7 @@ core.register_chatcommand("me", {
|
|||||||
core.register_chatcommand("admin", {
|
core.register_chatcommand("admin", {
|
||||||
description = "Show the name of the server owner",
|
description = "Show the name of the server owner",
|
||||||
func = function(name)
|
func = function(name)
|
||||||
local admin = minetest.settings:get("name")
|
local admin = core.settings:get("name")
|
||||||
if admin then
|
if admin then
|
||||||
return true, "The administrator of this server is "..admin.."."
|
return true, "The administrator of this server is "..admin.."."
|
||||||
else
|
else
|
||||||
@ -93,7 +93,7 @@ core.register_chatcommand("admin", {
|
|||||||
|
|
||||||
core.register_chatcommand("privs", {
|
core.register_chatcommand("privs", {
|
||||||
params = "[<name>]",
|
params = "[<name>]",
|
||||||
description = "Print privileges of player",
|
description = "Show privileges of yourself or another player",
|
||||||
func = function(caller, param)
|
func = function(caller, param)
|
||||||
param = param:trim()
|
param = param:trim()
|
||||||
local name = (param ~= "" and param or caller)
|
local name = (param ~= "" and param or caller)
|
||||||
@ -104,7 +104,7 @@ core.register_chatcommand("privs", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
local function handle_grant_command(caller, grantname, grantprivstr)
|
local function handle_grant_command(caller, grantname, grantprivstr)
|
||||||
local caller_privs = minetest.get_player_privs(caller)
|
local caller_privs = core.get_player_privs(caller)
|
||||||
if not (caller_privs.privs or caller_privs.basic_privs) then
|
if not (caller_privs.privs or caller_privs.basic_privs) then
|
||||||
return false, "Your privileges are insufficient."
|
return false, "Your privileges are insufficient."
|
||||||
end
|
end
|
||||||
@ -149,7 +149,7 @@ end
|
|||||||
|
|
||||||
core.register_chatcommand("grant", {
|
core.register_chatcommand("grant", {
|
||||||
params = "<name> (<privilege> | all)",
|
params = "<name> (<privilege> | all)",
|
||||||
description = "Give privilege to player",
|
description = "Give privileges to player",
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
|
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
|
||||||
if not grantname or not grantprivstr then
|
if not grantname or not grantprivstr then
|
||||||
@ -172,7 +172,7 @@ core.register_chatcommand("grantme", {
|
|||||||
|
|
||||||
core.register_chatcommand("revoke", {
|
core.register_chatcommand("revoke", {
|
||||||
params = "<name> (<privilege> | all)",
|
params = "<name> (<privilege> | all)",
|
||||||
description = "Remove privilege from player",
|
description = "Remove privileges from player",
|
||||||
privs = {},
|
privs = {},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if not core.check_player_privs(name, {privs=true}) and
|
if not core.check_player_privs(name, {privs=true}) and
|
||||||
@ -263,7 +263,7 @@ core.register_chatcommand("setpassword", {
|
|||||||
|
|
||||||
core.register_chatcommand("clearpassword", {
|
core.register_chatcommand("clearpassword", {
|
||||||
params = "<name>",
|
params = "<name>",
|
||||||
description = "Set empty password",
|
description = "Set empty password for a player",
|
||||||
privs = {password=true},
|
privs = {password=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
local toname = param
|
local toname = param
|
||||||
@ -290,7 +290,7 @@ core.register_chatcommand("auth_reload", {
|
|||||||
|
|
||||||
core.register_chatcommand("remove_player", {
|
core.register_chatcommand("remove_player", {
|
||||||
params = "<name>",
|
params = "<name>",
|
||||||
description = "Remove player data",
|
description = "Remove a player's data",
|
||||||
privs = {server=true},
|
privs = {server=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
local toname = param
|
local toname = param
|
||||||
@ -315,7 +315,7 @@ core.register_chatcommand("remove_player", {
|
|||||||
|
|
||||||
core.register_chatcommand("teleport", {
|
core.register_chatcommand("teleport", {
|
||||||
params = "<X>,<Y>,<Z> | <to_name> | (<name> <X>,<Y>,<Z>) | (<name> <to_name>)",
|
params = "<X>,<Y>,<Z> | <to_name> | (<name> <X>,<Y>,<Z>) | (<name> <to_name>)",
|
||||||
description = "Teleport to player or position",
|
description = "Teleport to position or player",
|
||||||
privs = {teleport=true},
|
privs = {teleport=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
-- Returns (pos, true) if found, otherwise (pos, false)
|
-- Returns (pos, true) if found, otherwise (pos, false)
|
||||||
@ -588,7 +588,7 @@ local function handle_give_command(cmd, giver, receiver, stackstring)
|
|||||||
end
|
end
|
||||||
|
|
||||||
core.register_chatcommand("give", {
|
core.register_chatcommand("give", {
|
||||||
params = "<name> <ItemString>",
|
params = "<name> <ItemString> [<count> [<wear>]]",
|
||||||
description = "Give item to player",
|
description = "Give item to player",
|
||||||
privs = {give=true},
|
privs = {give=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
@ -601,7 +601,7 @@ core.register_chatcommand("give", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
core.register_chatcommand("giveme", {
|
core.register_chatcommand("giveme", {
|
||||||
params = "<ItemString>",
|
params = "<ItemString> [<count> [<wear>]]",
|
||||||
description = "Give item to yourself",
|
description = "Give item to yourself",
|
||||||
privs = {give=true},
|
privs = {give=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
@ -629,7 +629,7 @@ core.register_chatcommand("spawnentity", {
|
|||||||
core.log("error", "Unable to spawn entity, player is nil")
|
core.log("error", "Unable to spawn entity, player is nil")
|
||||||
return false, "Unable to spawn entity, player is nil"
|
return false, "Unable to spawn entity, player is nil"
|
||||||
end
|
end
|
||||||
if not minetest.registered_entities[entityname] then
|
if not core.registered_entities[entityname] then
|
||||||
return false, "Cannot spawn an unknown entity"
|
return false, "Cannot spawn an unknown entity"
|
||||||
end
|
end
|
||||||
if p == "" then
|
if p == "" then
|
||||||
@ -766,15 +766,15 @@ core.register_chatcommand("rollback", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
core.register_chatcommand("status", {
|
core.register_chatcommand("status", {
|
||||||
description = "Print server status",
|
description = "Show server status",
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
return true, core.get_server_status()
|
return true, core.get_server_status()
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
core.register_chatcommand("time", {
|
core.register_chatcommand("time", {
|
||||||
params = "<0..23>:<0..59> | <0..24000>",
|
params = "[<0..23>:<0..59> | <0..24000>]",
|
||||||
description = "Set time of day",
|
description = "Show or set time of day",
|
||||||
privs = {},
|
privs = {},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if param == "" then
|
if param == "" then
|
||||||
@ -813,7 +813,7 @@ core.register_chatcommand("time", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
core.register_chatcommand("days", {
|
core.register_chatcommand("days", {
|
||||||
description = "Display day count",
|
description = "Show day count since world creation",
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
return true, "Current day is " .. core.get_day_count()
|
return true, "Current day is " .. core.get_day_count()
|
||||||
end
|
end
|
||||||
@ -839,12 +839,17 @@ core.register_chatcommand("shutdown", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
core.register_chatcommand("ban", {
|
core.register_chatcommand("ban", {
|
||||||
params = "<name>",
|
params = "[<name> | <IP_address>]",
|
||||||
description = "Ban IP of player",
|
description = "Ban player or show ban list",
|
||||||
privs = {ban=true},
|
privs = {ban=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if param == "" then
|
if param == "" then
|
||||||
return true, "Ban list: " .. core.get_ban_list()
|
local ban_list = core.get_ban_list()
|
||||||
|
if ban_list == "" then
|
||||||
|
return true, "The ban list is empty."
|
||||||
|
else
|
||||||
|
return true, "Ban list: " .. ban_list
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if not core.get_player_by_name(param) then
|
if not core.get_player_by_name(param) then
|
||||||
return false, "No such player."
|
return false, "No such player."
|
||||||
@ -860,7 +865,7 @@ core.register_chatcommand("ban", {
|
|||||||
|
|
||||||
core.register_chatcommand("unban", {
|
core.register_chatcommand("unban", {
|
||||||
params = "<name> | <IP_address>",
|
params = "<name> | <IP_address>",
|
||||||
description = "Remove IP ban",
|
description = "Remove player ban",
|
||||||
privs = {ban=true},
|
privs = {ban=true},
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if not core.unban_player_or_ip(param) then
|
if not core.unban_player_or_ip(param) then
|
||||||
@ -938,7 +943,7 @@ core.register_chatcommand("msg", {
|
|||||||
|
|
||||||
core.register_chatcommand("last-login", {
|
core.register_chatcommand("last-login", {
|
||||||
params = "[<name>]",
|
params = "[<name>]",
|
||||||
description = "Get the last login time of a player",
|
description = "Get the last login time of a player or yourself",
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if param == "" then
|
if param == "" then
|
||||||
param = name
|
param = name
|
||||||
@ -961,7 +966,7 @@ core.register_chatcommand("clearinv", {
|
|||||||
if param and param ~= "" and param ~= name then
|
if param and param ~= "" and param ~= name then
|
||||||
if not core.check_player_privs(name, {server=true}) then
|
if not core.check_player_privs(name, {server=true}) then
|
||||||
return false, "You don't have permission"
|
return false, "You don't have permission"
|
||||||
.. " to run this command (missing privilege: server)"
|
.. " to clear another player's inventory (missing privilege: server)"
|
||||||
end
|
end
|
||||||
player = core.get_player_by_name(param)
|
player = core.get_player_by_name(param)
|
||||||
core.chat_send_player(param, name.." cleared your inventory.")
|
core.chat_send_player(param, name.." cleared your inventory.")
|
||||||
@ -980,3 +985,34 @@ core.register_chatcommand("clearinv", {
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local function handle_kill_command(killer, victim)
|
||||||
|
if core.settings:get_bool("enable_damage") == false then
|
||||||
|
return false, "Players can't be killed, damage has been disabled."
|
||||||
|
end
|
||||||
|
local victimref = core.get_player_by_name(victim)
|
||||||
|
if victimref == nil then
|
||||||
|
return false, string.format("Player %s is not online.", victim)
|
||||||
|
elseif victimref:get_hp() <= 0 then
|
||||||
|
if killer == victim then
|
||||||
|
return false, "You are already dead."
|
||||||
|
else
|
||||||
|
return false, string.format("%s is already dead.", victim)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not killer == victim then
|
||||||
|
core.log("action", string.format("%s killed %s", killer, victim))
|
||||||
|
end
|
||||||
|
-- Kill victim
|
||||||
|
victimref:set_hp(0)
|
||||||
|
return true, string.format("%s has been killed.", victim)
|
||||||
|
end
|
||||||
|
|
||||||
|
core.register_chatcommand("kill", {
|
||||||
|
params = "[<name>]",
|
||||||
|
description = "Kill player or yourself",
|
||||||
|
privs = {server=true},
|
||||||
|
func = function(name, param)
|
||||||
|
return handle_kill_command(name, param == "" and name or param)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
@ -150,8 +150,22 @@ end
|
|||||||
|
|
||||||
local function drop_attached_node(p)
|
local function drop_attached_node(p)
|
||||||
local n = core.get_node(p)
|
local n = core.get_node(p)
|
||||||
|
local drops = core.get_node_drops(n, "")
|
||||||
|
local def = core.registered_items[n.name]
|
||||||
|
if def and def.preserve_metadata then
|
||||||
|
local oldmeta = core.get_meta(p):to_table().fields
|
||||||
|
-- Copy pos and node because the callback can modify them.
|
||||||
|
local pos_copy = {x=p.x, y=p.y, z=p.z}
|
||||||
|
local node_copy = {name=n.name, param1=n.param1, param2=n.param2}
|
||||||
|
local drop_stacks = {}
|
||||||
|
for k, v in pairs(drops) do
|
||||||
|
drop_stacks[k] = ItemStack(v)
|
||||||
|
end
|
||||||
|
drops = drop_stacks
|
||||||
|
def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
|
||||||
|
end
|
||||||
core.remove_node(p)
|
core.remove_node(p)
|
||||||
for _, item in pairs(core.get_node_drops(n, "")) do
|
for _, item in pairs(drops) do
|
||||||
local pos = {
|
local pos = {
|
||||||
x = p.x + math.random()/2 - 0.25,
|
x = p.x + math.random()/2 - 0.25,
|
||||||
y = p.y + math.random()/2 - 0.25,
|
y = p.y + math.random()/2 - 0.25,
|
||||||
|
@ -516,7 +516,8 @@ function core.handle_node_drops(pos, drops, digger)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
give_item = function(item)
|
give_item = function(item)
|
||||||
return item
|
-- itemstring to ItemStack for left:is_empty()
|
||||||
|
return ItemStack(item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -578,6 +579,20 @@ function core.node_dig(pos, node, digger)
|
|||||||
digger:set_wielded_item(wielded)
|
digger:set_wielded_item(wielded)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check to see if metadata should be preserved.
|
||||||
|
if def and def.preserve_metadata then
|
||||||
|
local oldmeta = core.get_meta(pos):to_table().fields
|
||||||
|
-- Copy pos and node because the callback can modify them.
|
||||||
|
local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
|
||||||
|
local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
|
||||||
|
local drop_stacks = {}
|
||||||
|
for k, v in pairs(drops) do
|
||||||
|
drop_stacks[k] = ItemStack(v)
|
||||||
|
end
|
||||||
|
drops = drop_stacks
|
||||||
|
def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
|
||||||
|
end
|
||||||
|
|
||||||
-- Handle drops
|
-- Handle drops
|
||||||
core.handle_node_drops(pos, drops, digger)
|
core.handle_node_drops(pos, drops, digger)
|
||||||
|
|
||||||
|
@ -147,9 +147,9 @@ core.register_entity(":__builtin:item", {
|
|||||||
})
|
})
|
||||||
local vel = self.object:getvelocity()
|
local vel = self.object:getvelocity()
|
||||||
local def = node and core.registered_nodes[node.name]
|
local def = node and core.registered_nodes[node.name]
|
||||||
-- Ignore is nil -> stop until the block loaded
|
-- Avoid entity falling into ignore nodes or unloaded areas
|
||||||
local is_moving = (def and not def.walkable) or
|
local is_moving = node and node.name ~= "ignore" and
|
||||||
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
|
((def and not def.walkable) or vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0)
|
||||||
local is_slippery = false
|
local is_slippery = false
|
||||||
|
|
||||||
if def and def.walkable then
|
if def and def.walkable then
|
||||||
|
@ -5,12 +5,11 @@
|
|||||||
--
|
--
|
||||||
|
|
||||||
function core.check_player_privs(name, ...)
|
function core.check_player_privs(name, ...)
|
||||||
local arg_type = type(name)
|
if core.is_player(name) then
|
||||||
if (arg_type == "userdata" or arg_type == "table") and
|
|
||||||
name.get_player_name then -- If it quacks like a Player...
|
|
||||||
name = name:get_player_name()
|
name = name:get_player_name()
|
||||||
elseif arg_type ~= "string" then
|
elseif type(name) ~= "string" then
|
||||||
error("Invalid core.check_player_privs argument type: " .. arg_type, 2)
|
error("core.check_player_privs expects a player or playername as " ..
|
||||||
|
"argument.", 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
local requested_privs = {...}
|
local requested_privs = {...}
|
||||||
@ -40,14 +39,17 @@ function core.check_player_privs(name, ...)
|
|||||||
return true, ""
|
return true, ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local player_list = {}
|
local player_list = {}
|
||||||
|
|
||||||
|
|
||||||
function core.send_join_message(player_name)
|
function core.send_join_message(player_name)
|
||||||
if not minetest.is_singleplayer() then
|
if not minetest.is_singleplayer() then
|
||||||
core.chat_send_all("*** " .. player_name .. " joined the game.")
|
core.chat_send_all("*** " .. player_name .. " joined the game.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.send_leave_message(player_name, timed_out)
|
function core.send_leave_message(player_name, timed_out)
|
||||||
local announcement = "*** " .. player_name .. " left the game."
|
local announcement = "*** " .. player_name .. " left the game."
|
||||||
if timed_out then
|
if timed_out then
|
||||||
@ -56,18 +58,21 @@ function core.send_leave_message(player_name, timed_out)
|
|||||||
core.chat_send_all(announcement)
|
core.chat_send_all(announcement)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
core.register_on_joinplayer(function(player)
|
core.register_on_joinplayer(function(player)
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
player_list[player_name] = player
|
player_list[player_name] = player
|
||||||
core.send_join_message(player_name)
|
core.send_join_message(player_name)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
core.register_on_leaveplayer(function(player, timed_out)
|
core.register_on_leaveplayer(function(player, timed_out)
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
player_list[player_name] = nil
|
player_list[player_name] = nil
|
||||||
core.send_leave_message(player_name, timed_out)
|
core.send_leave_message(player_name, timed_out)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
function core.get_connected_players()
|
function core.get_connected_players()
|
||||||
local temp_table = {}
|
local temp_table = {}
|
||||||
for index, value in pairs(player_list) do
|
for index, value in pairs(player_list) do
|
||||||
@ -78,12 +83,24 @@ function core.get_connected_players()
|
|||||||
return temp_table
|
return temp_table
|
||||||
end
|
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)
|
function minetest.player_exists(name)
|
||||||
return minetest.get_auth_handler().get_auth(name) ~= nil
|
return minetest.get_auth_handler().get_auth(name) ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Returns two position vectors representing a box of `radius` in each
|
-- Returns two position vectors representing a box of `radius` in each
|
||||||
-- direction centered around the player corresponding to `player_name`
|
-- direction centered around the player corresponding to `player_name`
|
||||||
|
|
||||||
function core.get_player_radius_area(player_name, radius)
|
function core.get_player_radius_area(player_name, radius)
|
||||||
local player = core.get_player_by_name(player_name)
|
local player = core.get_player_by_name(player_name)
|
||||||
if player == nil then
|
if player == nil then
|
||||||
@ -101,10 +118,12 @@ function core.get_player_radius_area(player_name, radius)
|
|||||||
return p1, p2
|
return p1, p2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.hash_node_position(pos)
|
function core.hash_node_position(pos)
|
||||||
return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
|
return (pos.z+32768)*65536*65536 + (pos.y+32768)*65536 + pos.x+32768
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.get_position_from_hash(hash)
|
function core.get_position_from_hash(hash)
|
||||||
local pos = {}
|
local pos = {}
|
||||||
pos.x = (hash%65536) - 32768
|
pos.x = (hash%65536) - 32768
|
||||||
@ -115,6 +134,7 @@ function core.get_position_from_hash(hash)
|
|||||||
return pos
|
return pos
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.get_item_group(name, group)
|
function core.get_item_group(name, group)
|
||||||
if not core.registered_items[name] or not
|
if not core.registered_items[name] or not
|
||||||
core.registered_items[name].groups[group] then
|
core.registered_items[name].groups[group] then
|
||||||
@ -123,11 +143,13 @@ function core.get_item_group(name, group)
|
|||||||
return core.registered_items[name].groups[group]
|
return core.registered_items[name].groups[group]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.get_node_group(name, group)
|
function core.get_node_group(name, group)
|
||||||
core.log("deprecated", "Deprecated usage of get_node_group, use get_item_group instead")
|
core.log("deprecated", "Deprecated usage of get_node_group, use get_item_group instead")
|
||||||
return core.get_item_group(name, group)
|
return core.get_item_group(name, group)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.setting_get_pos(name)
|
function core.setting_get_pos(name)
|
||||||
local value = core.settings:get(name)
|
local value = core.settings:get(name)
|
||||||
if not value then
|
if not value then
|
||||||
@ -136,17 +158,64 @@ function core.setting_get_pos(name)
|
|||||||
return core.string_to_pos(value)
|
return core.string_to_pos(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- To be overriden by protection mods
|
-- To be overriden by protection mods
|
||||||
|
|
||||||
function core.is_protected(pos, name)
|
function core.is_protected(pos, name)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.record_protection_violation(pos, name)
|
function core.record_protection_violation(pos, name)
|
||||||
for _, func in pairs(core.registered_on_protection_violation) do
|
for _, func in pairs(core.registered_on_protection_violation) do
|
||||||
func(pos, name)
|
func(pos, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Checks if specified volume intersects a protected volume
|
||||||
|
|
||||||
|
function core.intersects_protection(minp, maxp, player_name, interval)
|
||||||
|
-- 'interval' is the largest allowed interval for the 3D lattice of checks.
|
||||||
|
|
||||||
|
-- Compute the optimal float step 'd' for each axis so that all corners and
|
||||||
|
-- borders are checked. 'd' will be smaller or equal to 'interval'.
|
||||||
|
-- Subtracting 1e-4 ensures that the max co-ordinate will be reached by the
|
||||||
|
-- for loop (which might otherwise not be the case due to rounding errors).
|
||||||
|
|
||||||
|
-- Default to 4
|
||||||
|
interval = interval or 4
|
||||||
|
local d = {}
|
||||||
|
|
||||||
|
for _, c in pairs({"x", "y", "z"}) do
|
||||||
|
if maxp[c] > minp[c] then
|
||||||
|
d[c] = (maxp[c] - minp[c]) /
|
||||||
|
math.ceil((maxp[c] - minp[c]) / interval) - 1e-4
|
||||||
|
elseif maxp[c] == minp[c] then
|
||||||
|
d[c] = 1 -- Any value larger than 0 to avoid division by zero
|
||||||
|
else -- maxp[c] < minp[c], print error and treat as protection intersected
|
||||||
|
minetest.log("error", "maxp < minp in 'minetest.intersects_protection()'")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for zf = minp.z, maxp.z, d.z do
|
||||||
|
local z = math.floor(zf + 0.5)
|
||||||
|
for yf = minp.y, maxp.y, d.y do
|
||||||
|
local y = math.floor(yf + 0.5)
|
||||||
|
for xf = minp.x, maxp.x, d.x do
|
||||||
|
local x = math.floor(xf + 0.5)
|
||||||
|
if core.is_protected({x = x, y = y, z = z}, player_name) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local raillike_ids = {}
|
local raillike_ids = {}
|
||||||
local raillike_cur_id = 0
|
local raillike_cur_id = 0
|
||||||
function core.raillike_group(name)
|
function core.raillike_group(name)
|
||||||
@ -159,7 +228,9 @@ function core.raillike_group(name)
|
|||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- HTTP callback interface
|
-- HTTP callback interface
|
||||||
|
|
||||||
function core.http_add_fetch(httpenv)
|
function core.http_add_fetch(httpenv)
|
||||||
httpenv.fetch = function(req, callback)
|
httpenv.fetch = function(req, callback)
|
||||||
local handle = httpenv.fetch_async(req)
|
local handle = httpenv.fetch_async(req)
|
||||||
@ -178,11 +249,12 @@ function core.http_add_fetch(httpenv)
|
|||||||
return httpenv
|
return httpenv
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.close_formspec(player_name, formname)
|
function core.close_formspec(player_name, formname)
|
||||||
return minetest.show_formspec(player_name, formname, "")
|
return minetest.show_formspec(player_name, formname, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.cancel_shutdown_requests()
|
function core.cancel_shutdown_requests()
|
||||||
core.request_shutdown("", false, -1)
|
core.request_shutdown("", false, -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ core.register_privilege("basic_privs", "Can modify 'shout' and 'interact' privil
|
|||||||
core.register_privilege("privs", "Can modify privileges")
|
core.register_privilege("privs", "Can modify privileges")
|
||||||
|
|
||||||
core.register_privilege("teleport", {
|
core.register_privilege("teleport", {
|
||||||
description = "Can use /teleport command",
|
description = "Can teleport self",
|
||||||
give_to_singleplayer = false,
|
give_to_singleplayer = false,
|
||||||
})
|
})
|
||||||
core.register_privilege("bring", {
|
core.register_privilege("bring", {
|
||||||
@ -42,7 +42,7 @@ core.register_privilege("bring", {
|
|||||||
give_to_singleplayer = false,
|
give_to_singleplayer = false,
|
||||||
})
|
})
|
||||||
core.register_privilege("settime", {
|
core.register_privilege("settime", {
|
||||||
description = "Can use /time",
|
description = "Can set the time of day using /time",
|
||||||
give_to_singleplayer = false,
|
give_to_singleplayer = false,
|
||||||
})
|
})
|
||||||
core.register_privilege("server", {
|
core.register_privilege("server", {
|
||||||
@ -74,15 +74,15 @@ core.register_privilege("password", {
|
|||||||
give_to_admin = true,
|
give_to_admin = true,
|
||||||
})
|
})
|
||||||
core.register_privilege("fly", {
|
core.register_privilege("fly", {
|
||||||
description = "Can fly using the free_move mode",
|
description = "Can use fly mode",
|
||||||
give_to_singleplayer = false,
|
give_to_singleplayer = false,
|
||||||
})
|
})
|
||||||
core.register_privilege("fast", {
|
core.register_privilege("fast", {
|
||||||
description = "Can walk fast using the fast_move mode",
|
description = "Can use fast mode",
|
||||||
give_to_singleplayer = false,
|
give_to_singleplayer = false,
|
||||||
})
|
})
|
||||||
core.register_privilege("noclip", {
|
core.register_privilege("noclip", {
|
||||||
description = "Can fly through walls",
|
description = "Can fly through solid nodes using noclip mode",
|
||||||
give_to_singleplayer = false,
|
give_to_singleplayer = false,
|
||||||
})
|
})
|
||||||
core.register_privilege("rollback", {
|
core.register_privilege("rollback", {
|
||||||
|
@ -15,11 +15,42 @@
|
|||||||
--with this program; if not, write to the Free Software Foundation, Inc.,
|
--with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
local worldname = ""
|
||||||
|
|
||||||
local function create_world_formspec(dialogdata)
|
local function create_world_formspec(dialogdata)
|
||||||
local mapgens = core.get_mapgen_names()
|
local mapgens = core.get_mapgen_names()
|
||||||
|
|
||||||
local current_seed = core.settings:get("fixed_map_seed") or ""
|
local current_seed = core.settings:get("fixed_map_seed") or ""
|
||||||
local current_mg = core.settings:get("mg_name")
|
local current_mg = core.settings:get("mg_name")
|
||||||
|
local gameid = core.settings:get("menu_last_game")
|
||||||
|
|
||||||
|
local game, gameidx = nil , 0
|
||||||
|
if gameid ~= nil then
|
||||||
|
game, gameidx = gamemgr.find_by_gameid(gameid)
|
||||||
|
|
||||||
|
if gameidx == nil then
|
||||||
|
gameidx = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local game_by_gameidx = core.get_game(gameidx)
|
||||||
|
if game_by_gameidx ~= nil then
|
||||||
|
local gamepath = game_by_gameidx.path
|
||||||
|
local gameconfig = Settings(gamepath.."/game.conf")
|
||||||
|
|
||||||
|
local disallowed_mapgens = (gameconfig:get("disallowed_mapgens") or ""):split()
|
||||||
|
for key, value in pairs(disallowed_mapgens) do
|
||||||
|
disallowed_mapgens[key] = value:trim()
|
||||||
|
end
|
||||||
|
|
||||||
|
if disallowed_mapgens then
|
||||||
|
for i = #mapgens, 1, -1 do
|
||||||
|
if table.indexof(disallowed_mapgens, mapgens[i]) > 0 then
|
||||||
|
table.remove(mapgens, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local mglist = ""
|
local mglist = ""
|
||||||
local selindex = 1
|
local selindex = 1
|
||||||
@ -32,23 +63,12 @@ local function create_world_formspec(dialogdata)
|
|||||||
mglist = mglist .. v .. ","
|
mglist = mglist .. v .. ","
|
||||||
end
|
end
|
||||||
mglist = mglist:sub(1, -2)
|
mglist = mglist:sub(1, -2)
|
||||||
|
|
||||||
local gameid = core.settings:get("menu_last_game")
|
|
||||||
|
|
||||||
local game, gameidx = nil , 0
|
|
||||||
if gameid ~= nil then
|
|
||||||
game, gameidx = gamemgr.find_by_gameid(gameid)
|
|
||||||
|
|
||||||
if gameidx == nil then
|
|
||||||
gameidx = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
current_seed = core.formspec_escape(current_seed)
|
current_seed = core.formspec_escape(current_seed)
|
||||||
local retval =
|
local retval =
|
||||||
"size[11.5,6.5,true]" ..
|
"size[11.5,6.5,true]" ..
|
||||||
"label[2,0;" .. fgettext("World name") .. "]"..
|
"label[2,0;" .. fgettext("World name") .. "]"..
|
||||||
"field[4.5,0.4;6,0.5;te_world_name;;]" ..
|
"field[4.5,0.4;6,0.5;te_world_name;;" .. minetest.formspec_escape(worldname) .. "]" ..
|
||||||
|
|
||||||
"label[2,1;" .. fgettext("Seed") .. "]"..
|
"label[2,1;" .. fgettext("Seed") .. "]"..
|
||||||
"field[4.5,1.4;6,0.5;te_seed;;".. current_seed .. "]" ..
|
"field[4.5,1.4;6,0.5;te_seed;;".. current_seed .. "]" ..
|
||||||
@ -121,10 +141,14 @@ local function create_world_buttonhandler(this, fields)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
worldname = fields.te_world_name
|
||||||
|
|
||||||
if fields["games"] then
|
if fields["games"] then
|
||||||
|
local gameindex = core.get_textlist_index("games")
|
||||||
|
core.settings:set("menu_last_game", gamemgr.games[gameindex].id)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields["world_create_cancel"] then
|
if fields["world_create_cancel"] then
|
||||||
this:delete()
|
this:delete()
|
||||||
return true
|
return true
|
||||||
@ -135,6 +159,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
function create_create_world_dlg(update_worldlistfilter)
|
function create_create_world_dlg(update_worldlistfilter)
|
||||||
|
worldname = ""
|
||||||
local retval = dialog_create("sp_create_world",
|
local retval = dialog_create("sp_create_world",
|
||||||
create_world_formspec,
|
create_world_formspec,
|
||||||
create_world_buttonhandler,
|
create_world_buttonhandler,
|
||||||
|
@ -752,6 +752,18 @@ local function handle_change_setting_buttons(this, fields)
|
|||||||
core.update_formspec(this:get_formspec())
|
core.update_formspec(this:get_formspec())
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
if setting.min and new_value < setting.min then
|
||||||
|
this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
|
||||||
|
this.data.entered_text = fields["te_setting_value"]
|
||||||
|
core.update_formspec(this:get_formspec())
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if setting.max and new_value > setting.max then
|
||||||
|
this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
|
||||||
|
this.data.entered_text = fields["te_setting_value"]
|
||||||
|
core.update_formspec(this:get_formspec())
|
||||||
|
return true
|
||||||
|
end
|
||||||
core.settings:set(setting.name, new_value)
|
core.settings:set(setting.name, new_value)
|
||||||
|
|
||||||
elseif setting.type == "flags" then
|
elseif setting.type == "flags" then
|
||||||
|
@ -310,7 +310,7 @@ end
|
|||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
return {
|
return {
|
||||||
name = "local",
|
name = "local",
|
||||||
caption = fgettext("Local Game"),
|
caption = fgettext("Start Game"),
|
||||||
cbf_formspec = get_formspec,
|
cbf_formspec = get_formspec,
|
||||||
cbf_button_handler = main_button_handler,
|
cbf_button_handler = main_button_handler,
|
||||||
on_change = on_change
|
on_change = on_change
|
||||||
|
@ -344,7 +344,7 @@ end
|
|||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
return {
|
return {
|
||||||
name = "online",
|
name = "online",
|
||||||
caption = fgettext("Play Online"),
|
caption = fgettext("Join Game"),
|
||||||
cbf_formspec = get_formspec,
|
cbf_formspec = get_formspec,
|
||||||
cbf_button_handler = main_button_handler,
|
cbf_button_handler = main_button_handler,
|
||||||
on_change = on_change
|
on_change = on_change
|
||||||
|
@ -235,7 +235,7 @@ local function formspec(tabview, name, tabdata)
|
|||||||
.. dump(core.settings:get_bool("enable_bumpmapping")) .. "]" ..
|
.. dump(core.settings:get_bool("enable_bumpmapping")) .. "]" ..
|
||||||
"checkbox[8.25,1;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
|
"checkbox[8.25,1;cb_tonemapping;" .. fgettext("Tone Mapping") .. ";"
|
||||||
.. dump(core.settings:get_bool("tone_mapping")) .. "]" ..
|
.. dump(core.settings:get_bool("tone_mapping")) .. "]" ..
|
||||||
"checkbox[8.25,1.5;cb_generate_normalmaps;" .. fgettext("Normal Mapping") .. ";"
|
"checkbox[8.25,1.5;cb_generate_normalmaps;" .. fgettext("Generate Normal Maps") .. ";"
|
||||||
.. dump(core.settings:get_bool("generate_normalmaps")) .. "]" ..
|
.. dump(core.settings:get_bool("generate_normalmaps")) .. "]" ..
|
||||||
"checkbox[8.25,2;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";"
|
"checkbox[8.25,2;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";"
|
||||||
.. dump(core.settings:get_bool("enable_parallax_occlusion")) .. "]" ..
|
.. dump(core.settings:get_bool("enable_parallax_occlusion")) .. "]" ..
|
||||||
@ -252,7 +252,7 @@ local function formspec(tabview, name, tabdata)
|
|||||||
"label[8.38,1.2;" .. core.colorize("#888888",
|
"label[8.38,1.2;" .. core.colorize("#888888",
|
||||||
fgettext("Tone Mapping")) .. "]" ..
|
fgettext("Tone Mapping")) .. "]" ..
|
||||||
"label[8.38,1.7;" .. core.colorize("#888888",
|
"label[8.38,1.7;" .. core.colorize("#888888",
|
||||||
fgettext("Normal Mapping")) .. "]" ..
|
fgettext("Generate Normal Maps")) .. "]" ..
|
||||||
"label[8.38,2.2;" .. core.colorize("#888888",
|
"label[8.38,2.2;" .. core.colorize("#888888",
|
||||||
fgettext("Parallax Occlusion")) .. "]" ..
|
fgettext("Parallax Occlusion")) .. "]" ..
|
||||||
"label[8.38,2.7;" .. core.colorize("#888888",
|
"label[8.38,2.7;" .. core.colorize("#888888",
|
||||||
|
@ -536,6 +536,9 @@ fps_max (Maximum FPS) int 60
|
|||||||
# Maximum FPS when game is paused.
|
# Maximum FPS when game is paused.
|
||||||
pause_fps_max (FPS in pause menu) int 20
|
pause_fps_max (FPS in pause menu) int 20
|
||||||
|
|
||||||
|
# Open the pause menu when the window's focus is lost. Does not pause if a formspec is open.
|
||||||
|
pause_on_lost_focus (Pause on lost window focus) bool false
|
||||||
|
|
||||||
# View distance in nodes.
|
# View distance in nodes.
|
||||||
viewing_range (Viewing range) int 100 20 4000
|
viewing_range (Viewing range) int 100 20 4000
|
||||||
|
|
||||||
@ -566,23 +569,31 @@ vsync (V-Sync) bool false
|
|||||||
# Field of view in degrees.
|
# Field of view in degrees.
|
||||||
fov (Field of view) int 72 30 160
|
fov (Field of view) int 72 30 160
|
||||||
|
|
||||||
# Field of view while zooming in degrees.
|
|
||||||
# Requires to be allowed by server-sided mods.
|
|
||||||
zoom_fov (Field of view for zoom) int 15 7 160
|
|
||||||
|
|
||||||
# Adjust the gamma encoding for the light tables. Higher numbers are brighter.
|
# Adjust the gamma encoding for the light tables. Higher numbers are brighter.
|
||||||
# This setting is for the client only and is ignored by the server.
|
# This setting is for the client only and is ignored by the server.
|
||||||
display_gamma (Gamma) float 1.0 0.5 3.0
|
display_gamma (Gamma) float 1.0 0.5 3.0
|
||||||
|
|
||||||
|
# Gradient of light curve at minimum light level.
|
||||||
lighting_alpha (Darkness sharpness) float 0.0 0.0 4.0
|
lighting_alpha (Darkness sharpness) float 0.0 0.0 4.0
|
||||||
|
|
||||||
lighting_beta (Lightness sharpness) float 0.0 0.0 4.0
|
# Gradient of light curve at maximum light level.
|
||||||
|
lighting_beta (Lightness sharpness) float 1.5 0.0 4.0
|
||||||
|
|
||||||
|
# Strength of light curve mid-boost.
|
||||||
|
lighting_boost (Light curve mid boost) float 0.2 0.0 1.0
|
||||||
|
|
||||||
|
# Center of light curve mid-boost.
|
||||||
|
lighting_boost_center (Light curve mid boost center) float 0.5 0.0 1.0
|
||||||
|
|
||||||
|
# Spread of light curve mid-boost.
|
||||||
|
# Standard deviation of the mid-boost gaussian.
|
||||||
|
lighting_boost_spread (Light curve mid boost spread) float 0.2 0.0 1.0
|
||||||
|
|
||||||
# Path to texture directory. All textures are first searched from here.
|
# Path to texture directory. All textures are first searched from here.
|
||||||
texture_path (Texture path) path
|
texture_path (Texture path) path
|
||||||
|
|
||||||
# The rendering back-end for Irrlicht.
|
# The rendering back-end for Irrlicht.
|
||||||
video_driver (Video driver) enum opengl null,software,burningsvideo,direct3d8,direct3d9,opengl
|
video_driver (Video driver) enum opengl null,software,burningsvideo,direct3d8,direct3d9,opengl,ogles1,ogles2
|
||||||
|
|
||||||
# Radius of cloud area stated in number of 64 node cloud squares.
|
# Radius of cloud area stated in number of 64 node cloud squares.
|
||||||
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
|
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
|
||||||
@ -608,7 +619,7 @@ fall_bobbing_amount (Fall bobbing factor) float 0.0
|
|||||||
3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,pageflip
|
3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,pageflip
|
||||||
|
|
||||||
# In-game chat console height, between 0.1 (10%) and 1.0 (100%).
|
# In-game chat console height, between 0.1 (10%) and 1.0 (100%).
|
||||||
console_height (Console height) float 1.0 0.1 1.0
|
console_height (Console height) float 0.6 0.1 1.0
|
||||||
|
|
||||||
# In-game chat console background color (R,G,B).
|
# In-game chat console background color (R,G,B).
|
||||||
console_color (Console color) string (0,0,0)
|
console_color (Console color) string (0,0,0)
|
||||||
@ -990,14 +1001,20 @@ kick_msg_crash (Crash message) string This server has experienced an internal er
|
|||||||
ask_reconnect_on_crash (Ask to reconnect after crash) bool false
|
ask_reconnect_on_crash (Ask to reconnect after crash) bool false
|
||||||
|
|
||||||
# From how far clients know about objects, stated in mapblocks (16 nodes).
|
# From how far clients know about objects, stated in mapblocks (16 nodes).
|
||||||
|
#
|
||||||
|
# Setting this larger than active_block_range will also cause the server
|
||||||
|
# to maintain active objects up to this distance in the direction the
|
||||||
|
# player is looking. (This can avoid mobs suddenly disappearing from view)
|
||||||
active_object_send_range_blocks (Active object send range) int 3
|
active_object_send_range_blocks (Active object send range) int 3
|
||||||
|
|
||||||
# How large area of blocks are subject to the active block stuff, stated in mapblocks (16 nodes).
|
# How large area of blocks are subject to the active block stuff, stated in mapblocks (16 nodes).
|
||||||
# In active blocks objects are loaded and ABMs run.
|
# In active blocks objects are loaded and ABMs run.
|
||||||
|
# This is also the minimum range in which active objects (mobs) are maintained.
|
||||||
|
# This should be configured together with active_object_range.
|
||||||
active_block_range (Active block range) int 3
|
active_block_range (Active block range) int 3
|
||||||
|
|
||||||
# From how far blocks are sent to clients, stated in mapblocks (16 nodes).
|
# From how far blocks are sent to clients, stated in mapblocks (16 nodes).
|
||||||
max_block_send_distance (Max block send distance) int 10
|
max_block_send_distance (Max block send distance) int 9
|
||||||
|
|
||||||
# Maximum number of forceloaded mapblocks.
|
# Maximum number of forceloaded mapblocks.
|
||||||
max_forceloaded_blocks (Maximum forceloaded blocks) int 16
|
max_forceloaded_blocks (Maximum forceloaded blocks) int 16
|
||||||
@ -1104,12 +1121,13 @@ server_side_occlusion_culling (Server side occlusion culling) bool true
|
|||||||
|
|
||||||
# Restricts the access of certain client-side functions on servers
|
# Restricts the access of certain client-side functions on servers
|
||||||
# Combine these byteflags below to restrict more client-side features:
|
# Combine these byteflags below to restrict more client-side features:
|
||||||
# LOOKUP_NODES_LIMIT: 1 (limits get_node call client-side to csm_flavour_noderange_limit)
|
# LOAD_CLIENT_MODS: 1 (disable client mods loading)
|
||||||
# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
|
# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
|
||||||
# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
|
# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
|
||||||
# READ_NODEDEFS: 8 (disable get_node_def call client-side)
|
# READ_NODEDEFS: 8 (disable get_node_def call client-side)
|
||||||
|
# LOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to csm_flavour_noderange_limit)
|
||||||
# type: int
|
# type: int
|
||||||
csm_flavour_limits (Client side modding flavour limits) int 3
|
csm_flavour_limits (Client side modding flavour limits) int 18
|
||||||
|
|
||||||
# If the CSM flavour for node range is enabled, get_node is limited to
|
# If the CSM flavour for node range is enabled, get_node is limited to
|
||||||
# this many nodes from the player.
|
# this many nodes from the player.
|
||||||
@ -1181,7 +1199,8 @@ name (Player name) string
|
|||||||
|
|
||||||
# Set the language. Leave empty to use the system language.
|
# Set the language. Leave empty to use the system language.
|
||||||
# A restart is required after changing this.
|
# A restart is required after changing this.
|
||||||
language (Language) enum ,be,ca,cs,da,de,en,eo,es,et,fr,he,hu,id,it,ja,jbo,ko,ky,lt,nb,nl,pl,pt,pt_BR,ro,ru,sr_Cyrl,tr,uk,zh_CN,zh_TW
|
language (Language) enum ,be,ca,cs,da,de,dv,en,eo,es,et,fr,he,hu,id,it,ja,jbo,ko,ky,lt,ms,nb,nl,pl,pt,pt_BR,ro,ru,sl,sr_Cyrl,sv,sw,tr,uk,zh_CN,zh_TW
|
||||||
|
|
||||||
|
|
||||||
# Level of logging to be written to debug.txt:
|
# Level of logging to be written to debug.txt:
|
||||||
# - <nothing> (no logging)
|
# - <nothing> (no logging)
|
||||||
@ -1193,6 +1212,13 @@ language (Language) enum ,be,ca,cs,da,de,en,eo,es,et,fr,he,hu,id,it,ja,jbo,ko,
|
|||||||
# - verbose
|
# - verbose
|
||||||
debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose
|
debug_log_level (Debug log level) enum action ,none,error,warning,action,info,verbose
|
||||||
|
|
||||||
|
# ANSI colored logs: red error log, yellow warning and grey info and verbose logs
|
||||||
|
# Note that it doesn't work on Windows
|
||||||
|
# "yes" always enables it,
|
||||||
|
# "detect" enables it when printing to terminal and
|
||||||
|
# "no" disables it
|
||||||
|
log_color (Colored logs) enum detect yes,detect,no
|
||||||
|
|
||||||
# IPv6 support.
|
# IPv6 support.
|
||||||
enable_ipv6 (IPv6) bool true
|
enable_ipv6 (IPv6) bool true
|
||||||
|
|
||||||
@ -1387,13 +1413,16 @@ mgv7_large_cave_depth (Large cave depth) int -33
|
|||||||
# Y of upper limit of lava in large caves.
|
# Y of upper limit of lava in large caves.
|
||||||
mgv7_lava_depth (Lava depth) int -256
|
mgv7_lava_depth (Lava depth) int -256
|
||||||
|
|
||||||
# Controls the density of floatland mountain terrain.
|
# Controls the density of mountain-type floatlands.
|
||||||
# Is an offset added to the 'np_mountain' noise value.
|
# Is a noise offset added to the 'mgv7_np_mountain' noise value.
|
||||||
mgv7_float_mount_density (Floatland mountain density) float 0.6
|
mgv7_float_mount_density (Floatland mountain density) float 0.6
|
||||||
|
|
||||||
# Typical maximum height, above and below midpoint, of floatland mountain terrain.
|
# Typical maximum height, above and below midpoint, of floatland mountains.
|
||||||
mgv7_float_mount_height (Floatland mountain height) float 128.0
|
mgv7_float_mount_height (Floatland mountain height) float 128.0
|
||||||
|
|
||||||
|
# Alters how mountain-type floatlands taper above and below midpoint.
|
||||||
|
mgv7_float_mount_exponent (Floatland mountain exponent) float 0.75
|
||||||
|
|
||||||
# Y-level of floatland midpoint and lake surface.
|
# Y-level of floatland midpoint and lake surface.
|
||||||
mgv7_floatland_level (Floatland level) int 1280
|
mgv7_floatland_level (Floatland level) int 1280
|
||||||
|
|
||||||
|
@ -7,22 +7,32 @@ dofile("preview:example.lua")
|
|||||||
core.register_on_shutdown(function()
|
core.register_on_shutdown(function()
|
||||||
print("[PREVIEW] shutdown client")
|
print("[PREVIEW] shutdown client")
|
||||||
end)
|
end)
|
||||||
|
local id = nil
|
||||||
|
|
||||||
core.register_on_connect(function()
|
local server_info = core.get_server_info()
|
||||||
print("[PREVIEW] Player connection completed")
|
print("Server version: " .. server_info.protocol_version)
|
||||||
local server_info = core.get_server_info()
|
print("Server ip: " .. server_info.ip)
|
||||||
print("Server version: " .. server_info.protocol_version)
|
print("Server address: " .. server_info.address)
|
||||||
print("Server ip: " .. server_info.ip)
|
print("Server port: " .. server_info.port)
|
||||||
print("Server address: " .. server_info.address)
|
mod_channel = core.mod_channel_join("experimental_preview")
|
||||||
print("Server port: " .. server_info.port)
|
|
||||||
|
|
||||||
mod_channel = core.mod_channel_join("experimental_preview")
|
core.after(4, function()
|
||||||
|
if mod_channel:is_writeable() then
|
||||||
|
mod_channel:send_all("preview talk to experimental")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
core.after(4, function()
|
core.after(1, function()
|
||||||
if mod_channel:is_writeable() then
|
id = core.localplayer:hud_add({
|
||||||
mod_channel:send_all("preview talk to experimental")
|
hud_elem_type = "text",
|
||||||
end
|
name = "example",
|
||||||
end)
|
number = 0xff0000,
|
||||||
|
position = {x=0, y=1},
|
||||||
|
offset = {x=8, y=-8},
|
||||||
|
text = "You are using the preview mod",
|
||||||
|
scale = {x=200, y=60},
|
||||||
|
alignment = {x=1, y=-1},
|
||||||
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
core.register_on_modchannel_message(function(channel, sender, message)
|
core.register_on_modchannel_message(function(channel, sender, message)
|
||||||
@ -184,3 +194,9 @@ core.register_chatcommand("privs", {
|
|||||||
return true, core.privs_to_string(minetest.get_privilege_list())
|
return true, core.privs_to_string(minetest.get_privilege_list())
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
core.register_chatcommand("text", {
|
||||||
|
func = function(param)
|
||||||
|
return core.localplayer:hud_change(id, "text", param)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
@ -6,7 +6,7 @@ Minetest Lua Client Modding API Reference 0.5.0
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
**WARNING: The client API is currently unstable, and may break/change without warning.**
|
** WARNING: The client API is currently unstable, and may break/change without warning. **
|
||||||
|
|
||||||
Content and functionality can be added to Minetest 0.4.15-dev+ by using Lua
|
Content and functionality can be added to Minetest 0.4.15-dev+ by using Lua
|
||||||
scripting in run-time loaded mods.
|
scripting in run-time loaded mods.
|
||||||
@ -14,7 +14,7 @@ scripting in run-time loaded mods.
|
|||||||
A mod is a self-contained bunch of scripts, textures and other related
|
A mod is a self-contained bunch of scripts, textures and other related
|
||||||
things that is loaded by and interfaces with Minetest.
|
things that is loaded by and interfaces with Minetest.
|
||||||
|
|
||||||
Transfering client-sided mods form the server to the client is planned, but not implemented yet.
|
Transferring client-sided mods from the server to the client is planned, but not implemented yet.
|
||||||
|
|
||||||
If you see a deficiency in the API, feel free to attempt to add the
|
If you see a deficiency in the API, feel free to attempt to add the
|
||||||
functionality in the engine and API. You can send such improvements as
|
functionality in the engine and API. You can send such improvements as
|
||||||
@ -626,7 +626,7 @@ Minetest namespace reference
|
|||||||
* `hash`: Full git version (only set if available), eg, "1.2.3-dev-01234567-dirty"
|
* `hash`: Full git version (only set if available), eg, "1.2.3-dev-01234567-dirty"
|
||||||
Use this for informational purposes only. The information in the returned
|
Use this for informational purposes only. The information in the returned
|
||||||
table does not represent the capabilities of the engine, nor is it
|
table does not represent the capabilities of the engine, nor is it
|
||||||
reliable or verifyable. Compatible forks will have a different name and
|
reliable or verifiable. Compatible forks will have a different name and
|
||||||
version entirely. To check for the presence of engine features, test
|
version entirely. To check for the presence of engine features, test
|
||||||
whether the functions exported by the wanted features exist. For example:
|
whether the functions exported by the wanted features exist. For example:
|
||||||
`if minetest.check_for_falling then ... end`.
|
`if minetest.check_for_falling then ... end`.
|
||||||
@ -651,8 +651,6 @@ Call these functions only at load time!
|
|||||||
* **Warning**: If the client terminates abnormally (i.e. crashes), the registered
|
* **Warning**: If the client terminates abnormally (i.e. crashes), the registered
|
||||||
callbacks **will likely not be run**. Data should be saved at
|
callbacks **will likely not be run**. Data should be saved at
|
||||||
semi-frequent intervals as well as on server shutdown.
|
semi-frequent intervals as well as on server shutdown.
|
||||||
* `minetest.register_on_connect(func())`
|
|
||||||
* Called at the end of client connection (when player is loaded onto map)
|
|
||||||
* `minetest.register_on_receiving_chat_message(func(message))`
|
* `minetest.register_on_receiving_chat_message(func(message))`
|
||||||
* Called always when a client receive a message
|
* Called always when a client receive a message
|
||||||
* Return `true` to mark the message as handled, which means that it will not be shown to chat
|
* Return `true` to mark the message as handled, which means that it will not be shown to chat
|
||||||
@ -727,7 +725,7 @@ Call these functions only at load time!
|
|||||||
* `minetest.get_node_or_nil(pos)`
|
* `minetest.get_node_or_nil(pos)`
|
||||||
* Returns the node at the given position as table in the format
|
* Returns the node at the given position as table in the format
|
||||||
`{name="node_name", param1=0, param2=0}`, returns `nil`
|
`{name="node_name", param1=0, param2=0}`, returns `nil`
|
||||||
for unloaded areas or flavour limited areas.
|
for unloaded areas or flavor limited areas.
|
||||||
* `minetest.find_node_near(pos, radius, nodenames, [search_center])`: returns pos or `nil`
|
* `minetest.find_node_near(pos, radius, nodenames, [search_center])`: returns pos or `nil`
|
||||||
* `radius`: using a maximum metric
|
* `radius`: using a maximum metric
|
||||||
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
* `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"`
|
||||||
@ -754,7 +752,7 @@ Call these functions only at load time!
|
|||||||
|
|
||||||
### Privileges
|
### Privileges
|
||||||
* `minetest.get_privilege_list()`
|
* `minetest.get_privilege_list()`
|
||||||
* Returns a list of privileges the currect player has in the format `{priv1=true,...}`
|
* Returns a list of privileges the current player has in the format `{priv1=true,...}`
|
||||||
* `minetest.string_to_privs(str)`: returns `{priv1=true,...}`
|
* `minetest.string_to_privs(str)`: returns `{priv1=true,...}`
|
||||||
* `minetest.privs_to_string(privs)`: returns `"priv1,priv2,..."`
|
* `minetest.privs_to_string(privs)`: returns `"priv1,priv2,..."`
|
||||||
* Convert between two privilege representations
|
* Convert between two privilege representations
|
||||||
@ -765,8 +763,6 @@ Call these functions only at load time!
|
|||||||
* `minetest.disconnect()`
|
* `minetest.disconnect()`
|
||||||
* Disconnect from the server and exit to main menu.
|
* Disconnect from the server and exit to main menu.
|
||||||
* Returns `false` if the client is already disconnecting otherwise returns `true`.
|
* Returns `false` if the client is already disconnecting otherwise returns `true`.
|
||||||
* `minetest.take_screenshot()`
|
|
||||||
* Take a screenshot.
|
|
||||||
* `minetest.get_server_info()`
|
* `minetest.get_server_info()`
|
||||||
* Returns [server info](#server-info).
|
* Returns [server info](#server-info).
|
||||||
* `minetest.send_respawn()`
|
* `minetest.send_respawn()`
|
||||||
@ -784,8 +780,16 @@ Call these functions only at load time!
|
|||||||
* Client joins channel `channel_name`, and creates it, if necessary. You
|
* Client joins channel `channel_name`, and creates it, if necessary. You
|
||||||
should listen from incoming messages with `minetest.register_on_modchannel_message`
|
should listen from incoming messages with `minetest.register_on_modchannel_message`
|
||||||
call to receive incoming messages. Warning, this function is asynchronous.
|
call to receive incoming messages. Warning, this function is asynchronous.
|
||||||
* You should use a minetest.register_on_connect(function() ... end) to perform
|
|
||||||
a successful channel join on client startup.
|
### Particles
|
||||||
|
* `minetest.add_particle(particle definition)`
|
||||||
|
|
||||||
|
* `minetest.add_particlespawner(particlespawner definition)`
|
||||||
|
* Add a `ParticleSpawner`, an object that spawns an amount of particles over `time` seconds
|
||||||
|
* Returns an `id`, and -1 if adding didn't succeed
|
||||||
|
|
||||||
|
* `minetest.delete_particlespawner(id)`
|
||||||
|
* Delete `ParticleSpawner` with `id` (return value from `minetest.add_particlespawner`)
|
||||||
|
|
||||||
### Misc.
|
### Misc.
|
||||||
* `minetest.parse_json(string[, nullvalue])`: returns something
|
* `minetest.parse_json(string[, nullvalue])`: returns something
|
||||||
@ -870,9 +874,9 @@ An interface to use mod channels on client and server
|
|||||||
* No more incoming or outgoing messages can be sent to this channel from client mods.
|
* No more incoming or outgoing messages can be sent to this channel from client mods.
|
||||||
* This invalidate all future object usage
|
* This invalidate all future object usage
|
||||||
* Ensure your set mod_channel to nil after that to free Lua resources
|
* Ensure your set mod_channel to nil after that to free Lua resources
|
||||||
* `is_writeable()`: returns true if channel is writeable and mod can send over it.
|
* `is_writeable()`: returns true if channel is writable and mod can send over it.
|
||||||
* `send_all(message)`: Send `message` though the mod channel.
|
* `send_all(message)`: Send `message` though the mod channel.
|
||||||
* If mod channel is not writeable or invalid, message will be dropped.
|
* If mod channel is not writable or invalid, message will be dropped.
|
||||||
* Message size is limited to 65535 characters by protocol.
|
* Message size is limited to 65535 characters by protocol.
|
||||||
|
|
||||||
### Minimap
|
### Minimap
|
||||||
@ -891,14 +895,14 @@ An interface to manipulate minimap on client UI
|
|||||||
* `get_shape()`: Gets the minimap shape. (0 = square, 1 = round)
|
* `get_shape()`: Gets the minimap shape. (0 = square, 1 = round)
|
||||||
|
|
||||||
### Camera
|
### Camera
|
||||||
An interface to get or set information about the camera and cameranode.
|
An interface to get or set information about the camera and camera-node.
|
||||||
Please do not try to access the reference until the camera is initialized, otherwise the reference will be nil.
|
Please do not try to access the reference until the camera is initialized, otherwise the reference will be nil.
|
||||||
|
|
||||||
#### Methods
|
#### Methods
|
||||||
* `set_camera_mode(mode)`
|
* `set_camera_mode(mode)`
|
||||||
* Pass `0` for first-person, `1` for third person, and `2` for third person front
|
* Pass `0` for first-person, `1` for third person, and `2` for third person front
|
||||||
* `get_camera_mode()`
|
* `get_camera_mode()`
|
||||||
* Returns with same syntax as above
|
* Returns 0, 1, or 2 as described above
|
||||||
* `get_fov()`
|
* `get_fov()`
|
||||||
* Returns:
|
* Returns:
|
||||||
|
|
||||||
@ -925,18 +929,7 @@ Please do not try to access the reference until the camera is initialized, other
|
|||||||
* Returns aspect ratio of screen
|
* Returns aspect ratio of screen
|
||||||
|
|
||||||
### LocalPlayer
|
### LocalPlayer
|
||||||
An interface to retrieve information about the player. The player is
|
An interface to retrieve information about the player.
|
||||||
not accessible until the client is fully done loading and therefore
|
|
||||||
not at module init time.
|
|
||||||
|
|
||||||
To get the localplayer handle correctly, use `on_connect()` as follows:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local localplayer
|
|
||||||
minetest.register_on_connect(function()
|
|
||||||
localplayer = minetest.localplayer
|
|
||||||
end)
|
|
||||||
```
|
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
@ -1025,6 +1018,17 @@ Methods:
|
|||||||
* returns last look vertical angle
|
* returns last look vertical angle
|
||||||
* `get_key_pressed()`:
|
* `get_key_pressed()`:
|
||||||
* returns last key typed by the player
|
* returns last key typed by the player
|
||||||
|
* `hud_add(definition)`
|
||||||
|
* add a HUD element described by HUD def, returns ID number on success and `nil` on failure.
|
||||||
|
* See [`HUD definition`](#hud-definition-hud_add-hud_get)
|
||||||
|
* `hud_get(id)`
|
||||||
|
* returns the [`definition`](#hud-definition-hud_add-hud_get) of the HUD with that ID number or `nil`, if non-existent.
|
||||||
|
* `hud_remove(id)`
|
||||||
|
* remove the HUD element of the specified id, returns `true` on success
|
||||||
|
* `hud_change(id, stat, value)`
|
||||||
|
* change a value of a previously added HUD element
|
||||||
|
* element `stat` values: `position`, `name`, `scale`, `text`, `number`, `item`, `dir`
|
||||||
|
* Returns `true` on success, otherwise returns `nil`
|
||||||
|
|
||||||
### Settings
|
### Settings
|
||||||
An interface to read config files in the format of `minetest.conf`.
|
An interface to read config files in the format of `minetest.conf`.
|
||||||
@ -1136,7 +1140,7 @@ Can be obtained via `minetest.get_meta(pos)`.
|
|||||||
stack_max = number, -- Number of items stackable together
|
stack_max = number, -- Number of items stackable together
|
||||||
usable = bool, -- Has on_use callback defined
|
usable = bool, -- Has on_use callback defined
|
||||||
liquids_pointable = bool, -- Whether you can point at liquids with the item
|
liquids_pointable = bool, -- Whether you can point at liquids with the item
|
||||||
tool_capabilities = <table>, -- If the item is a tool, tool capabiltites of the item
|
tool_capabilities = <table>, -- If the item is a tool, tool capabilities of the item
|
||||||
groups = table, -- Groups of the item
|
groups = table, -- Groups of the item
|
||||||
sound_place = SimpleSoundSpec, -- Sound played when placed
|
sound_place = SimpleSoundSpec, -- Sound played when placed
|
||||||
sound_place_failed = SimpleSoundSpec, -- Sound played when placement failed
|
sound_place_failed = SimpleSoundSpec, -- Sound played when placement failed
|
||||||
@ -1163,6 +1167,30 @@ Can be obtained via `minetest.get_meta(pos)`.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### HUD Definition (`hud_add`, `hud_get`)
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
hud_elem_type = "image", -- see HUD element types, default "text"
|
||||||
|
-- ^ type of HUD element, can be either of "image", "text", "statbar", or "inventory"
|
||||||
|
position = {x=0.5, y=0.5},
|
||||||
|
-- ^ Left corner position of element, default `{x=0,y=0}`.
|
||||||
|
name = "<name>", -- default ""
|
||||||
|
scale = {x=2, y=2}, -- default {x=0,y=0}
|
||||||
|
text = "<text>", -- default ""
|
||||||
|
number = 2, -- default 0
|
||||||
|
item = 3, -- default 0
|
||||||
|
-- ^ Selected item in inventory. 0 for no item selected.
|
||||||
|
direction = 0, -- default 0
|
||||||
|
-- ^ Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
|
||||||
|
alignment = {x=0, y=0}, -- default {x=0, y=0}
|
||||||
|
-- ^ See "HUD Element Types"
|
||||||
|
offset = {x=0, y=0}, -- default {x=0, y=0}
|
||||||
|
-- ^ See "HUD Element Types"
|
||||||
|
size = { x=100, y=100 }, -- default {x=0, y=0}
|
||||||
|
-- ^ Size of element in pixels
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Escape sequences
|
Escape sequences
|
||||||
----------------
|
----------------
|
||||||
Most text can contain escape sequences, that can for example color the text.
|
Most text can contain escape sequences, that can for example color the text.
|
||||||
@ -1206,3 +1234,134 @@ value must (always) be two hexadecimal digits.
|
|||||||
`Color`
|
`Color`
|
||||||
-------------
|
-------------
|
||||||
`{a = alpha, r = red, g = green, b = blue}` defines an ARGB8 color.
|
`{a = alpha, r = red, g = green, b = blue}` defines an ARGB8 color.
|
||||||
|
|
||||||
|
HUD element types
|
||||||
|
-----------------
|
||||||
|
The position field is used for all element types.
|
||||||
|
|
||||||
|
To account for differing resolutions, the position coordinates are the percentage
|
||||||
|
of the screen, ranging in value from `0` to `1`.
|
||||||
|
|
||||||
|
The name field is not yet used, but should contain a description of what the
|
||||||
|
HUD element represents. The direction field is the direction in which something
|
||||||
|
is drawn.
|
||||||
|
|
||||||
|
`0` draws from left to right, `1` draws from right to left, `2` draws from
|
||||||
|
top to bottom, and `3` draws from bottom to top.
|
||||||
|
|
||||||
|
The `alignment` field specifies how the item will be aligned. It ranges from `-1` to `1`,
|
||||||
|
with `0` being the center, `-1` is moved to the left/up, and `1` is to the right/down.
|
||||||
|
Fractional values can be used.
|
||||||
|
|
||||||
|
The `offset` field specifies a pixel offset from the position. Contrary to position,
|
||||||
|
the offset is not scaled to screen size. This allows for some precisely-positioned
|
||||||
|
items in the HUD.
|
||||||
|
|
||||||
|
**Note**: `offset` _will_ adapt to screen DPI as well as user defined scaling factor!
|
||||||
|
|
||||||
|
Below are the specific uses for fields in each type; fields not listed for that type are ignored.
|
||||||
|
|
||||||
|
**Note**: Future revisions to the HUD API may be incompatible; the HUD API is still
|
||||||
|
in the experimental stages.
|
||||||
|
|
||||||
|
### `image`
|
||||||
|
Displays an image on the HUD.
|
||||||
|
|
||||||
|
* `scale`: The scale of the image, with 1 being the original texture size.
|
||||||
|
Only the X coordinate scale is used (positive values).
|
||||||
|
Negative values represent that percentage of the screen it
|
||||||
|
should take; e.g. `x=-100` means 100% (width).
|
||||||
|
* `text`: The name of the texture that is displayed.
|
||||||
|
* `alignment`: The alignment of the image.
|
||||||
|
* `offset`: offset in pixels from position.
|
||||||
|
|
||||||
|
### `text`
|
||||||
|
Displays text on the HUD.
|
||||||
|
|
||||||
|
* `scale`: Defines the bounding rectangle of the text.
|
||||||
|
A value such as `{x=100, y=100}` should work.
|
||||||
|
* `text`: The text to be displayed in the HUD element.
|
||||||
|
* `number`: An integer containing the RGB value of the color used to draw the text.
|
||||||
|
Specify `0xFFFFFF` for white text, `0xFF0000` for red, and so on.
|
||||||
|
* `alignment`: The alignment of the text.
|
||||||
|
* `offset`: offset in pixels from position.
|
||||||
|
|
||||||
|
### `statbar`
|
||||||
|
Displays a horizontal bar made up of half-images.
|
||||||
|
|
||||||
|
* `text`: The name of the texture that is used.
|
||||||
|
* `number`: The number of half-textures that are displayed.
|
||||||
|
If odd, will end with a vertically center-split texture.
|
||||||
|
* `direction`
|
||||||
|
* `offset`: offset in pixels from position.
|
||||||
|
* `size`: If used, will force full-image size to this value (override texture pack image size)
|
||||||
|
|
||||||
|
### `inventory`
|
||||||
|
* `text`: The name of the inventory list to be displayed.
|
||||||
|
* `number`: Number of items in the inventory to be displayed.
|
||||||
|
* `item`: Position of item that is selected.
|
||||||
|
* `direction`
|
||||||
|
* `offset`: offset in pixels from position.
|
||||||
|
|
||||||
|
### `waypoint`
|
||||||
|
Displays distance to selected world position.
|
||||||
|
|
||||||
|
* `name`: The name of the waypoint.
|
||||||
|
* `text`: Distance suffix. Can be blank.
|
||||||
|
* `number:` An integer containing the RGB value of the color used to draw the text.
|
||||||
|
* `world_pos`: World position of the waypoint.
|
||||||
|
|
||||||
|
### Particle definition (`add_particle`)
|
||||||
|
|
||||||
|
{
|
||||||
|
pos = {x=0, y=0, z=0},
|
||||||
|
velocity = {x=0, y=0, z=0},
|
||||||
|
acceleration = {x=0, y=0, z=0},
|
||||||
|
-- ^ Spawn particle at pos with velocity and acceleration
|
||||||
|
expirationtime = 1,
|
||||||
|
-- ^ Disappears after expirationtime seconds
|
||||||
|
size = 1,
|
||||||
|
collisiondetection = false,
|
||||||
|
-- ^ collisiondetection: if true collides with physical objects
|
||||||
|
collision_removal = false,
|
||||||
|
-- ^ collision_removal: if true then particle is removed when it collides,
|
||||||
|
-- ^ requires collisiondetection = true to have any effect
|
||||||
|
vertical = false,
|
||||||
|
-- ^ vertical: if true faces player using y axis only
|
||||||
|
texture = "image.png",
|
||||||
|
-- ^ Uses texture (string)
|
||||||
|
animation = {Tile Animation definition},
|
||||||
|
-- ^ optional, specifies how to animate the particle texture
|
||||||
|
glow = 0
|
||||||
|
-- ^ optional, specify particle self-luminescence in darkness
|
||||||
|
}
|
||||||
|
|
||||||
|
### `ParticleSpawner` definition (`add_particlespawner`)
|
||||||
|
|
||||||
|
{
|
||||||
|
amount = 1,
|
||||||
|
time = 1,
|
||||||
|
-- ^ If time is 0 has infinite lifespan and spawns the amount on a per-second base
|
||||||
|
minpos = {x=0, y=0, z=0},
|
||||||
|
maxpos = {x=0, y=0, z=0},
|
||||||
|
minvel = {x=0, y=0, z=0},
|
||||||
|
maxvel = {x=0, y=0, z=0},
|
||||||
|
minacc = {x=0, y=0, z=0},
|
||||||
|
maxacc = {x=0, y=0, z=0},
|
||||||
|
minexptime = 1,
|
||||||
|
maxexptime = 1,
|
||||||
|
minsize = 1,
|
||||||
|
maxsize = 1,
|
||||||
|
-- ^ The particle's properties are random values in between the bounds:
|
||||||
|
-- ^ minpos/maxpos, minvel/maxvel (velocity), minacc/maxacc (acceleration),
|
||||||
|
-- ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
|
||||||
|
collisiondetection = false,
|
||||||
|
-- ^ collisiondetection: if true uses collision detection
|
||||||
|
collision_removal = false,
|
||||||
|
-- ^ collision_removal: if true then particle is removed when it collides,
|
||||||
|
-- ^ requires collisiondetection = true to have any effect
|
||||||
|
vertical = false,
|
||||||
|
-- ^ vertical: if true faces player using y axis only
|
||||||
|
texture = "image.png",
|
||||||
|
-- ^ Uses texture (string)
|
||||||
|
}
|
890
doc/lua_api.txt
890
doc/lua_api.txt
File diff suppressed because it is too large
Load Diff
@ -682,6 +682,74 @@ minetest.register_chatcommand("test1", {
|
|||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("test_bulk_set_node", {
|
||||||
|
params = "",
|
||||||
|
description = "Test 2: bulk set a node",
|
||||||
|
func = function(name, param)
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if not player then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pos_list = {}
|
||||||
|
local ppos = player:get_pos()
|
||||||
|
local i = 1
|
||||||
|
for x=2,10 do
|
||||||
|
for y=2,10 do
|
||||||
|
for z=2,10 do
|
||||||
|
pos_list[i] = {x=ppos.x + x,y = ppos.y + y,z = ppos.z + z}
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
minetest.bulk_set_node(pos_list, {name = "default:stone"})
|
||||||
|
minetest.chat_send_player(name, "Done.");
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_chatcommand("bench_bulk_set_node", {
|
||||||
|
params = "",
|
||||||
|
description = "Test 3: bulk set a node (bench)",
|
||||||
|
func = function(name, param)
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if not player then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pos_list = {}
|
||||||
|
local ppos = player:get_pos()
|
||||||
|
local i = 1
|
||||||
|
for x=2,100 do
|
||||||
|
for y=2,100 do
|
||||||
|
for z=2,100 do
|
||||||
|
pos_list[i] = {x=ppos.x + x,y = ppos.y + y,z = ppos.z + z}
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.chat_send_player(name, "Benching bulk set node. Warming up...");
|
||||||
|
|
||||||
|
-- warm up with default:stone to prevent having different callbacks
|
||||||
|
-- due to different node topology
|
||||||
|
minetest.bulk_set_node(pos_list, {name = "default:stone"})
|
||||||
|
|
||||||
|
minetest.chat_send_player(name, "Warming up finished, now benching...");
|
||||||
|
|
||||||
|
local start_time = os.clock()
|
||||||
|
for i=1,#pos_list do
|
||||||
|
minetest.set_node(pos_list[i], {name = "default:stone"})
|
||||||
|
end
|
||||||
|
local middle_time = os.clock()
|
||||||
|
minetest.bulk_set_node(pos_list, {name = "default:stone"})
|
||||||
|
local end_time = os.clock()
|
||||||
|
minetest.chat_send_player(name,
|
||||||
|
string.format("Bench results: set_node loop[%.2fms], bulk_set_node[%.2fms]",
|
||||||
|
(middle_time - start_time) * 1000,
|
||||||
|
(end_time - middle_time) * 1000
|
||||||
|
)
|
||||||
|
);
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
experimental.print_to_everything("Inventory fields 1: player="..player:get_player_name()..", fields="..dump(fields))
|
experimental.print_to_everything("Inventory fields 1: player="..player:get_player_name()..", fields="..dump(fields))
|
||||||
end)
|
end)
|
||||||
|
@ -701,7 +701,7 @@
|
|||||||
|
|
||||||
# In-game chat console height, between 0.1 (10%) and 1.0 (100%).
|
# In-game chat console height, between 0.1 (10%) and 1.0 (100%).
|
||||||
# type: float min: 0.1 max: 1
|
# type: float min: 0.1 max: 1
|
||||||
# console_height = 1.0
|
# console_height = 0.6
|
||||||
|
|
||||||
# In-game chat console background color (R,G,B).
|
# In-game chat console background color (R,G,B).
|
||||||
# type: string
|
# type: string
|
||||||
@ -994,6 +994,10 @@
|
|||||||
# type: int
|
# type: int
|
||||||
# max_out_chat_queue_size = 20
|
# max_out_chat_queue_size = 20
|
||||||
|
|
||||||
|
# Open the pause menu when the window's focus is lost. Does not pause if a formspec is open.
|
||||||
|
# type: bool
|
||||||
|
# pause_on_lost_focus = false
|
||||||
|
|
||||||
## Advanced
|
## Advanced
|
||||||
|
|
||||||
# Timeout for client to remove unused map data from memory.
|
# Timeout for client to remove unused map data from memory.
|
||||||
@ -1346,13 +1350,13 @@
|
|||||||
|
|
||||||
# Restricts the access of certain client-side functions on servers
|
# Restricts the access of certain client-side functions on servers
|
||||||
# Combine these byteflags below to restrict more client-side features:
|
# Combine these byteflags below to restrict more client-side features:
|
||||||
# LOOKUP_NODES_LIMIT: 1 (limits get_node call client-side to csm_flavour_noderange_limit)
|
# LOAD_CLIENT_MODS: 1 (disable client mods loading)
|
||||||
# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
|
# CHAT_MESSAGES: 2 (disable send_chat_message call client-side)
|
||||||
# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
|
# READ_ITEMDEFS: 4 (disable get_item_def call client-side)
|
||||||
# READ_NODEDEFS: 8 (disable get_node_def call client-side)
|
# READ_NODEDEFS: 8 (disable get_node_def call client-side)
|
||||||
# type: int
|
# type: int
|
||||||
# type: int
|
# LOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to csm_flavour_noderange_limit)
|
||||||
# csm_flavour_limits = 3
|
# csm_flavour_limits = 18
|
||||||
|
|
||||||
# If the CSM flavour for node range is enabled, get_node is limited to
|
# If the CSM flavour for node range is enabled, get_node is limited to
|
||||||
# this many nodes from the player.
|
# this many nodes from the player.
|
||||||
|
@ -448,6 +448,7 @@ set(common_SRCS
|
|||||||
version.cpp
|
version.cpp
|
||||||
voxel.cpp
|
voxel.cpp
|
||||||
voxelalgorithms.cpp
|
voxelalgorithms.cpp
|
||||||
|
hud.cpp
|
||||||
${common_network_SRCS}
|
${common_network_SRCS}
|
||||||
${JTHREAD_SRCS}
|
${JTHREAD_SRCS}
|
||||||
${common_SCRIPT_SRCS}
|
${common_SCRIPT_SRCS}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2018 nerzhul, Loic BLOT <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -125,11 +126,11 @@ void BanManager::remove(const std::string &ip_or_name)
|
|||||||
for (StringMap::iterator it = m_ips.begin(); it != m_ips.end();) {
|
for (StringMap::iterator it = m_ips.begin(); it != m_ips.end();) {
|
||||||
if ((it->first == ip_or_name) || (it->second == ip_or_name)) {
|
if ((it->first == ip_or_name) || (it->second == ip_or_name)) {
|
||||||
m_ips.erase(it++);
|
m_ips.erase(it++);
|
||||||
|
m_modified = true;
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_modified = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,8 +72,7 @@ Camera::Camera(MapDrawControl &draw_control, Client *client):
|
|||||||
m_cache_fall_bobbing_amount = g_settings->getFloat("fall_bobbing_amount");
|
m_cache_fall_bobbing_amount = g_settings->getFloat("fall_bobbing_amount");
|
||||||
m_cache_view_bobbing_amount = g_settings->getFloat("view_bobbing_amount");
|
m_cache_view_bobbing_amount = g_settings->getFloat("view_bobbing_amount");
|
||||||
m_cache_fov = g_settings->getFloat("fov");
|
m_cache_fov = g_settings->getFloat("fov");
|
||||||
m_cache_zoom_fov = g_settings->getFloat("zoom_fov");
|
m_arm_inertia = g_settings->getBool("arm_inertia");
|
||||||
m_arm_inertia = g_settings->getBool("arm_inertia");
|
|
||||||
m_nametags.clear();
|
m_nametags.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,12 +452,13 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
|
|||||||
|
|
||||||
// Get FOV
|
// Get FOV
|
||||||
f32 fov_degrees;
|
f32 fov_degrees;
|
||||||
if (player->getPlayerControl().zoom && player->getCanZoom()) {
|
// Disable zoom with zoom FOV = 0
|
||||||
fov_degrees = m_cache_zoom_fov;
|
if (player->getPlayerControl().zoom && player->getZoomFOV() > 0.001f) {
|
||||||
|
fov_degrees = player->getZoomFOV();
|
||||||
} else {
|
} else {
|
||||||
fov_degrees = m_cache_fov;
|
fov_degrees = m_cache_fov;
|
||||||
}
|
}
|
||||||
fov_degrees = rangelim(fov_degrees, 1.0, 160.0);
|
fov_degrees = rangelim(fov_degrees, 1.0f, 160.0f);
|
||||||
|
|
||||||
// FOV and aspect ratio
|
// FOV and aspect ratio
|
||||||
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
||||||
|
@ -225,7 +225,6 @@ private:
|
|||||||
f32 m_cache_fall_bobbing_amount;
|
f32 m_cache_fall_bobbing_amount;
|
||||||
f32 m_cache_view_bobbing_amount;
|
f32 m_cache_view_bobbing_amount;
|
||||||
f32 m_cache_fov;
|
f32 m_cache_fov;
|
||||||
f32 m_cache_zoom_fov;
|
|
||||||
bool m_arm_inertia;
|
bool m_arm_inertia;
|
||||||
|
|
||||||
std::list<Nametag *> m_nametags;
|
std::list<Nametag *> m_nametags;
|
||||||
|
22
src/chat.cpp
22
src/chat.cpp
@ -18,11 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "debug.h"
|
|
||||||
#include "config.h"
|
#include <algorithm>
|
||||||
#include "util/strfnd.h"
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util/strfnd.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
|
|
||||||
@ -403,8 +406,14 @@ void ChatPrompt::input(const std::wstring &str)
|
|||||||
|
|
||||||
void ChatPrompt::addToHistory(std::wstring line)
|
void ChatPrompt::addToHistory(std::wstring line)
|
||||||
{
|
{
|
||||||
if (!line.empty())
|
if (!line.empty() &&
|
||||||
|
(m_history.size() == 0 || m_history.back() != line)) {
|
||||||
|
// Remove all duplicates
|
||||||
|
m_history.erase(std::remove(m_history.begin(), m_history.end(),
|
||||||
|
line), m_history.end());
|
||||||
|
// Push unique line
|
||||||
m_history.push_back(line);
|
m_history.push_back(line);
|
||||||
|
}
|
||||||
if (m_history.size() > m_history_limit)
|
if (m_history.size() > m_history_limit)
|
||||||
m_history.erase(m_history.begin());
|
m_history.erase(m_history.begin());
|
||||||
m_history_index = m_history.size();
|
m_history_index = m_history.size();
|
||||||
@ -699,11 +708,10 @@ ChatBuffer& ChatBackend::getRecentBuffer()
|
|||||||
return m_recent_buffer;
|
return m_recent_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnrichedString ChatBackend::getRecentChat()
|
EnrichedString ChatBackend::getRecentChat() const
|
||||||
{
|
{
|
||||||
EnrichedString result;
|
EnrichedString result;
|
||||||
for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i)
|
for (u32 i = 0; i < m_recent_buffer.getLineCount(); ++i) {
|
||||||
{
|
|
||||||
const ChatLine& line = m_recent_buffer.getLine(i);
|
const ChatLine& line = m_recent_buffer.getLine(i);
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
result += L"\n";
|
result += L"\n";
|
||||||
|
@ -265,7 +265,7 @@ public:
|
|||||||
// Get the recent messages buffer
|
// Get the recent messages buffer
|
||||||
ChatBuffer& getRecentBuffer();
|
ChatBuffer& getRecentBuffer();
|
||||||
// Concatenate all recent messages
|
// Concatenate all recent messages
|
||||||
EnrichedString getRecentChat();
|
EnrichedString getRecentChat() const;
|
||||||
// Get the console prompt
|
// Get the console prompt
|
||||||
ChatPrompt& getPrompt();
|
ChatPrompt& getPrompt();
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ public:
|
|||||||
|
|
||||||
// Resize recent buffer based on settings
|
// Resize recent buffer based on settings
|
||||||
void applySettings();
|
void applySettings();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ChatBuffer m_console_buffer;
|
ChatBuffer m_console_buffer;
|
||||||
ChatBuffer m_recent_buffer;
|
ChatBuffer m_recent_buffer;
|
||||||
|
138
src/client.cpp
138
src/client.cpp
@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "network/networkpacket.h"
|
#include "network/networkpacket.h"
|
||||||
#include "threading/mutex_auto_lock.h"
|
#include "threading/mutex_auto_lock.h"
|
||||||
#include "client/clientevent.h"
|
#include "client/clientevent.h"
|
||||||
|
#include "client/gameui.h"
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
#include "client/tile.h"
|
#include "client/tile.h"
|
||||||
#include "util/auth.h"
|
#include "util/auth.h"
|
||||||
@ -74,7 +75,7 @@ Client::Client(
|
|||||||
ISoundManager *sound,
|
ISoundManager *sound,
|
||||||
MtEventManager *event,
|
MtEventManager *event,
|
||||||
bool ipv6,
|
bool ipv6,
|
||||||
GameUIFlags *game_ui_flags
|
GameUI *game_ui
|
||||||
):
|
):
|
||||||
m_tsrc(tsrc),
|
m_tsrc(tsrc),
|
||||||
m_shsrc(shsrc),
|
m_shsrc(shsrc),
|
||||||
@ -96,7 +97,7 @@ Client::Client(
|
|||||||
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
|
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
|
||||||
m_media_downloader(new ClientMediaDownloader()),
|
m_media_downloader(new ClientMediaDownloader()),
|
||||||
m_state(LC_Created),
|
m_state(LC_Created),
|
||||||
m_game_ui_flags(game_ui_flags),
|
m_game_ui(game_ui),
|
||||||
m_modchannel_mgr(new ModChannelMgr())
|
m_modchannel_mgr(new ModChannelMgr())
|
||||||
{
|
{
|
||||||
// Add local player
|
// Add local player
|
||||||
@ -113,18 +114,38 @@ Client::Client(
|
|||||||
m_script->setEnv(&m_env);
|
m_script->setEnv(&m_env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::loadMods()
|
void Client::loadBuiltin()
|
||||||
{
|
{
|
||||||
// Load builtin
|
// Load builtin
|
||||||
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
|
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
|
||||||
|
|
||||||
// If modding is not enabled, don't load mods, just builtin
|
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
|
||||||
if (!m_modding_enabled) {
|
}
|
||||||
|
|
||||||
|
void Client::loadMods()
|
||||||
|
{
|
||||||
|
// Don't permit to load mods twice
|
||||||
|
if (m_mods_loaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If modding is not enabled or flavour disable it, don't load mods, just builtin
|
||||||
|
if (!m_modding_enabled) {
|
||||||
|
warningstream << "Client side mods are disabled by configuration." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_LOAD_CLIENT_MODS)) {
|
||||||
|
warningstream << "Client side mods are disabled by server." << std::endl;
|
||||||
|
// If mods loading is disabled and builtin integrity is wrong, disconnect user.
|
||||||
|
if (!checkBuiltinIntegrity()) {
|
||||||
|
// @TODO disconnect user
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ClientModConfiguration modconf(getClientModsLuaPath());
|
ClientModConfiguration modconf(getClientModsLuaPath());
|
||||||
m_mods = modconf.getMods();
|
m_mods = modconf.getMods();
|
||||||
std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
|
|
||||||
// complain about mods with unsatisfied dependencies
|
// complain about mods with unsatisfied dependencies
|
||||||
if (!modconf.isConsistent()) {
|
if (!modconf.isConsistent()) {
|
||||||
modconf.printUnsatisfiedModsError();
|
modconf.printUnsatisfiedModsError();
|
||||||
@ -145,6 +166,18 @@ void Client::loadMods()
|
|||||||
}
|
}
|
||||||
scanModIntoMemory(mod.name, mod.path);
|
scanModIntoMemory(mod.name, mod.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load and run "mod" scripts
|
||||||
|
for (const ModSpec &mod : m_mods)
|
||||||
|
m_script->loadModFromMemory(mod.name);
|
||||||
|
|
||||||
|
m_mods_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::checkBuiltinIntegrity()
|
||||||
|
{
|
||||||
|
// @TODO
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::scanModSubfolder(const std::string &mod_name, const std::string &mod_path,
|
void Client::scanModSubfolder(const std::string &mod_name, const std::string &mod_path,
|
||||||
@ -164,20 +197,6 @@ void Client::scanModSubfolder(const std::string &mod_name, const std::string &mo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::initMods()
|
|
||||||
{
|
|
||||||
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
|
|
||||||
|
|
||||||
// If modding is not enabled, don't load mods, just builtin
|
|
||||||
if (!m_modding_enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load and run "mod" scripts
|
|
||||||
for (const ModSpec &mod : m_mods)
|
|
||||||
m_script->loadModFromMemory(mod.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &Client::getBuiltinLuaPath()
|
const std::string &Client::getBuiltinLuaPath()
|
||||||
{
|
{
|
||||||
static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin";
|
static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin";
|
||||||
@ -264,14 +283,9 @@ void Client::connect(Address address, bool is_local_server)
|
|||||||
void Client::step(float dtime)
|
void Client::step(float dtime)
|
||||||
{
|
{
|
||||||
// Limit a bit
|
// Limit a bit
|
||||||
if(dtime > 2.0)
|
if (dtime > 2.0)
|
||||||
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;
|
m_animation_time += dtime;
|
||||||
if(m_animation_time > 60.0)
|
if(m_animation_time > 60.0)
|
||||||
m_animation_time -= 60.0;
|
m_animation_time -= 60.0;
|
||||||
@ -304,6 +318,10 @@ void Client::step(float dtime)
|
|||||||
initial_step = false;
|
initial_step = false;
|
||||||
}
|
}
|
||||||
else if(m_state == LC_Created) {
|
else if(m_state == LC_Created) {
|
||||||
|
if (m_is_registration_confirmation_state) {
|
||||||
|
// Waiting confirmation
|
||||||
|
return;
|
||||||
|
}
|
||||||
float &counter = m_connection_reinit_timer;
|
float &counter = m_connection_reinit_timer;
|
||||||
counter -= dtime;
|
counter -= dtime;
|
||||||
if(counter <= 0.0) {
|
if(counter <= 0.0) {
|
||||||
@ -394,18 +412,16 @@ void Client::step(float dtime)
|
|||||||
ClientEnvEvent envEvent = m_env.getClientEnvEvent();
|
ClientEnvEvent envEvent = m_env.getClientEnvEvent();
|
||||||
|
|
||||||
if (envEvent.type == CEE_PLAYER_DAMAGE) {
|
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)
|
if (envEvent.player_damage.send_to_server)
|
||||||
sendDamage(damage);
|
sendDamage(damage);
|
||||||
|
|
||||||
// Add to ClientEvent queue
|
// Add to ClientEvent queue
|
||||||
ClientEvent *event = new ClientEvent();
|
ClientEvent *event = new ClientEvent();
|
||||||
event->type = CE_PLAYER_DAMAGE;
|
event->type = CE_PLAYER_DAMAGE;
|
||||||
event->player_damage.amount = damage;
|
event->player_damage.amount = damage;
|
||||||
m_client_event_queue.push(event);
|
m_client_event_queue.push(event);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,6 +978,18 @@ void Client::sendInit(const std::string &playerName)
|
|||||||
Send(&pkt);
|
Send(&pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::promptConfirmRegistration(AuthMechanism chosen_auth_mechanism)
|
||||||
|
{
|
||||||
|
m_chosen_auth_mech = chosen_auth_mechanism;
|
||||||
|
m_is_registration_confirmation_state = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::confirmRegistration()
|
||||||
|
{
|
||||||
|
m_is_registration_confirmation_state = false;
|
||||||
|
startAuth(m_chosen_auth_mech);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::startAuth(AuthMechanism chosen_auth_mechanism)
|
void Client::startAuth(AuthMechanism chosen_auth_mechanism)
|
||||||
{
|
{
|
||||||
m_chosen_auth_mech = chosen_auth_mechanism;
|
m_chosen_auth_mech = chosen_auth_mechanism;
|
||||||
@ -1165,9 +1193,6 @@ void Client::sendChangePassword(const std::string &oldpassword,
|
|||||||
|
|
||||||
void Client::sendDamage(u8 damage)
|
void Client::sendDamage(u8 damage)
|
||||||
{
|
{
|
||||||
NetworkPacket pkt(TOSERVER_DAMAGE, sizeof(u8));
|
|
||||||
pkt << damage;
|
|
||||||
Send(&pkt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::sendRespawn()
|
void Client::sendRespawn()
|
||||||
@ -1670,7 +1695,6 @@ void Client::afterContentReceived()
|
|||||||
|
|
||||||
if (g_settings->getBool("enable_client_modding")) {
|
if (g_settings->getBool("enable_client_modding")) {
|
||||||
m_script->on_client_ready(m_env.getLocalPlayer());
|
m_script->on_client_ready(m_env.getLocalPlayer());
|
||||||
m_script->on_connect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
text = wgettext("Done!");
|
text = wgettext("Done!");
|
||||||
@ -1760,34 +1784,9 @@ void Client::pushToEventQueue(ClientEvent *event)
|
|||||||
m_client_event_queue.push(event);
|
m_client_event_queue.push(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::showGameChat(const bool show)
|
|
||||||
{
|
|
||||||
m_game_ui_flags->show_chat = show;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::showGameHud(const bool show)
|
|
||||||
{
|
|
||||||
m_game_ui_flags->show_hud = show;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::showMinimap(const bool show)
|
void Client::showMinimap(const bool show)
|
||||||
{
|
{
|
||||||
m_game_ui_flags->show_minimap = show;
|
m_game_ui->showMinimap(show);
|
||||||
}
|
|
||||||
|
|
||||||
void Client::showProfiler(const bool show)
|
|
||||||
{
|
|
||||||
m_game_ui_flags->show_profiler_graph = show;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::showGameFog(const bool show)
|
|
||||||
{
|
|
||||||
m_game_ui_flags->force_fog_off = !show;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::showGameDebug(const bool show)
|
|
||||||
{
|
|
||||||
m_game_ui_flags->show_debug = show;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IGameDef interface
|
// IGameDef interface
|
||||||
@ -1836,7 +1835,7 @@ ParticleManager* Client::getParticleManager()
|
|||||||
return &m_particle_manager;
|
return &m_particle_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
|
scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache)
|
||||||
{
|
{
|
||||||
StringMap::const_iterator it = m_mesh_data.find(filename);
|
StringMap::const_iterator it = m_mesh_data.find(filename);
|
||||||
if (it == m_mesh_data.end()) {
|
if (it == m_mesh_data.end()) {
|
||||||
@ -1855,10 +1854,9 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
|
|||||||
|
|
||||||
scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile);
|
scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile);
|
||||||
rfile->drop();
|
rfile->drop();
|
||||||
// NOTE: By playing with Irrlicht refcounts, maybe we could cache a bunch
|
|
||||||
// of uniquely named instances and re-use them
|
|
||||||
mesh->grab();
|
mesh->grab();
|
||||||
RenderingEngine::get_mesh_cache()->removeMesh(mesh);
|
if (!cache)
|
||||||
|
RenderingEngine::get_mesh_cache()->removeMesh(mesh);
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
src/client.h
42
src/client.h
@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
#include "inventorymanager.h"
|
#include "inventorymanager.h"
|
||||||
#include "localplayer.h"
|
#include "localplayer.h"
|
||||||
#include "hud.h"
|
#include "client/hud.h"
|
||||||
#include "particles.h"
|
#include "particles.h"
|
||||||
#include "mapnode.h"
|
#include "mapnode.h"
|
||||||
#include "tileanimation.h"
|
#include "tileanimation.h"
|
||||||
@ -112,7 +112,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class ClientScripting;
|
class ClientScripting;
|
||||||
struct GameUIFlags;
|
class GameUI;
|
||||||
|
|
||||||
class Client : public con::PeerHandler, public InventoryManager, public IGameDef
|
class Client : public con::PeerHandler, public InventoryManager, public IGameDef
|
||||||
{
|
{
|
||||||
@ -133,14 +133,14 @@ public:
|
|||||||
ISoundManager *sound,
|
ISoundManager *sound,
|
||||||
MtEventManager *event,
|
MtEventManager *event,
|
||||||
bool ipv6,
|
bool ipv6,
|
||||||
GameUIFlags *game_ui_flags
|
GameUI *game_ui
|
||||||
);
|
);
|
||||||
|
|
||||||
~Client();
|
~Client();
|
||||||
DISABLE_CLASS_COPY(Client);
|
DISABLE_CLASS_COPY(Client);
|
||||||
|
|
||||||
// Load local mods into memory
|
// Load local mods into memory
|
||||||
void loadMods();
|
void loadBuiltin();
|
||||||
void scanModSubfolder(const std::string &mod_name, const std::string &mod_path,
|
void scanModSubfolder(const std::string &mod_name, const std::string &mod_path,
|
||||||
std::string mod_subpath);
|
std::string mod_subpath);
|
||||||
inline void scanModIntoMemory(const std::string &mod_name, const std::string &mod_path)
|
inline void scanModIntoMemory(const std::string &mod_name, const std::string &mod_path)
|
||||||
@ -148,9 +148,6 @@ public:
|
|||||||
scanModSubfolder(mod_name, mod_path, "");
|
scanModSubfolder(mod_name, mod_path, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initizle the mods
|
|
||||||
void initMods();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
request all threads managed by client to be stopped
|
request all threads managed by client to be stopped
|
||||||
*/
|
*/
|
||||||
@ -301,7 +298,7 @@ public:
|
|||||||
u16 getHP();
|
u16 getHP();
|
||||||
|
|
||||||
bool checkPrivilege(const std::string &priv) const
|
bool checkPrivilege(const std::string &priv) const
|
||||||
{ return (m_privileges.count(priv) != 0); }
|
{ return true; }
|
||||||
|
|
||||||
const std::unordered_set<std::string> &getPrivilegeList() const
|
const std::unordered_set<std::string> &getPrivilegeList() const
|
||||||
{ return m_privileges; }
|
{ return m_privileges; }
|
||||||
@ -348,6 +345,9 @@ public:
|
|||||||
{ return m_proto_ver; }
|
{ return m_proto_ver; }
|
||||||
|
|
||||||
bool connectedToServer();
|
bool connectedToServer();
|
||||||
|
void confirmRegistration();
|
||||||
|
bool m_is_registration_confirmation_state = false;
|
||||||
|
bool m_simple_singleplayer_mode;
|
||||||
|
|
||||||
float mediaReceiveProgress();
|
float mediaReceiveProgress();
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ public:
|
|||||||
virtual ParticleManager* getParticleManager();
|
virtual ParticleManager* getParticleManager();
|
||||||
bool checkLocalPrivilege(const std::string &priv)
|
bool checkLocalPrivilege(const std::string &priv)
|
||||||
{ return checkPrivilege(priv); }
|
{ return checkPrivilege(priv); }
|
||||||
virtual scene::IAnimatedMesh* getMesh(const std::string &filename);
|
virtual scene::IAnimatedMesh* getMesh(const std::string &filename, bool cache = false);
|
||||||
const std::string* getModFile(const std::string &filename);
|
const std::string* getModFile(const std::string &filename);
|
||||||
|
|
||||||
virtual std::string getModStoragePath() const;
|
virtual std::string getModStoragePath() const;
|
||||||
@ -403,12 +403,7 @@ public:
|
|||||||
|
|
||||||
void pushToEventQueue(ClientEvent *event);
|
void pushToEventQueue(ClientEvent *event);
|
||||||
|
|
||||||
void showGameChat(bool show = true);
|
|
||||||
void showGameHud(bool show = true);
|
|
||||||
void showMinimap(bool show = true);
|
void showMinimap(bool show = true);
|
||||||
void showProfiler(bool show = true);
|
|
||||||
void showGameFog(bool show = true);
|
|
||||||
void showGameDebug(bool show = true);
|
|
||||||
|
|
||||||
const Address getServerAddress();
|
const Address getServerAddress();
|
||||||
|
|
||||||
@ -427,12 +422,19 @@ public:
|
|||||||
return m_csm_noderange_limit;
|
return m_csm_noderange_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::unordered_map<u32, u32> &getHUDTranslationMap()
|
||||||
|
{
|
||||||
|
return m_hud_server_to_client;
|
||||||
|
}
|
||||||
|
|
||||||
bool joinModChannel(const std::string &channel);
|
bool joinModChannel(const std::string &channel);
|
||||||
bool leaveModChannel(const std::string &channel);
|
bool leaveModChannel(const std::string &channel);
|
||||||
bool sendModChannelMessage(const std::string &channel, const std::string &message);
|
bool sendModChannelMessage(const std::string &channel, const std::string &message);
|
||||||
ModChannel *getModChannel(const std::string &channel);
|
ModChannel *getModChannel(const std::string &channel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void loadMods();
|
||||||
|
bool checkBuiltinIntegrity();
|
||||||
|
|
||||||
// Virtual methods from con::PeerHandler
|
// Virtual methods from con::PeerHandler
|
||||||
void peerAdded(con::Peer *peer);
|
void peerAdded(con::Peer *peer);
|
||||||
@ -454,6 +456,7 @@ private:
|
|||||||
static AuthMechanism choseAuthMech(const u32 mechs);
|
static AuthMechanism choseAuthMech(const u32 mechs);
|
||||||
|
|
||||||
void sendInit(const std::string &playerName);
|
void sendInit(const std::string &playerName);
|
||||||
|
void promptConfirmRegistration(AuthMechanism chosen_auth_mechanism);
|
||||||
void startAuth(AuthMechanism chosen_auth_mechanism);
|
void startAuth(AuthMechanism chosen_auth_mechanism);
|
||||||
void sendDeletedBlocks(std::vector<v3s16> &blocks);
|
void sendDeletedBlocks(std::vector<v3s16> &blocks);
|
||||||
void sendGotBlocks(v3s16 block);
|
void sendGotBlocks(v3s16 block);
|
||||||
@ -469,7 +472,6 @@ private:
|
|||||||
float m_connection_reinit_timer = 0.1f;
|
float m_connection_reinit_timer = 0.1f;
|
||||||
float m_avg_rtt_timer = 0.0f;
|
float m_avg_rtt_timer = 0.0f;
|
||||||
float m_playerpos_send_timer = 0.0f;
|
float m_playerpos_send_timer = 0.0f;
|
||||||
float m_ignore_damage_timer = 0.0f; // Used after server moves player
|
|
||||||
IntervalLimiter m_map_timer_and_unload_interval;
|
IntervalLimiter m_map_timer_and_unload_interval;
|
||||||
|
|
||||||
IWritableTextureSource *m_tsrc;
|
IWritableTextureSource *m_tsrc;
|
||||||
@ -537,6 +539,7 @@ private:
|
|||||||
std::queue<ClientEvent *> m_client_event_queue;
|
std::queue<ClientEvent *> m_client_event_queue;
|
||||||
bool m_itemdef_received = false;
|
bool m_itemdef_received = false;
|
||||||
bool m_nodedef_received = false;
|
bool m_nodedef_received = false;
|
||||||
|
bool m_mods_loaded = false;
|
||||||
ClientMediaDownloader *m_media_downloader;
|
ClientMediaDownloader *m_media_downloader;
|
||||||
|
|
||||||
// time_of_day speed approximation for old protocol
|
// time_of_day speed approximation for old protocol
|
||||||
@ -556,6 +559,12 @@ private:
|
|||||||
// And relations to objects
|
// And relations to objects
|
||||||
std::unordered_map<int, u16> m_sounds_to_objects;
|
std::unordered_map<int, u16> m_sounds_to_objects;
|
||||||
|
|
||||||
|
// CSM/client IDs to SSM/server IDs Mapping
|
||||||
|
// Map server particle spawner IDs to client IDs
|
||||||
|
std::unordered_map<u32, u32> m_particles_server_to_client;
|
||||||
|
// Map server hud ids to client hud ids
|
||||||
|
std::unordered_map<u32, u32> m_hud_server_to_client;
|
||||||
|
|
||||||
// Privileges
|
// Privileges
|
||||||
std::unordered_set<std::string> m_privileges;
|
std::unordered_set<std::string> m_privileges;
|
||||||
|
|
||||||
@ -571,6 +580,8 @@ private:
|
|||||||
// own state
|
// own state
|
||||||
LocalClientState m_state;
|
LocalClientState m_state;
|
||||||
|
|
||||||
|
GameUI *m_game_ui;
|
||||||
|
|
||||||
// Used for saving server map to disk client-side
|
// Used for saving server map to disk client-side
|
||||||
MapDatabase *m_localdb = nullptr;
|
MapDatabase *m_localdb = nullptr;
|
||||||
IntervalLimiter m_localdb_save_interval;
|
IntervalLimiter m_localdb_save_interval;
|
||||||
@ -581,7 +592,6 @@ private:
|
|||||||
std::unordered_map<std::string, ModMetadata *> m_mod_storages;
|
std::unordered_map<std::string, ModMetadata *> m_mod_storages;
|
||||||
float m_mod_storage_save_timer = 10.0f;
|
float m_mod_storage_save_timer = 10.0f;
|
||||||
std::vector<ModSpec> m_mods;
|
std::vector<ModSpec> m_mods;
|
||||||
GameUIFlags *m_game_ui_flags;
|
|
||||||
|
|
||||||
bool m_shutdown = false;
|
bool m_shutdown = false;
|
||||||
|
|
||||||
|
@ -9,8 +9,10 @@ set(client_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/render/stereo.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/render/stereo.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/renderingengine.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/renderingengine.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/gameui.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/inputhandler.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/inputhandler.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/hud.cpp
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
@ -116,7 +116,7 @@ struct ClientEvent
|
|||||||
} delete_particlespawner;
|
} delete_particlespawner;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u32 id;
|
u32 server_id;
|
||||||
u8 type;
|
u8 type;
|
||||||
v2f *pos;
|
v2f *pos;
|
||||||
std::string *name;
|
std::string *name;
|
||||||
|
304
src/client/gameui.cpp
Normal file
304
src/client/gameui.cpp
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2018 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gameui.h"
|
||||||
|
#include <irrlicht_changes/static_text.h>
|
||||||
|
#include <gettext.h>
|
||||||
|
#include "gui/mainmenumanager.h"
|
||||||
|
#include "util/pointedthing.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "clientmap.h"
|
||||||
|
#include "fontengine.h"
|
||||||
|
#include "nodedef.h"
|
||||||
|
#include "profiler.h"
|
||||||
|
#include "renderingengine.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
inline static const char *yawToDirectionString(int yaw)
|
||||||
|
{
|
||||||
|
static const char *direction[4] = {"N +Z", "W -X", "S -Z", "E +X"};
|
||||||
|
|
||||||
|
yaw = wrapDegrees_0_360(yaw);
|
||||||
|
yaw = (yaw + 45) % 360 / 90;
|
||||||
|
|
||||||
|
return direction[yaw];
|
||||||
|
}
|
||||||
|
|
||||||
|
GameUI::GameUI()
|
||||||
|
{
|
||||||
|
if (guienv && guienv->getSkin())
|
||||||
|
m_statustext_initial_color = guienv->getSkin()->getColor(gui::EGDC_BUTTON_TEXT);
|
||||||
|
else
|
||||||
|
m_statustext_initial_color = video::SColor(255, 0, 0, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
void GameUI::init()
|
||||||
|
{
|
||||||
|
// First line of debug text
|
||||||
|
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
|
||||||
|
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
|
||||||
|
|
||||||
|
// Second line of debug text
|
||||||
|
m_guitext2 = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
|
||||||
|
false, guiroot);
|
||||||
|
|
||||||
|
// At the middle of the screen
|
||||||
|
// Object infos are shown in this
|
||||||
|
m_guitext_info = gui::StaticText::add(guienv, L"",
|
||||||
|
core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5)
|
||||||
|
+ v2s32(100, 200), false, true, guiroot);
|
||||||
|
|
||||||
|
// Status text (displays info when showing and hiding GUI stuff, etc.)
|
||||||
|
m_guitext_status = gui::StaticText::add(guienv, L"<Status>",
|
||||||
|
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
|
||||||
|
m_guitext_status->setVisible(false);
|
||||||
|
|
||||||
|
// Chat text
|
||||||
|
m_guitext_chat = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0),
|
||||||
|
//false, false); // Disable word wrap as of now
|
||||||
|
false, true, guiroot);
|
||||||
|
|
||||||
|
// Profiler text (size is updated when text is updated)
|
||||||
|
m_guitext_profiler = gui::StaticText::add(guienv, L"<Profiler>",
|
||||||
|
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
|
||||||
|
m_guitext_profiler->setBackgroundColor(video::SColor(120, 0, 0, 0));
|
||||||
|
m_guitext_profiler->setVisible(false);
|
||||||
|
m_guitext_profiler->setWordWrap(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
|
||||||
|
const CameraOrientation &cam, const PointedThing &pointed_old, float dtime)
|
||||||
|
{
|
||||||
|
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
|
||||||
|
|
||||||
|
if (m_flags.show_debug) {
|
||||||
|
static float drawtime_avg = 0;
|
||||||
|
drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
|
||||||
|
u16 fps = 1.0 / stats.dtime_jitter.avg;
|
||||||
|
|
||||||
|
std::ostringstream os(std::ios_base::binary);
|
||||||
|
os << std::fixed
|
||||||
|
<< PROJECT_NAME_C " " << g_version_hash
|
||||||
|
<< ", FPS: " << fps
|
||||||
|
<< std::setprecision(0)
|
||||||
|
<< ", drawtime: " << drawtime_avg << "ms"
|
||||||
|
<< std::setprecision(1)
|
||||||
|
<< ", dtime jitter: "
|
||||||
|
<< (stats.dtime_jitter.max_fraction * 100.0) << "%"
|
||||||
|
<< std::setprecision(1)
|
||||||
|
<< ", view range: "
|
||||||
|
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
|
||||||
|
<< std::setprecision(3)
|
||||||
|
<< ", RTT: " << client->getRTT() << "s";
|
||||||
|
setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
|
||||||
|
|
||||||
|
m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X,
|
||||||
|
5 + g_fontengine->getTextHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally set the guitext visible depending on the flag
|
||||||
|
m_guitext->setVisible(m_flags.show_debug);
|
||||||
|
|
||||||
|
if (m_flags.show_debug) {
|
||||||
|
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||||
|
v3f player_position = player->getPosition();
|
||||||
|
|
||||||
|
std::ostringstream os(std::ios_base::binary);
|
||||||
|
os << std::setprecision(1) << std::fixed
|
||||||
|
<< "pos: (" << (player_position.X / BS)
|
||||||
|
<< ", " << (player_position.Y / BS)
|
||||||
|
<< ", " << (player_position.Z / BS)
|
||||||
|
<< "), yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
|
||||||
|
<< yawToDirectionString(cam.camera_yaw)
|
||||||
|
<< ", seed: " << ((u64)client->getMapSeed());
|
||||||
|
|
||||||
|
if (pointed_old.type == POINTEDTHING_NODE) {
|
||||||
|
ClientMap &map = client->getEnv().getClientMap();
|
||||||
|
const INodeDefManager *nodedef = client->getNodeDefManager();
|
||||||
|
MapNode n = map.getNodeNoEx(pointed_old.node_undersurface);
|
||||||
|
|
||||||
|
if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
|
||||||
|
os << ", pointed: " << nodedef->get(n).name
|
||||||
|
<< ", param2: " << (u64) n.getParam2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setStaticText(m_guitext2, utf8_to_wide(os.str()).c_str());
|
||||||
|
|
||||||
|
m_guitext2->setRelativePosition(core::rect<s32>(5,
|
||||||
|
5 + g_fontengine->getTextHeight(), screensize.X,
|
||||||
|
5 + g_fontengine->getTextHeight() * 2
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_guitext2->setVisible(m_flags.show_debug);
|
||||||
|
|
||||||
|
setStaticText(m_guitext_info, translate_string(m_infotext).c_str());
|
||||||
|
m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0);
|
||||||
|
|
||||||
|
static const float statustext_time_max = 1.5f;
|
||||||
|
|
||||||
|
if (!m_statustext.empty()) {
|
||||||
|
m_statustext_time += dtime;
|
||||||
|
|
||||||
|
if (m_statustext_time >= statustext_time_max) {
|
||||||
|
clearStatusText();
|
||||||
|
m_statustext_time = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setStaticText(m_guitext_status, translate_string(m_statustext).c_str());
|
||||||
|
m_guitext_status->setVisible(!m_statustext.empty());
|
||||||
|
|
||||||
|
if (!m_statustext.empty()) {
|
||||||
|
s32 status_width = m_guitext_status->getTextWidth();
|
||||||
|
s32 status_height = m_guitext_status->getTextHeight();
|
||||||
|
s32 status_y = screensize.Y - 150;
|
||||||
|
s32 status_x = (screensize.X - status_width) / 2;
|
||||||
|
|
||||||
|
m_guitext_status->setRelativePosition(core::rect<s32>(status_x ,
|
||||||
|
status_y - status_height, status_x + status_width, status_y));
|
||||||
|
|
||||||
|
// Fade out
|
||||||
|
video::SColor final_color = m_statustext_initial_color;
|
||||||
|
final_color.setAlpha(0);
|
||||||
|
video::SColor fade_color = m_statustext_initial_color.getInterpolated_quadratic(
|
||||||
|
m_statustext_initial_color, final_color, m_statustext_time / statustext_time_max);
|
||||||
|
m_guitext_status->setOverrideColor(fade_color);
|
||||||
|
m_guitext_status->enableOverrideColor(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::initFlags()
|
||||||
|
{
|
||||||
|
memset(&m_flags, 0, sizeof(GameUI::Flags));
|
||||||
|
m_flags.show_chat = true;
|
||||||
|
m_flags.show_hud = true;
|
||||||
|
m_flags.show_debug = g_settings->getBool("show_debug");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::showMinimap(bool show)
|
||||||
|
{
|
||||||
|
m_flags.show_minimap = show;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::showTranslatedStatusText(const char *str)
|
||||||
|
{
|
||||||
|
const wchar_t *wmsg = wgettext(str);
|
||||||
|
showStatusText(wmsg);
|
||||||
|
delete[] wmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
|
||||||
|
{
|
||||||
|
setStaticText(m_guitext_chat, chat_text);
|
||||||
|
|
||||||
|
// Update gui element size and position
|
||||||
|
s32 chat_y = 5;
|
||||||
|
|
||||||
|
if (m_flags.show_debug)
|
||||||
|
chat_y += 2 * g_fontengine->getLineHeight();
|
||||||
|
|
||||||
|
// first pass to calculate height of text to be set
|
||||||
|
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
||||||
|
s32 width = std::min(g_fontengine->getTextWidth(chat_text.c_str()) + 10,
|
||||||
|
window_size.X - 20);
|
||||||
|
m_guitext_chat->setRelativePosition(core::rect<s32>(10, chat_y, width,
|
||||||
|
chat_y + window_size.Y));
|
||||||
|
|
||||||
|
// now use real height of text and adjust rect according to this size
|
||||||
|
m_guitext_chat->setRelativePosition(core::rect<s32>(10, chat_y, width,
|
||||||
|
chat_y + m_guitext_chat->getTextHeight()));
|
||||||
|
|
||||||
|
// Don't show chat if disabled or empty or profiler is enabled
|
||||||
|
m_guitext_chat->setVisible(m_flags.show_chat &&
|
||||||
|
recent_chat_count != 0 && m_profiler_current_page == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::updateProfiler()
|
||||||
|
{
|
||||||
|
if (m_profiler_current_page != 0) {
|
||||||
|
std::ostringstream os(std::ios_base::binary);
|
||||||
|
g_profiler->printPage(os, m_profiler_current_page, m_profiler_max_page);
|
||||||
|
|
||||||
|
std::wstring text = translate_string(utf8_to_wide(os.str()));
|
||||||
|
setStaticText(m_guitext_profiler, text.c_str());
|
||||||
|
|
||||||
|
s32 w = g_fontengine->getTextWidth(text);
|
||||||
|
|
||||||
|
if (w < 400)
|
||||||
|
w = 400;
|
||||||
|
|
||||||
|
u32 text_height = g_fontengine->getTextHeight();
|
||||||
|
|
||||||
|
core::position2di upper_left, lower_right;
|
||||||
|
|
||||||
|
upper_left.X = 6;
|
||||||
|
upper_left.Y = (text_height + 5) * 2;
|
||||||
|
lower_right.X = 12 + w;
|
||||||
|
lower_right.Y = upper_left.Y + (text_height + 1) * MAX_PROFILER_TEXT_ROWS;
|
||||||
|
|
||||||
|
s32 screen_height = RenderingEngine::get_video_driver()->getScreenSize().Height;
|
||||||
|
|
||||||
|
if (lower_right.Y > screen_height * 2 / 3)
|
||||||
|
lower_right.Y = screen_height * 2 / 3;
|
||||||
|
|
||||||
|
m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_guitext_profiler->setVisible(m_profiler_current_page != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::toggleChat()
|
||||||
|
{
|
||||||
|
m_flags.show_chat = !m_flags.show_chat;
|
||||||
|
if (m_flags.show_chat)
|
||||||
|
showTranslatedStatusText("Chat shown");
|
||||||
|
else
|
||||||
|
showTranslatedStatusText("Chat hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::toggleHud()
|
||||||
|
{
|
||||||
|
m_flags.show_hud = !m_flags.show_hud;
|
||||||
|
if (m_flags.show_hud)
|
||||||
|
showTranslatedStatusText("HUD shown");
|
||||||
|
else
|
||||||
|
showTranslatedStatusText("HUD hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameUI::toggleProfiler()
|
||||||
|
{
|
||||||
|
m_profiler_current_page = (m_profiler_current_page + 1) % (m_profiler_max_page + 1);
|
||||||
|
|
||||||
|
// FIXME: This updates the profiler with incomplete values
|
||||||
|
updateProfiler();
|
||||||
|
|
||||||
|
if (m_profiler_current_page != 0) {
|
||||||
|
wchar_t buf[255];
|
||||||
|
const wchar_t* str = wgettext("Profiler shown (page %d of %d)");
|
||||||
|
swprintf(buf, sizeof(buf) / sizeof(wchar_t), str,
|
||||||
|
m_profiler_current_page, m_profiler_max_page);
|
||||||
|
delete[] str;
|
||||||
|
showStatusText(buf);
|
||||||
|
} else {
|
||||||
|
showTranslatedStatusText("Profiler hidden");
|
||||||
|
}
|
||||||
|
}
|
110
src/client/gameui.h
Normal file
110
src/client/gameui.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2018 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <IGUIEnvironment.h>
|
||||||
|
#include "util/enriched_string.h"
|
||||||
|
#include "util/pointedthing.h"
|
||||||
|
#include "game.h"
|
||||||
|
|
||||||
|
using namespace irr;
|
||||||
|
class Client;
|
||||||
|
struct MapDrawControl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This object intend to contain the core UI elements
|
||||||
|
* It includes:
|
||||||
|
* - status texts
|
||||||
|
* - debug texts
|
||||||
|
* - chat texts
|
||||||
|
* - hud flags
|
||||||
|
*/
|
||||||
|
class GameUI
|
||||||
|
{
|
||||||
|
// Temporary between coding time to move things here
|
||||||
|
friend class Game;
|
||||||
|
|
||||||
|
// Permit unittests to access members directly
|
||||||
|
friend class TestGameUI;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GameUI();
|
||||||
|
~GameUI() = default;
|
||||||
|
|
||||||
|
// Flags that can, or may, change during main game loop
|
||||||
|
struct Flags
|
||||||
|
{
|
||||||
|
bool show_chat = true;
|
||||||
|
bool show_hud = true;
|
||||||
|
bool show_minimap = true;
|
||||||
|
bool show_debug = true;
|
||||||
|
bool show_profiler_graph = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
|
||||||
|
const CameraOrientation &cam, const PointedThing &pointed_old,
|
||||||
|
float dtime);
|
||||||
|
|
||||||
|
void initFlags();
|
||||||
|
const Flags &getFlags() const { return m_flags; }
|
||||||
|
|
||||||
|
void showMinimap(bool show);
|
||||||
|
|
||||||
|
inline void setInfoText(const std::wstring &str) { m_infotext = str; }
|
||||||
|
inline void clearInfoText() { m_infotext.clear(); }
|
||||||
|
|
||||||
|
inline void showStatusText(const std::wstring &str)
|
||||||
|
{
|
||||||
|
m_statustext = str;
|
||||||
|
m_statustext_time = 0.0f;
|
||||||
|
}
|
||||||
|
void showTranslatedStatusText(const char *str);
|
||||||
|
inline void clearStatusText() { m_statustext.clear(); }
|
||||||
|
|
||||||
|
void setChatText(const EnrichedString &chat_text, u32 recent_chat_count);
|
||||||
|
|
||||||
|
void updateProfiler();
|
||||||
|
|
||||||
|
void toggleChat();
|
||||||
|
void toggleHud();
|
||||||
|
void toggleProfiler();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Flags m_flags;
|
||||||
|
|
||||||
|
gui::IGUIStaticText *m_guitext = nullptr; // First line of debug text
|
||||||
|
gui::IGUIStaticText *m_guitext2 = nullptr; // Second line of debug text
|
||||||
|
|
||||||
|
gui::IGUIStaticText *m_guitext_info = nullptr; // At the middle of the screen
|
||||||
|
std::wstring m_infotext;
|
||||||
|
|
||||||
|
gui::IGUIStaticText *m_guitext_status = nullptr;
|
||||||
|
std::wstring m_statustext;
|
||||||
|
float m_statustext_time = 0.0f;
|
||||||
|
video::SColor m_statustext_initial_color;
|
||||||
|
|
||||||
|
gui::IGUIStaticText *m_guitext_chat = nullptr; // Chat text
|
||||||
|
|
||||||
|
gui::IGUIStaticText *m_guitext_profiler = nullptr; // Profiler text
|
||||||
|
u8 m_profiler_current_page = 0;
|
||||||
|
const u8 m_profiler_max_page = 3;
|
||||||
|
};
|
775
src/client/hud.cpp
Normal file
775
src/client/hud.cpp
Normal file
@ -0,0 +1,775 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2010-2013 blue42u, Jonathon Anderson <anderjon@umail.iu.edu>
|
||||||
|
Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "client/hud.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "util/numeric.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "inventory.h"
|
||||||
|
#include "shader.h"
|
||||||
|
#include "client/tile.h"
|
||||||
|
#include "localplayer.h"
|
||||||
|
#include "camera.h"
|
||||||
|
#include "porting.h"
|
||||||
|
#include "fontengine.h"
|
||||||
|
#include "guiscalingfilter.h"
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "wieldmesh.h"
|
||||||
|
#include "client/renderingengine.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
|
#include "gui/touchscreengui.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
|
||||||
|
Inventory *inventory)
|
||||||
|
{
|
||||||
|
driver = RenderingEngine::get_video_driver();
|
||||||
|
this->guienv = guienv;
|
||||||
|
this->client = client;
|
||||||
|
this->player = player;
|
||||||
|
this->inventory = inventory;
|
||||||
|
|
||||||
|
m_hud_scaling = g_settings->getFloat("hud_scaling");
|
||||||
|
m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
|
||||||
|
RenderingEngine::getDisplayDensity() + 0.5f);
|
||||||
|
m_hotbar_imagesize *= m_hud_scaling;
|
||||||
|
m_padding = m_hotbar_imagesize / 12;
|
||||||
|
|
||||||
|
for (auto &hbar_color : hbar_colors)
|
||||||
|
hbar_color = video::SColor(255, 255, 255, 255);
|
||||||
|
|
||||||
|
tsrc = client->getTextureSource();
|
||||||
|
|
||||||
|
v3f crosshair_color = g_settings->getV3F("crosshair_color");
|
||||||
|
u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
|
||||||
|
u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
|
||||||
|
u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
|
||||||
|
u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
|
||||||
|
crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
|
||||||
|
|
||||||
|
v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
|
||||||
|
u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
|
||||||
|
u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
|
||||||
|
u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
|
||||||
|
selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
|
||||||
|
|
||||||
|
use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
|
||||||
|
|
||||||
|
m_selection_boxes.clear();
|
||||||
|
m_halo_boxes.clear();
|
||||||
|
|
||||||
|
std::string mode_setting = g_settings->get("node_highlighting");
|
||||||
|
|
||||||
|
if (mode_setting == "halo") {
|
||||||
|
m_mode = HIGHLIGHT_HALO;
|
||||||
|
} else if (mode_setting == "none") {
|
||||||
|
m_mode = HIGHLIGHT_NONE;
|
||||||
|
} else {
|
||||||
|
m_mode = HIGHLIGHT_BOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_selection_material.Lighting = false;
|
||||||
|
|
||||||
|
if (g_settings->getBool("enable_shaders")) {
|
||||||
|
IShaderSource *shdrsrc = client->getShaderSource();
|
||||||
|
u16 shader_id = shdrsrc->getShader(
|
||||||
|
m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1);
|
||||||
|
m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
|
||||||
|
} else {
|
||||||
|
m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_mode == HIGHLIGHT_BOX) {
|
||||||
|
m_selection_material.Thickness =
|
||||||
|
rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
|
||||||
|
} else if (m_mode == HIGHLIGHT_HALO) {
|
||||||
|
m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png"));
|
||||||
|
m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
|
||||||
|
} else {
|
||||||
|
m_selection_material.MaterialType = video::EMT_SOLID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hud::~Hud()
|
||||||
|
{
|
||||||
|
if (m_selection_mesh)
|
||||||
|
m_selection_mesh->drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
|
||||||
|
bool selected)
|
||||||
|
{
|
||||||
|
if (selected) {
|
||||||
|
/* draw hihlighting around selected item */
|
||||||
|
if (use_hotbar_selected_image) {
|
||||||
|
core::rect<s32> imgrect2 = rect;
|
||||||
|
imgrect2.UpperLeftCorner.X -= (m_padding*2);
|
||||||
|
imgrect2.UpperLeftCorner.Y -= (m_padding*2);
|
||||||
|
imgrect2.LowerRightCorner.X += (m_padding*2);
|
||||||
|
imgrect2.LowerRightCorner.Y += (m_padding*2);
|
||||||
|
video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
|
||||||
|
core::dimension2di imgsize(texture->getOriginalSize());
|
||||||
|
draw2DImageFilterScaled(driver, texture, imgrect2,
|
||||||
|
core::rect<s32>(core::position2d<s32>(0,0), imgsize),
|
||||||
|
NULL, hbar_colors, true);
|
||||||
|
} else {
|
||||||
|
video::SColor c_outside(255,255,0,0);
|
||||||
|
//video::SColor c_outside(255,0,0,0);
|
||||||
|
//video::SColor c_inside(255,192,192,192);
|
||||||
|
s32 x1 = rect.UpperLeftCorner.X;
|
||||||
|
s32 y1 = rect.UpperLeftCorner.Y;
|
||||||
|
s32 x2 = rect.LowerRightCorner.X;
|
||||||
|
s32 y2 = rect.LowerRightCorner.Y;
|
||||||
|
// Black base borders
|
||||||
|
driver->draw2DRectangle(c_outside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x1 - m_padding, y1 - m_padding),
|
||||||
|
v2s32(x2 + m_padding, y1)
|
||||||
|
), NULL);
|
||||||
|
driver->draw2DRectangle(c_outside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x1 - m_padding, y2),
|
||||||
|
v2s32(x2 + m_padding, y2 + m_padding)
|
||||||
|
), NULL);
|
||||||
|
driver->draw2DRectangle(c_outside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x1 - m_padding, y1),
|
||||||
|
v2s32(x1, y2)
|
||||||
|
), NULL);
|
||||||
|
driver->draw2DRectangle(c_outside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x2, y1),
|
||||||
|
v2s32(x2 + m_padding, y2)
|
||||||
|
), NULL);
|
||||||
|
/*// Light inside borders
|
||||||
|
driver->draw2DRectangle(c_inside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x1 - padding/2, y1 - padding/2),
|
||||||
|
v2s32(x2 + padding/2, y1)
|
||||||
|
), NULL);
|
||||||
|
driver->draw2DRectangle(c_inside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x1 - padding/2, y2),
|
||||||
|
v2s32(x2 + padding/2, y2 + padding/2)
|
||||||
|
), NULL);
|
||||||
|
driver->draw2DRectangle(c_inside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x1 - padding/2, y1),
|
||||||
|
v2s32(x1, y2)
|
||||||
|
), NULL);
|
||||||
|
driver->draw2DRectangle(c_inside,
|
||||||
|
core::rect<s32>(
|
||||||
|
v2s32(x2, y1),
|
||||||
|
v2s32(x2 + padding/2, y2)
|
||||||
|
), NULL);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
video::SColor bgcolor2(128, 0, 0, 0);
|
||||||
|
if (!use_hotbar_image)
|
||||||
|
driver->draw2DRectangle(bgcolor2, rect, NULL);
|
||||||
|
drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL,
|
||||||
|
client, selected ? IT_ROT_SELECTED : IT_ROT_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: selectitem = 0 -> no selected; selectitem 1-based
|
||||||
|
void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
|
||||||
|
s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
|
if (g_touchscreengui && inv_offset == 0)
|
||||||
|
g_touchscreengui->resetHud();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s32 height = m_hotbar_imagesize + m_padding * 2;
|
||||||
|
s32 width = (itemcount - inv_offset) * (m_hotbar_imagesize + m_padding * 2);
|
||||||
|
|
||||||
|
if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
|
||||||
|
s32 tmp = height;
|
||||||
|
height = width;
|
||||||
|
width = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position of upper left corner of bar
|
||||||
|
v2s32 pos = screen_offset;
|
||||||
|
pos.X *= m_hud_scaling * RenderingEngine::getDisplayDensity();
|
||||||
|
pos.Y *= m_hud_scaling * RenderingEngine::getDisplayDensity();
|
||||||
|
pos += upperleftpos;
|
||||||
|
|
||||||
|
// Store hotbar_image in member variable, used by drawItem()
|
||||||
|
if (hotbar_image != player->hotbar_image) {
|
||||||
|
hotbar_image = player->hotbar_image;
|
||||||
|
if (!hotbar_image.empty())
|
||||||
|
use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
|
||||||
|
else
|
||||||
|
use_hotbar_image = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store hotbar_selected_image in member variable, used by drawItem()
|
||||||
|
if (hotbar_selected_image != player->hotbar_selected_image) {
|
||||||
|
hotbar_selected_image = player->hotbar_selected_image;
|
||||||
|
if (!hotbar_selected_image.empty())
|
||||||
|
use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
|
||||||
|
else
|
||||||
|
use_hotbar_selected_image = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw customized item background
|
||||||
|
if (use_hotbar_image) {
|
||||||
|
core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
|
||||||
|
width+m_padding/2, height+m_padding/2);
|
||||||
|
core::rect<s32> rect2 = imgrect2 + pos;
|
||||||
|
video::ITexture *texture = tsrc->getTexture(hotbar_image);
|
||||||
|
core::dimension2di imgsize(texture->getOriginalSize());
|
||||||
|
draw2DImageFilterScaled(driver, texture, rect2,
|
||||||
|
core::rect<s32>(core::position2d<s32>(0,0), imgsize),
|
||||||
|
NULL, hbar_colors, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw items
|
||||||
|
core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
|
||||||
|
for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) {
|
||||||
|
s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
|
||||||
|
|
||||||
|
v2s32 steppos;
|
||||||
|
switch (direction) {
|
||||||
|
case HUD_DIR_RIGHT_LEFT:
|
||||||
|
steppos = v2s32(-(m_padding + (i - inv_offset) * fullimglen), m_padding);
|
||||||
|
break;
|
||||||
|
case HUD_DIR_TOP_BOTTOM:
|
||||||
|
steppos = v2s32(m_padding, m_padding + (i - inv_offset) * fullimglen);
|
||||||
|
break;
|
||||||
|
case HUD_DIR_BOTTOM_TOP:
|
||||||
|
steppos = v2s32(m_padding, -(m_padding + (i - inv_offset) * fullimglen));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
steppos = v2s32(m_padding + (i - inv_offset) * fullimglen, m_padding);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i + 1) == selectitem);
|
||||||
|
|
||||||
|
#ifdef HAVE_TOUCHSCREENGUI
|
||||||
|
if (g_touchscreengui)
|
||||||
|
g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Hud::drawLuaElements(const v3s16 &camera_offset)
|
||||||
|
{
|
||||||
|
u32 text_height = g_fontengine->getTextHeight();
|
||||||
|
irr::gui::IGUIFont* font = g_fontengine->getFont();
|
||||||
|
for (size_t i = 0; i != player->maxHudId(); i++) {
|
||||||
|
HudElement *e = player->getHud(i);
|
||||||
|
if (!e)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
|
||||||
|
floor(e->pos.Y * (float) m_screensize.Y + 0.5));
|
||||||
|
switch (e->type) {
|
||||||
|
case HUD_ELEM_IMAGE: {
|
||||||
|
video::ITexture *texture = tsrc->getTexture(e->text);
|
||||||
|
if (!texture)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const video::SColor color(255, 255, 255, 255);
|
||||||
|
const video::SColor colors[] = {color, color, color, color};
|
||||||
|
core::dimension2di imgsize(texture->getOriginalSize());
|
||||||
|
v2s32 dstsize(imgsize.Width * e->scale.X,
|
||||||
|
imgsize.Height * e->scale.Y);
|
||||||
|
if (e->scale.X < 0)
|
||||||
|
dstsize.X = m_screensize.X * (e->scale.X * -0.01);
|
||||||
|
if (e->scale.Y < 0)
|
||||||
|
dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
|
||||||
|
v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
|
||||||
|
(e->align.Y - 1.0) * dstsize.Y / 2);
|
||||||
|
core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
|
||||||
|
rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
|
||||||
|
draw2DImageFilterScaled(driver, texture, rect,
|
||||||
|
core::rect<s32>(core::position2d<s32>(0,0), imgsize),
|
||||||
|
NULL, colors, true);
|
||||||
|
break; }
|
||||||
|
case HUD_ELEM_TEXT: {
|
||||||
|
video::SColor color(255, (e->number >> 16) & 0xFF,
|
||||||
|
(e->number >> 8) & 0xFF,
|
||||||
|
(e->number >> 0) & 0xFF);
|
||||||
|
core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
|
||||||
|
std::wstring text = unescape_translate(utf8_to_wide(e->text));
|
||||||
|
core::dimension2d<u32> textsize = font->getDimension(text.c_str());
|
||||||
|
v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
|
||||||
|
(e->align.Y - 1.0) * (textsize.Height / 2));
|
||||||
|
v2s32 offs(e->offset.X, e->offset.Y);
|
||||||
|
font->draw(text.c_str(), size + pos + offset + offs, color);
|
||||||
|
break; }
|
||||||
|
case HUD_ELEM_STATBAR: {
|
||||||
|
v2s32 offs(e->offset.X, e->offset.Y);
|
||||||
|
drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
|
||||||
|
break; }
|
||||||
|
case HUD_ELEM_INVENTORY: {
|
||||||
|
InventoryList *inv = inventory->getList(e->text);
|
||||||
|
drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0,
|
||||||
|
inv, e->item, e->dir);
|
||||||
|
break; }
|
||||||
|
case HUD_ELEM_WAYPOINT: {
|
||||||
|
v3f p_pos = player->getPosition() / BS;
|
||||||
|
v3f w_pos = e->world_pos * BS;
|
||||||
|
float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
|
||||||
|
scene::ICameraSceneNode* camera =
|
||||||
|
RenderingEngine::get_scene_manager()->getActiveCamera();
|
||||||
|
w_pos -= intToFloat(camera_offset, BS);
|
||||||
|
core::matrix4 trans = camera->getProjectionMatrix();
|
||||||
|
trans *= camera->getViewMatrix();
|
||||||
|
f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
|
||||||
|
trans.multiplyWith1x4Matrix(transformed_pos);
|
||||||
|
if (transformed_pos[3] < 0)
|
||||||
|
break;
|
||||||
|
f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
|
||||||
|
core::reciprocal(transformed_pos[3]);
|
||||||
|
pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
|
||||||
|
pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
|
||||||
|
video::SColor color(255, (e->number >> 16) & 0xFF,
|
||||||
|
(e->number >> 8) & 0xFF,
|
||||||
|
(e->number >> 0) & 0xFF);
|
||||||
|
core::rect<s32> size(0, 0, 200, 2 * text_height);
|
||||||
|
std::wstring text = unescape_translate(utf8_to_wide(e->name));
|
||||||
|
font->draw(text.c_str(), size + pos, color);
|
||||||
|
std::ostringstream os;
|
||||||
|
os << distance << e->text;
|
||||||
|
text = unescape_translate(utf8_to_wide(os.str()));
|
||||||
|
pos.Y += text_height;
|
||||||
|
font->draw(text.c_str(), size + pos, color);
|
||||||
|
break; }
|
||||||
|
default:
|
||||||
|
infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
|
||||||
|
" of hud element ID " << i << " due to unrecognized type" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
|
||||||
|
s32 count, v2s32 offset, v2s32 size)
|
||||||
|
{
|
||||||
|
const video::SColor color(255, 255, 255, 255);
|
||||||
|
const video::SColor colors[] = {color, color, color, color};
|
||||||
|
|
||||||
|
video::ITexture *stat_texture = tsrc->getTexture(texture);
|
||||||
|
if (!stat_texture)
|
||||||
|
return;
|
||||||
|
|
||||||
|
core::dimension2di srcd(stat_texture->getOriginalSize());
|
||||||
|
core::dimension2di dstd;
|
||||||
|
if (size == v2s32()) {
|
||||||
|
dstd = srcd;
|
||||||
|
} else {
|
||||||
|
float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity();
|
||||||
|
dstd.Height = size.Y * size_factor;
|
||||||
|
dstd.Width = size.X * size_factor;
|
||||||
|
offset.X *= size_factor;
|
||||||
|
offset.Y *= size_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
v2s32 p = pos;
|
||||||
|
if (corner & HUD_CORNER_LOWER)
|
||||||
|
p -= dstd.Height;
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
|
||||||
|
core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
|
||||||
|
|
||||||
|
dstrect += p;
|
||||||
|
draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
|
||||||
|
p += steppos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count % 2 == 1) {
|
||||||
|
dsthalfrect += p;
|
||||||
|
draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Hud::drawHotbar(u16 playeritem) {
|
||||||
|
|
||||||
|
v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
|
||||||
|
|
||||||
|
InventoryList *mainlist = inventory->getList("main");
|
||||||
|
if (mainlist == NULL) {
|
||||||
|
//silently ignore this we may not be initialized completely
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 hotbar_itemcount = player->hud_hotbar_itemcount;
|
||||||
|
s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
|
||||||
|
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
|
||||||
|
|
||||||
|
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
||||||
|
if ( (float) width / (float) window_size.X <=
|
||||||
|
g_settings->getFloat("hud_hotbar_max_width")) {
|
||||||
|
if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
|
||||||
|
drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pos.X += width/4;
|
||||||
|
|
||||||
|
v2s32 secondpos = pos;
|
||||||
|
pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
|
||||||
|
|
||||||
|
if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
|
||||||
|
drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
|
||||||
|
mainlist, playeritem + 1, 0);
|
||||||
|
drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
|
||||||
|
hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////// compatibility code to be removed //////////////
|
||||||
|
// this is ugly as hell but there's no other way to keep compatibility to
|
||||||
|
// old servers
|
||||||
|
if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) {
|
||||||
|
drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
|
||||||
|
floor(1 * (float) m_screensize.Y + 0.5)),
|
||||||
|
HUD_CORNER_UPPER, 0, "heart.png",
|
||||||
|
player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
|
||||||
|
(player->getBreath() < 11)) {
|
||||||
|
drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
|
||||||
|
floor(1 * (float) m_screensize.Y + 0.5)),
|
||||||
|
HUD_CORNER_UPPER, 0, "bubble.png",
|
||||||
|
player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Hud::drawCrosshair()
|
||||||
|
{
|
||||||
|
if (use_crosshair_image) {
|
||||||
|
video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
|
||||||
|
v2u32 size = crosshair->getOriginalSize();
|
||||||
|
v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
|
||||||
|
m_displaycenter.Y - (size.Y / 2));
|
||||||
|
driver->draw2DImage(crosshair, lsize,
|
||||||
|
core::rect<s32>(0, 0, size.X, size.Y),
|
||||||
|
0, crosshair_argb, true);
|
||||||
|
} else {
|
||||||
|
driver->draw2DLine(m_displaycenter - v2s32(10, 0),
|
||||||
|
m_displaycenter + v2s32(10, 0), crosshair_argb);
|
||||||
|
driver->draw2DLine(m_displaycenter - v2s32(0, 10),
|
||||||
|
m_displaycenter + v2s32(0, 10), crosshair_argb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
|
||||||
|
{
|
||||||
|
m_camera_offset = camera_offset;
|
||||||
|
m_selection_pos = pos;
|
||||||
|
m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hud::drawSelectionMesh()
|
||||||
|
{
|
||||||
|
if (m_mode == HIGHLIGHT_BOX) {
|
||||||
|
// Draw 3D selection boxes
|
||||||
|
video::SMaterial oldmaterial = driver->getMaterial2D();
|
||||||
|
driver->setMaterial(m_selection_material);
|
||||||
|
for (std::vector<aabb3f>::const_iterator
|
||||||
|
i = m_selection_boxes.begin();
|
||||||
|
i != m_selection_boxes.end(); ++i) {
|
||||||
|
aabb3f box = aabb3f(
|
||||||
|
i->MinEdge + m_selection_pos_with_offset,
|
||||||
|
i->MaxEdge + m_selection_pos_with_offset);
|
||||||
|
|
||||||
|
u32 r = (selectionbox_argb.getRed() *
|
||||||
|
m_selection_mesh_color.getRed() / 255);
|
||||||
|
u32 g = (selectionbox_argb.getGreen() *
|
||||||
|
m_selection_mesh_color.getGreen() / 255);
|
||||||
|
u32 b = (selectionbox_argb.getBlue() *
|
||||||
|
m_selection_mesh_color.getBlue() / 255);
|
||||||
|
driver->draw3DBox(box, video::SColor(255, r, g, b));
|
||||||
|
}
|
||||||
|
driver->setMaterial(oldmaterial);
|
||||||
|
} else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
|
||||||
|
// Draw selection mesh
|
||||||
|
video::SMaterial oldmaterial = driver->getMaterial2D();
|
||||||
|
driver->setMaterial(m_selection_material);
|
||||||
|
setMeshColor(m_selection_mesh, m_selection_mesh_color);
|
||||||
|
video::SColor face_color(0,
|
||||||
|
MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
|
||||||
|
MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
|
||||||
|
MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
|
||||||
|
setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
|
||||||
|
face_color);
|
||||||
|
scene::IMesh* mesh = cloneMesh(m_selection_mesh);
|
||||||
|
translateMesh(mesh, m_selection_pos_with_offset);
|
||||||
|
u32 mc = m_selection_mesh->getMeshBufferCount();
|
||||||
|
for (u32 i = 0; i < mc; i++) {
|
||||||
|
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||||
|
driver->drawMeshBuffer(buf);
|
||||||
|
}
|
||||||
|
mesh->drop();
|
||||||
|
driver->setMaterial(oldmaterial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hud::updateSelectionMesh(const v3s16 &camera_offset)
|
||||||
|
{
|
||||||
|
m_camera_offset = camera_offset;
|
||||||
|
if (m_mode != HIGHLIGHT_HALO)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_selection_mesh) {
|
||||||
|
m_selection_mesh->drop();
|
||||||
|
m_selection_mesh = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_selection_boxes.empty()) {
|
||||||
|
// No pointed object
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New pointed object, create new mesh.
|
||||||
|
|
||||||
|
// Texture UV coordinates for selection boxes
|
||||||
|
static f32 texture_uv[24] = {
|
||||||
|
0,0,1,1,
|
||||||
|
0,0,1,1,
|
||||||
|
0,0,1,1,
|
||||||
|
0,0,1,1,
|
||||||
|
0,0,1,1,
|
||||||
|
0,0,1,1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use single halo box instead of multiple overlapping boxes.
|
||||||
|
// Temporary solution - problem can be solved with multiple
|
||||||
|
// rendering targets, or some method to remove inner surfaces.
|
||||||
|
// Thats because of halo transparency.
|
||||||
|
|
||||||
|
aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
|
||||||
|
m_halo_boxes.clear();
|
||||||
|
|
||||||
|
for (const auto &selection_box : m_selection_boxes) {
|
||||||
|
halo_box.addInternalBox(selection_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_halo_boxes.push_back(halo_box);
|
||||||
|
m_selection_mesh = convertNodeboxesToMesh(
|
||||||
|
m_halo_boxes, texture_uv, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hud::resizeHotbar() {
|
||||||
|
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
||||||
|
|
||||||
|
if (m_screensize != window_size) {
|
||||||
|
m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
|
||||||
|
RenderingEngine::getDisplayDensity() + 0.5);
|
||||||
|
m_hotbar_imagesize *= m_hud_scaling;
|
||||||
|
m_padding = m_hotbar_imagesize / 12;
|
||||||
|
m_screensize = window_size;
|
||||||
|
m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MeshTimeInfo {
|
||||||
|
u64 time;
|
||||||
|
scene::IMesh *mesh;
|
||||||
|
};
|
||||||
|
|
||||||
|
void drawItemStack(video::IVideoDriver *driver,
|
||||||
|
gui::IGUIFont *font,
|
||||||
|
const ItemStack &item,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip,
|
||||||
|
Client *client,
|
||||||
|
ItemRotationKind rotation_kind)
|
||||||
|
{
|
||||||
|
static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
|
||||||
|
static thread_local bool enable_animations =
|
||||||
|
g_settings->getBool("inventory_items_animations");
|
||||||
|
|
||||||
|
if (item.empty()) {
|
||||||
|
if (rotation_kind < IT_ROT_NONE) {
|
||||||
|
rotation_time_infos[rotation_kind].mesh = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ItemDefinition &def = item.getDefinition(client->idef());
|
||||||
|
ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
|
||||||
|
|
||||||
|
if (imesh && imesh->mesh) {
|
||||||
|
scene::IMesh *mesh = imesh->mesh;
|
||||||
|
driver->clearZBuffer();
|
||||||
|
s32 delta = 0;
|
||||||
|
if (rotation_kind < IT_ROT_NONE) {
|
||||||
|
MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
|
||||||
|
if (mesh != ti.mesh) {
|
||||||
|
ti.mesh = mesh;
|
||||||
|
ti.time = porting::getTimeMs();
|
||||||
|
} else {
|
||||||
|
delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core::rect<s32> oldViewPort = driver->getViewPort();
|
||||||
|
core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
|
||||||
|
core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
|
||||||
|
core::matrix4 ProjMatrix;
|
||||||
|
ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
|
||||||
|
driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
|
||||||
|
driver->setTransform(video::ETS_VIEW, ProjMatrix);
|
||||||
|
core::matrix4 matrix;
|
||||||
|
matrix.makeIdentity();
|
||||||
|
|
||||||
|
if (enable_animations) {
|
||||||
|
float timer_f = (float) delta / 5000.0;
|
||||||
|
matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
driver->setTransform(video::ETS_WORLD, matrix);
|
||||||
|
driver->setViewPort(rect);
|
||||||
|
|
||||||
|
video::SColor basecolor =
|
||||||
|
client->idef()->getItemstackColor(item, client);
|
||||||
|
|
||||||
|
u32 mc = mesh->getMeshBufferCount();
|
||||||
|
for (u32 j = 0; j < mc; ++j) {
|
||||||
|
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||||
|
// we can modify vertices relatively fast,
|
||||||
|
// because these meshes are not buffered.
|
||||||
|
assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
|
||||||
|
video::SColor c = basecolor;
|
||||||
|
if (imesh->buffer_colors.size() > j) {
|
||||||
|
ItemPartColor *p = &imesh->buffer_colors[j];
|
||||||
|
if (p->override_base)
|
||||||
|
c = p->color;
|
||||||
|
}
|
||||||
|
if (imesh->needs_shading)
|
||||||
|
colorizeMeshBuffer(buf, &c);
|
||||||
|
else
|
||||||
|
setMeshBufferColor(buf, c);
|
||||||
|
video::SMaterial &material = buf->getMaterial();
|
||||||
|
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||||
|
material.Lighting = false;
|
||||||
|
driver->setMaterial(material);
|
||||||
|
driver->drawMeshBuffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
driver->setTransform(video::ETS_VIEW, oldViewMat);
|
||||||
|
driver->setTransform(video::ETS_PROJECTION, oldProjMat);
|
||||||
|
driver->setViewPort(oldViewPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(def.type == ITEM_TOOL && item.wear != 0)
|
||||||
|
{
|
||||||
|
// Draw a progressbar
|
||||||
|
float barheight = rect.getHeight()/16;
|
||||||
|
float barpad_x = rect.getWidth()/16;
|
||||||
|
float barpad_y = rect.getHeight()/16;
|
||||||
|
core::rect<s32> progressrect(
|
||||||
|
rect.UpperLeftCorner.X + barpad_x,
|
||||||
|
rect.LowerRightCorner.Y - barpad_y - barheight,
|
||||||
|
rect.LowerRightCorner.X - barpad_x,
|
||||||
|
rect.LowerRightCorner.Y - barpad_y);
|
||||||
|
|
||||||
|
// Shrink progressrect by amount of tool damage
|
||||||
|
float wear = item.wear / 65535.0;
|
||||||
|
int progressmid =
|
||||||
|
wear * progressrect.UpperLeftCorner.X +
|
||||||
|
(1-wear) * progressrect.LowerRightCorner.X;
|
||||||
|
|
||||||
|
// Compute progressbar color
|
||||||
|
// wear = 0.0: green
|
||||||
|
// wear = 0.5: yellow
|
||||||
|
// wear = 1.0: red
|
||||||
|
video::SColor color(255,255,255,255);
|
||||||
|
int wear_i = MYMIN(floor(wear * 600), 511);
|
||||||
|
wear_i = MYMIN(wear_i + 10, 511);
|
||||||
|
if(wear_i <= 255)
|
||||||
|
color.set(255, wear_i, 255, 0);
|
||||||
|
else
|
||||||
|
color.set(255, 255, 511-wear_i, 0);
|
||||||
|
|
||||||
|
core::rect<s32> progressrect2 = progressrect;
|
||||||
|
progressrect2.LowerRightCorner.X = progressmid;
|
||||||
|
driver->draw2DRectangle(color, progressrect2, clip);
|
||||||
|
|
||||||
|
color = video::SColor(255,0,0,0);
|
||||||
|
progressrect2 = progressrect;
|
||||||
|
progressrect2.UpperLeftCorner.X = progressmid;
|
||||||
|
driver->draw2DRectangle(color, progressrect2, clip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font != NULL && item.count >= 2)
|
||||||
|
{
|
||||||
|
// Get the item count as a string
|
||||||
|
std::string text = itos(item.count);
|
||||||
|
v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
|
||||||
|
v2s32 sdim(dim.X,dim.Y);
|
||||||
|
|
||||||
|
core::rect<s32> rect2(
|
||||||
|
/*rect.UpperLeftCorner,
|
||||||
|
core::dimension2d<u32>(rect.getWidth(), 15)*/
|
||||||
|
rect.LowerRightCorner - sdim,
|
||||||
|
sdim
|
||||||
|
);
|
||||||
|
|
||||||
|
video::SColor bgcolor(128,0,0,0);
|
||||||
|
driver->draw2DRectangle(bgcolor, rect2, clip);
|
||||||
|
|
||||||
|
video::SColor color(255,255,255,255);
|
||||||
|
font->draw(text.c_str(), rect2, color, false, false, clip);
|
||||||
|
}
|
||||||
|
}
|
136
src/client/hud.h
Normal file
136
src/client/hud.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
Copyright (C) 2017 red-001 <red-001@outlook.ie>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLIENT_HUD_HEADER
|
||||||
|
#define CLIENT_HUD_HEADER
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <IGUIFont.h>
|
||||||
|
#include "irr_aabb3d.h"
|
||||||
|
#include "../hud.h"
|
||||||
|
|
||||||
|
class Client;
|
||||||
|
class ITextureSource;
|
||||||
|
class Inventory;
|
||||||
|
class InventoryList;
|
||||||
|
class LocalPlayer;
|
||||||
|
struct ItemStack;
|
||||||
|
|
||||||
|
class Hud
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
video::IVideoDriver *driver;
|
||||||
|
scene::ISceneManager *smgr;
|
||||||
|
gui::IGUIEnvironment *guienv;
|
||||||
|
Client *client;
|
||||||
|
LocalPlayer *player;
|
||||||
|
Inventory *inventory;
|
||||||
|
ITextureSource *tsrc;
|
||||||
|
|
||||||
|
video::SColor crosshair_argb;
|
||||||
|
video::SColor selectionbox_argb;
|
||||||
|
bool use_crosshair_image = false;
|
||||||
|
std::string hotbar_image = "";
|
||||||
|
bool use_hotbar_image = false;
|
||||||
|
std::string hotbar_selected_image = "";
|
||||||
|
bool use_hotbar_selected_image = false;
|
||||||
|
|
||||||
|
Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
|
||||||
|
Inventory *inventory);
|
||||||
|
~Hud();
|
||||||
|
|
||||||
|
void drawHotbar(u16 playeritem);
|
||||||
|
void resizeHotbar();
|
||||||
|
void drawCrosshair();
|
||||||
|
void drawSelectionMesh();
|
||||||
|
void updateSelectionMesh(const v3s16 &camera_offset);
|
||||||
|
|
||||||
|
std::vector<aabb3f> *getSelectionBoxes() { return &m_selection_boxes; }
|
||||||
|
|
||||||
|
void setSelectionPos(const v3f &pos, const v3s16 &camera_offset);
|
||||||
|
|
||||||
|
v3f getSelectionPos() const { return m_selection_pos; }
|
||||||
|
|
||||||
|
void setSelectionMeshColor(const video::SColor &color)
|
||||||
|
{
|
||||||
|
m_selection_mesh_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSelectedFaceNormal(const v3f &face_normal)
|
||||||
|
{
|
||||||
|
m_selected_face_normal = face_normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawLuaElements(const v3s16 &camera_offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
|
||||||
|
s32 count, v2s32 offset, v2s32 size = v2s32());
|
||||||
|
|
||||||
|
void drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
|
||||||
|
s32 inv_offset, InventoryList *mainlist, u16 selectitem,
|
||||||
|
u16 direction);
|
||||||
|
|
||||||
|
void drawItem(const ItemStack &item, const core::rect<s32> &rect, bool selected);
|
||||||
|
|
||||||
|
float m_hud_scaling; // cached minetest setting
|
||||||
|
v3s16 m_camera_offset;
|
||||||
|
v2u32 m_screensize;
|
||||||
|
v2s32 m_displaycenter;
|
||||||
|
s32 m_hotbar_imagesize; // Takes hud_scaling into account, updated by resizeHotbar()
|
||||||
|
s32 m_padding; // Takes hud_scaling into account, updated by resizeHotbar()
|
||||||
|
video::SColor hbar_colors[4];
|
||||||
|
|
||||||
|
std::vector<aabb3f> m_selection_boxes;
|
||||||
|
std::vector<aabb3f> m_halo_boxes;
|
||||||
|
v3f m_selection_pos;
|
||||||
|
v3f m_selection_pos_with_offset;
|
||||||
|
|
||||||
|
scene::IMesh *m_selection_mesh = nullptr;
|
||||||
|
video::SColor m_selection_mesh_color;
|
||||||
|
v3f m_selected_face_normal;
|
||||||
|
|
||||||
|
video::SMaterial m_selection_material;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
HIGHLIGHT_BOX,
|
||||||
|
HIGHLIGHT_HALO,
|
||||||
|
HIGHLIGHT_NONE
|
||||||
|
} m_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ItemRotationKind
|
||||||
|
{
|
||||||
|
IT_ROT_SELECTED,
|
||||||
|
IT_ROT_HOVERED,
|
||||||
|
IT_ROT_DRAGGED,
|
||||||
|
IT_ROT_NONE, // Must be last, also serves as number
|
||||||
|
};
|
||||||
|
|
||||||
|
void drawItemStack(video::IVideoDriver *driver,
|
||||||
|
gui::IGUIFont *font,
|
||||||
|
const ItemStack &item,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip,
|
||||||
|
Client *client,
|
||||||
|
ItemRotationKind rotation_kind);
|
||||||
|
|
||||||
|
#endif
|
@ -22,6 +22,75 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "inputhandler.h"
|
#include "inputhandler.h"
|
||||||
#include "gui/mainmenumanager.h"
|
#include "gui/mainmenumanager.h"
|
||||||
|
|
||||||
|
void KeyCache::populate_nonchanging()
|
||||||
|
{
|
||||||
|
key[KeyType::ESC] = EscapeKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyCache::populate()
|
||||||
|
{
|
||||||
|
key[KeyType::FORWARD] = getKeySetting("keymap_forward");
|
||||||
|
key[KeyType::BACKWARD] = getKeySetting("keymap_backward");
|
||||||
|
key[KeyType::LEFT] = getKeySetting("keymap_left");
|
||||||
|
key[KeyType::RIGHT] = getKeySetting("keymap_right");
|
||||||
|
key[KeyType::JUMP] = getKeySetting("keymap_jump");
|
||||||
|
key[KeyType::SPECIAL1] = getKeySetting("keymap_special1");
|
||||||
|
key[KeyType::SNEAK] = getKeySetting("keymap_sneak");
|
||||||
|
|
||||||
|
key[KeyType::AUTOFORWARD] = getKeySetting("keymap_autoforward");
|
||||||
|
|
||||||
|
key[KeyType::DROP] = getKeySetting("keymap_drop");
|
||||||
|
key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
|
||||||
|
key[KeyType::CHAT] = getKeySetting("keymap_chat");
|
||||||
|
key[KeyType::CMD] = getKeySetting("keymap_cmd");
|
||||||
|
key[KeyType::CMD_LOCAL] = getKeySetting("keymap_cmd_local");
|
||||||
|
key[KeyType::CONSOLE] = getKeySetting("keymap_console");
|
||||||
|
key[KeyType::MINIMAP] = getKeySetting("keymap_minimap");
|
||||||
|
key[KeyType::FREEMOVE] = getKeySetting("keymap_freemove");
|
||||||
|
key[KeyType::FASTMOVE] = getKeySetting("keymap_fastmove");
|
||||||
|
key[KeyType::NOCLIP] = getKeySetting("keymap_noclip");
|
||||||
|
key[KeyType::HOTBAR_PREV] = getKeySetting("keymap_hotbar_previous");
|
||||||
|
key[KeyType::HOTBAR_NEXT] = getKeySetting("keymap_hotbar_next");
|
||||||
|
key[KeyType::MUTE] = getKeySetting("keymap_mute");
|
||||||
|
key[KeyType::INC_VOLUME] = getKeySetting("keymap_increase_volume");
|
||||||
|
key[KeyType::DEC_VOLUME] = getKeySetting("keymap_decrease_volume");
|
||||||
|
key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic");
|
||||||
|
key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot");
|
||||||
|
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
|
||||||
|
key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
|
||||||
|
key[KeyType::TOGGLE_FORCE_FOG_OFF] = getKeySetting("keymap_toggle_force_fog_off");
|
||||||
|
key[KeyType::TOGGLE_UPDATE_CAMERA] = getKeySetting("keymap_toggle_update_camera");
|
||||||
|
key[KeyType::TOGGLE_DEBUG] = getKeySetting("keymap_toggle_debug");
|
||||||
|
key[KeyType::TOGGLE_PROFILER] = getKeySetting("keymap_toggle_profiler");
|
||||||
|
key[KeyType::CAMERA_MODE] = getKeySetting("keymap_camera_mode");
|
||||||
|
key[KeyType::INCREASE_VIEWING_RANGE] =
|
||||||
|
getKeySetting("keymap_increase_viewing_range_min");
|
||||||
|
key[KeyType::DECREASE_VIEWING_RANGE] =
|
||||||
|
getKeySetting("keymap_decrease_viewing_range_min");
|
||||||
|
key[KeyType::RANGESELECT] = getKeySetting("keymap_rangeselect");
|
||||||
|
key[KeyType::ZOOM] = getKeySetting("keymap_zoom");
|
||||||
|
|
||||||
|
key[KeyType::QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
|
||||||
|
key[KeyType::QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
|
||||||
|
key[KeyType::QUICKTUNE_INC] = getKeySetting("keymap_quicktune_inc");
|
||||||
|
key[KeyType::QUICKTUNE_DEC] = getKeySetting("keymap_quicktune_dec");
|
||||||
|
|
||||||
|
for (int i = 0; i < 23; i++) {
|
||||||
|
std::string slot_key_name = "keymap_slot" + std::to_string(i + 1);
|
||||||
|
key[KeyType::SLOT_1 + i] = getKeySetting(slot_key_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handler) {
|
||||||
|
// First clear all keys, then re-add the ones we listen for
|
||||||
|
handler->dontListenForKeys();
|
||||||
|
for (const KeyPress &k : key) {
|
||||||
|
handler->listenForKey(k);
|
||||||
|
}
|
||||||
|
handler->listenForKey(EscapeKey);
|
||||||
|
handler->listenForKey(CancelKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MyEventReceiver::OnEvent(const SEvent &event)
|
bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -116,3 +185,72 @@ s32 RandomInputHandler::Rand(s32 min, s32 max)
|
|||||||
{
|
{
|
||||||
return (myrand() % (max - min + 1)) + min;
|
return (myrand() % (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RandomInputHandler::step(float dtime)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
static float counter1 = 0;
|
||||||
|
counter1 -= dtime;
|
||||||
|
if (counter1 < 0.0) {
|
||||||
|
counter1 = 0.1 * Rand(1, 40);
|
||||||
|
keydown.toggle(getKeySetting("keymap_jump"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static float counter1 = 0;
|
||||||
|
counter1 -= dtime;
|
||||||
|
if (counter1 < 0.0) {
|
||||||
|
counter1 = 0.1 * Rand(1, 40);
|
||||||
|
keydown.toggle(getKeySetting("keymap_special1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static float counter1 = 0;
|
||||||
|
counter1 -= dtime;
|
||||||
|
if (counter1 < 0.0) {
|
||||||
|
counter1 = 0.1 * Rand(1, 40);
|
||||||
|
keydown.toggle(getKeySetting("keymap_forward"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static float counter1 = 0;
|
||||||
|
counter1 -= dtime;
|
||||||
|
if (counter1 < 0.0) {
|
||||||
|
counter1 = 0.1 * Rand(1, 40);
|
||||||
|
keydown.toggle(getKeySetting("keymap_left"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static float counter1 = 0;
|
||||||
|
counter1 -= dtime;
|
||||||
|
if (counter1 < 0.0) {
|
||||||
|
counter1 = 0.1 * Rand(1, 20);
|
||||||
|
mousespeed = v2s32(Rand(-20, 20), Rand(-15, 20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static float counter1 = 0;
|
||||||
|
counter1 -= dtime;
|
||||||
|
if (counter1 < 0.0) {
|
||||||
|
counter1 = 0.1 * Rand(1, 30);
|
||||||
|
leftdown = !leftdown;
|
||||||
|
if (leftdown)
|
||||||
|
leftclicked = true;
|
||||||
|
if (!leftdown)
|
||||||
|
leftreleased = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
static float counter1 = 0;
|
||||||
|
counter1 -= dtime;
|
||||||
|
if (counter1 < 0.0) {
|
||||||
|
counter1 = 0.1 * Rand(1, 15);
|
||||||
|
rightdown = !rightdown;
|
||||||
|
if (rightdown)
|
||||||
|
rightclicked = true;
|
||||||
|
if (!rightdown)
|
||||||
|
rightreleased = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mousepos += mousespeed;
|
||||||
|
}
|
||||||
|
@ -29,6 +29,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "gui/touchscreengui.h"
|
#include "gui/touchscreengui.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class InputHandler;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Fast key cache for main game loop
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This is faster than using getKeySetting with the tradeoff that functions
|
||||||
|
* using it must make sure that it's initialised before using it and there is
|
||||||
|
* no error handling (for example bounds checking). This is really intended for
|
||||||
|
* use only in the main running loop of the client (the_game()) where the faster
|
||||||
|
* (up to 10x faster) key lookup is an asset. Other parts of the codebase
|
||||||
|
* (e.g. formspecs) should continue using getKeySetting().
|
||||||
|
*/
|
||||||
|
struct KeyCache
|
||||||
|
{
|
||||||
|
|
||||||
|
KeyCache()
|
||||||
|
{
|
||||||
|
handler = NULL;
|
||||||
|
populate();
|
||||||
|
populate_nonchanging();
|
||||||
|
}
|
||||||
|
|
||||||
|
void populate();
|
||||||
|
|
||||||
|
// Keys that are not settings dependent
|
||||||
|
void populate_nonchanging();
|
||||||
|
|
||||||
|
KeyPress key[KeyType::INTERNAL_ENUM_COUNT];
|
||||||
|
InputHandler *handler;
|
||||||
|
};
|
||||||
|
|
||||||
class KeyList : private std::list<KeyPress>
|
class KeyList : private std::list<KeyPress>
|
||||||
{
|
{
|
||||||
typedef std::list<KeyPress> super;
|
typedef std::list<KeyPress> super;
|
||||||
@ -179,12 +211,17 @@ private:
|
|||||||
class InputHandler
|
class InputHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InputHandler() = default;
|
InputHandler()
|
||||||
|
{
|
||||||
|
keycache.handler = this;
|
||||||
|
keycache.populate();
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~InputHandler() = default;
|
virtual ~InputHandler() = default;
|
||||||
|
|
||||||
virtual bool isKeyDown(const KeyPress &keyCode) = 0;
|
virtual bool isKeyDown(GameKeyType k) = 0;
|
||||||
virtual bool wasKeyDown(const KeyPress &keyCode) = 0;
|
virtual bool wasKeyDown(GameKeyType k) = 0;
|
||||||
|
virtual bool cancelPressed() = 0;
|
||||||
|
|
||||||
virtual void listenForKey(const KeyPress &keyCode) {}
|
virtual void listenForKey(const KeyPress &keyCode) {}
|
||||||
virtual void dontListenForKeys() {}
|
virtual void dontListenForKeys() {}
|
||||||
@ -212,6 +249,7 @@ public:
|
|||||||
virtual void clear() {}
|
virtual void clear() {}
|
||||||
|
|
||||||
JoystickController joystick;
|
JoystickController joystick;
|
||||||
|
KeyCache keycache;
|
||||||
};
|
};
|
||||||
/*
|
/*
|
||||||
Separated input handler
|
Separated input handler
|
||||||
@ -224,13 +262,17 @@ public:
|
|||||||
{
|
{
|
||||||
m_receiver->joystick = &joystick;
|
m_receiver->joystick = &joystick;
|
||||||
}
|
}
|
||||||
virtual bool isKeyDown(const KeyPress &keyCode)
|
virtual bool isKeyDown(GameKeyType k)
|
||||||
{
|
{
|
||||||
return m_receiver->IsKeyDown(keyCode);
|
return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k);
|
||||||
}
|
}
|
||||||
virtual bool wasKeyDown(const KeyPress &keyCode)
|
virtual bool wasKeyDown(GameKeyType k)
|
||||||
{
|
{
|
||||||
return m_receiver->WasKeyDown(keyCode);
|
return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
|
||||||
|
}
|
||||||
|
virtual bool cancelPressed()
|
||||||
|
{
|
||||||
|
return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey);
|
||||||
}
|
}
|
||||||
virtual void listenForKey(const KeyPress &keyCode)
|
virtual void listenForKey(const KeyPress &keyCode)
|
||||||
{
|
{
|
||||||
@ -259,18 +301,58 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool getLeftState() { return m_receiver->left_active; }
|
virtual bool getLeftState()
|
||||||
virtual bool getRightState() { return m_receiver->right_active; }
|
{
|
||||||
|
return m_receiver->left_active || joystick.isKeyDown(KeyType::MOUSE_L);
|
||||||
|
}
|
||||||
|
virtual bool getRightState()
|
||||||
|
{
|
||||||
|
return m_receiver->right_active || joystick.isKeyDown(KeyType::MOUSE_R);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool getLeftClicked() { return m_receiver->leftclicked; }
|
virtual bool getLeftClicked()
|
||||||
virtual bool getRightClicked() { return m_receiver->rightclicked; }
|
{
|
||||||
virtual void resetLeftClicked() { m_receiver->leftclicked = false; }
|
return m_receiver->leftclicked ||
|
||||||
virtual void resetRightClicked() { m_receiver->rightclicked = false; }
|
joystick.getWasKeyDown(KeyType::MOUSE_L);
|
||||||
|
}
|
||||||
|
virtual bool getRightClicked()
|
||||||
|
{
|
||||||
|
return m_receiver->rightclicked ||
|
||||||
|
joystick.getWasKeyDown(KeyType::MOUSE_R);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool getLeftReleased() { return m_receiver->leftreleased; }
|
virtual void resetLeftClicked()
|
||||||
virtual bool getRightReleased() { return m_receiver->rightreleased; }
|
{
|
||||||
virtual void resetLeftReleased() { m_receiver->leftreleased = false; }
|
m_receiver->leftclicked = false;
|
||||||
virtual void resetRightReleased() { m_receiver->rightreleased = false; }
|
joystick.clearWasKeyDown(KeyType::MOUSE_L);
|
||||||
|
}
|
||||||
|
virtual void resetRightClicked()
|
||||||
|
{
|
||||||
|
m_receiver->rightclicked = false;
|
||||||
|
joystick.clearWasKeyDown(KeyType::MOUSE_R);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool getLeftReleased()
|
||||||
|
{
|
||||||
|
return m_receiver->leftreleased ||
|
||||||
|
joystick.wasKeyReleased(KeyType::MOUSE_L);
|
||||||
|
}
|
||||||
|
virtual bool getRightReleased()
|
||||||
|
{
|
||||||
|
return m_receiver->rightreleased ||
|
||||||
|
joystick.wasKeyReleased(KeyType::MOUSE_R);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void resetLeftReleased()
|
||||||
|
{
|
||||||
|
m_receiver->leftreleased = false;
|
||||||
|
joystick.clearWasKeyReleased(KeyType::MOUSE_L);
|
||||||
|
}
|
||||||
|
virtual void resetRightReleased()
|
||||||
|
{
|
||||||
|
m_receiver->rightreleased = false;
|
||||||
|
joystick.clearWasKeyReleased(KeyType::MOUSE_R);
|
||||||
|
}
|
||||||
|
|
||||||
virtual s32 getMouseWheel() { return m_receiver->getMouseWheel(); }
|
virtual s32 getMouseWheel() { return m_receiver->getMouseWheel(); }
|
||||||
|
|
||||||
@ -290,8 +372,9 @@ class RandomInputHandler : public InputHandler
|
|||||||
public:
|
public:
|
||||||
RandomInputHandler() = default;
|
RandomInputHandler() = default;
|
||||||
|
|
||||||
virtual bool isKeyDown(const KeyPress &keyCode) { return keydown[keyCode]; }
|
virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
|
||||||
virtual bool wasKeyDown(const KeyPress &keyCode) { return false; }
|
virtual bool wasKeyDown(GameKeyType k) { return false; }
|
||||||
|
virtual bool cancelPressed() { return false; }
|
||||||
virtual v2s32 getMousePos() { return mousepos; }
|
virtual v2s32 getMousePos() { return mousepos; }
|
||||||
virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
|
virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
|
||||||
|
|
||||||
@ -310,74 +393,7 @@ public:
|
|||||||
|
|
||||||
virtual s32 getMouseWheel() { return 0; }
|
virtual s32 getMouseWheel() { return 0; }
|
||||||
|
|
||||||
virtual void step(float dtime)
|
virtual void step(float dtime);
|
||||||
{
|
|
||||||
{
|
|
||||||
static float counter1 = 0;
|
|
||||||
counter1 -= dtime;
|
|
||||||
if (counter1 < 0.0) {
|
|
||||||
counter1 = 0.1 * Rand(1, 40);
|
|
||||||
keydown.toggle(getKeySetting("keymap_jump"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
static float counter1 = 0;
|
|
||||||
counter1 -= dtime;
|
|
||||||
if (counter1 < 0.0) {
|
|
||||||
counter1 = 0.1 * Rand(1, 40);
|
|
||||||
keydown.toggle(getKeySetting("keymap_special1"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
static float counter1 = 0;
|
|
||||||
counter1 -= dtime;
|
|
||||||
if (counter1 < 0.0) {
|
|
||||||
counter1 = 0.1 * Rand(1, 40);
|
|
||||||
keydown.toggle(getKeySetting("keymap_forward"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
static float counter1 = 0;
|
|
||||||
counter1 -= dtime;
|
|
||||||
if (counter1 < 0.0) {
|
|
||||||
counter1 = 0.1 * Rand(1, 40);
|
|
||||||
keydown.toggle(getKeySetting("keymap_left"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
static float counter1 = 0;
|
|
||||||
counter1 -= dtime;
|
|
||||||
if (counter1 < 0.0) {
|
|
||||||
counter1 = 0.1 * Rand(1, 20);
|
|
||||||
mousespeed = v2s32(Rand(-20, 20), Rand(-15, 20));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
static float counter1 = 0;
|
|
||||||
counter1 -= dtime;
|
|
||||||
if (counter1 < 0.0) {
|
|
||||||
counter1 = 0.1 * Rand(1, 30);
|
|
||||||
leftdown = !leftdown;
|
|
||||||
if (leftdown)
|
|
||||||
leftclicked = true;
|
|
||||||
if (!leftdown)
|
|
||||||
leftreleased = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
static float counter1 = 0;
|
|
||||||
counter1 -= dtime;
|
|
||||||
if (counter1 < 0.0) {
|
|
||||||
counter1 = 0.1 * Rand(1, 15);
|
|
||||||
rightdown = !rightdown;
|
|
||||||
if (rightdown)
|
|
||||||
rightclicked = true;
|
|
||||||
if (!rightdown)
|
|
||||||
rightreleased = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mousepos += mousespeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 Rand(s32 min, s32 max);
|
s32 Rand(s32 min, s32 max);
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "sidebyside.h"
|
#include "sidebyside.h"
|
||||||
#include <ICameraSceneNode.h>
|
#include <ICameraSceneNode.h>
|
||||||
#include "hud.h"
|
#include "client/hud.h"
|
||||||
|
|
||||||
RenderingCoreSideBySide::RenderingCoreSideBySide(
|
RenderingCoreSideBySide::RenderingCoreSideBySide(
|
||||||
IrrlichtDevice *_device, Client *_client, Hud *_hud, bool _horizontal)
|
IrrlichtDevice *_device, Client *_client, Hud *_hud, bool _horizontal)
|
||||||
|
@ -25,8 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "clouds.h"
|
#include "clouds.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "guiscalingfilter.h"
|
#include "guiscalingfilter.h"
|
||||||
#include "hud.h"
|
|
||||||
#include "localplayer.h"
|
#include "localplayer.h"
|
||||||
|
#include "client/hud.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
#include "clientmap.h"
|
#include "clientmap.h"
|
||||||
@ -410,6 +410,26 @@ void RenderingEngine::_draw_load_screen(const std::wstring &text,
|
|||||||
guitext->remove();
|
guitext->remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Draws the menu scene including (optional) cloud background.
|
||||||
|
*/
|
||||||
|
void RenderingEngine::_draw_menu_scene(gui::IGUIEnvironment *guienv,
|
||||||
|
float dtime, bool clouds)
|
||||||
|
{
|
||||||
|
bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
|
||||||
|
if (cloud_menu_background) {
|
||||||
|
g_menuclouds->step(dtime * 3);
|
||||||
|
g_menuclouds->render();
|
||||||
|
get_video_driver()->beginScene(
|
||||||
|
true, true, video::SColor(255, 140, 186, 250));
|
||||||
|
g_menucloudsmgr->drawAll();
|
||||||
|
} else
|
||||||
|
get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0));
|
||||||
|
|
||||||
|
guienv->drawAll();
|
||||||
|
get_video_driver()->endScene();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<core::vector3d<u32>> RenderingEngine::getSupportedVideoModes()
|
std::vector<core::vector3d<u32>> RenderingEngine::getSupportedVideoModes()
|
||||||
{
|
{
|
||||||
IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL);
|
IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL);
|
||||||
|
@ -110,6 +110,12 @@ public:
|
|||||||
text, guienv, tsrc, dtime, percent, clouds);
|
text, guienv, tsrc, dtime, percent, clouds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static void draw_menu_scene(
|
||||||
|
gui::IGUIEnvironment *guienv, float dtime, bool clouds)
|
||||||
|
{
|
||||||
|
s_singleton->_draw_menu_scene(guienv, dtime, clouds);
|
||||||
|
}
|
||||||
|
|
||||||
inline static void draw_scene(video::SColor skycolor, bool show_hud,
|
inline static void draw_scene(video::SColor skycolor, bool show_hud,
|
||||||
bool show_minimap, bool draw_wield_tool, bool draw_crosshair)
|
bool show_minimap, bool draw_wield_tool, bool draw_crosshair)
|
||||||
{
|
{
|
||||||
@ -138,6 +144,9 @@ private:
|
|||||||
ITextureSource *tsrc, float dtime = 0, int percent = 0,
|
ITextureSource *tsrc, float dtime = 0, int percent = 0,
|
||||||
bool clouds = true);
|
bool clouds = true);
|
||||||
|
|
||||||
|
void _draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime = 0,
|
||||||
|
bool clouds = true);
|
||||||
|
|
||||||
void _draw_scene(video::SColor skycolor, bool show_hud, bool show_minimap,
|
void _draw_scene(video::SColor skycolor, bool show_hud, bool show_minimap,
|
||||||
bool draw_wield_tool, bool draw_crosshair);
|
bool draw_wield_tool, bool draw_crosshair);
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "raycast.h"
|
#include "raycast.h"
|
||||||
#include "voxelalgorithms.h"
|
#include "voxelalgorithms.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "content_cao.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
|
|
||||||
@ -207,6 +208,8 @@ void ClientEnvironment::step(float dtime)
|
|||||||
|
|
||||||
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
|
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
|
||||||
|
|
||||||
|
bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal();
|
||||||
|
|
||||||
for (const CollisionInfo &info : player_collisions) {
|
for (const CollisionInfo &info : player_collisions) {
|
||||||
v3f speed_diff = info.new_speed - info.old_speed;;
|
v3f speed_diff = info.new_speed - info.old_speed;;
|
||||||
// Handle only fall damage
|
// Handle only fall damage
|
||||||
@ -227,7 +230,7 @@ void ClientEnvironment::step(float dtime)
|
|||||||
pre_factor = 1.0 + (float)addp/100.0;
|
pre_factor = 1.0 + (float)addp/100.0;
|
||||||
}
|
}
|
||||||
float speed = pre_factor * speed_diff.getLength();
|
float speed = pre_factor * speed_diff.getLength();
|
||||||
if (speed > tolerance) {
|
if (speed > tolerance && !player_immortal) {
|
||||||
f32 damage_f = (speed - tolerance) / BS * post_factor;
|
f32 damage_f = (speed - tolerance) / BS * post_factor;
|
||||||
u8 damage = (u8)MYMIN(damage_f + 0.5, 255);
|
u8 damage = (u8)MYMIN(damage_f + 0.5, 255);
|
||||||
if (damage != 0) {
|
if (damage != 0) {
|
||||||
|
@ -199,7 +199,7 @@ void RemoteClient::GetNextBlocks (
|
|||||||
const s16 full_d_max = std::min(adjustDist(m_max_send_distance, camera_fov), wanted_range);
|
const s16 full_d_max = std::min(adjustDist(m_max_send_distance, camera_fov), wanted_range);
|
||||||
const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, camera_fov), wanted_range);
|
const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, camera_fov), wanted_range);
|
||||||
const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
|
const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
|
||||||
infostream << "Fov from client " << camera_fov << " full_d_max " << full_d_max << std::endl;
|
//infostream << "Fov from client " << camera_fov << " full_d_max " << full_d_max << std::endl;
|
||||||
|
|
||||||
s16 d_max = full_d_max;
|
s16 d_max = full_d_max;
|
||||||
s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, camera_fov), wanted_range);
|
s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, camera_fov), wanted_range);
|
||||||
|
@ -360,6 +360,11 @@ v3f GenericCAO::getPosition()
|
|||||||
return pos_translator.vect_show;
|
return pos_translator.vect_show;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool GenericCAO::isImmortal()
|
||||||
|
{
|
||||||
|
return itemgroup_get(getGroups(), "immortal");
|
||||||
|
}
|
||||||
|
|
||||||
scene::ISceneNode* GenericCAO::getSceneNode()
|
scene::ISceneNode* GenericCAO::getSceneNode()
|
||||||
{
|
{
|
||||||
if (m_meshnode) {
|
if (m_meshnode) {
|
||||||
@ -563,7 +568,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
|
|||||||
}
|
}
|
||||||
else if(m_prop.visual == "mesh") {
|
else if(m_prop.visual == "mesh") {
|
||||||
infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
|
infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
|
||||||
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh);
|
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
|
||||||
if(mesh)
|
if(mesh)
|
||||||
{
|
{
|
||||||
m_animated_meshnode = RenderingEngine::get_scene_manager()->
|
m_animated_meshnode = RenderingEngine::get_scene_manager()->
|
||||||
@ -575,13 +580,17 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
|
|||||||
m_prop.visual_size.Y,
|
m_prop.visual_size.Y,
|
||||||
m_prop.visual_size.X));
|
m_prop.visual_size.X));
|
||||||
u8 li = m_last_light;
|
u8 li = m_last_light;
|
||||||
|
|
||||||
|
// set vertex colors to ensure alpha is set
|
||||||
setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
|
setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
|
||||||
|
|
||||||
|
setAnimatedMeshColor(m_animated_meshnode, video::SColor(255,li,li,li));
|
||||||
|
|
||||||
bool backface_culling = m_prop.backface_culling;
|
bool backface_culling = m_prop.backface_culling;
|
||||||
if (m_is_player)
|
if (m_is_player)
|
||||||
backface_culling = false;
|
backface_culling = false;
|
||||||
|
|
||||||
m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
|
m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
|
||||||
m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
|
m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
|
||||||
m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
|
m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
|
||||||
m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
|
m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
|
||||||
@ -669,7 +678,7 @@ void GenericCAO::updateLightNoCheck(u8 light_at_pos)
|
|||||||
if (m_meshnode) {
|
if (m_meshnode) {
|
||||||
setMeshColor(m_meshnode->getMesh(), color);
|
setMeshColor(m_meshnode->getMesh(), color);
|
||||||
} else if (m_animated_meshnode) {
|
} else if (m_animated_meshnode) {
|
||||||
setMeshColor(m_animated_meshnode->getMesh(), color);
|
setAnimatedMeshColor(m_animated_meshnode, color);
|
||||||
} else if (m_wield_meshnode) {
|
} else if (m_wield_meshnode) {
|
||||||
m_wield_meshnode->setColor(color);
|
m_wield_meshnode->setColor(color);
|
||||||
} else if (m_spritenode) {
|
} else if (m_spritenode) {
|
||||||
@ -904,19 +913,19 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!getParent() && m_prop.automatic_face_movement_dir &&
|
if (!getParent() && m_prop.automatic_face_movement_dir &&
|
||||||
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001))
|
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) {
|
||||||
{
|
|
||||||
float optimal_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI
|
float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI
|
||||||
+ m_prop.automatic_face_movement_dir_offset;
|
+ m_prop.automatic_face_movement_dir_offset;
|
||||||
float max_rotation_delta =
|
float max_rotation_delta =
|
||||||
dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
|
dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
|
||||||
|
float delta = wrapDegrees_0_360(target_yaw - m_yaw);
|
||||||
|
|
||||||
if ((m_prop.automatic_face_movement_max_rotation_per_sec > 0) &&
|
if (delta > max_rotation_delta && 360 - delta > max_rotation_delta) {
|
||||||
(fabs(m_yaw - optimal_yaw) > max_rotation_delta)) {
|
m_yaw += (delta < 180) ? max_rotation_delta : -max_rotation_delta;
|
||||||
|
m_yaw = wrapDegrees_0_360(m_yaw);
|
||||||
m_yaw = optimal_yaw < m_yaw ? m_yaw - max_rotation_delta : m_yaw + max_rotation_delta;
|
|
||||||
} else {
|
} else {
|
||||||
m_yaw = optimal_yaw;
|
m_yaw = target_yaw;
|
||||||
}
|
}
|
||||||
updateNodePos();
|
updateNodePos();
|
||||||
}
|
}
|
||||||
@ -1025,7 +1034,7 @@ void GenericCAO::updateTextures(std::string mod)
|
|||||||
// Set material flags and texture
|
// Set material flags and texture
|
||||||
video::SMaterial& material = m_animated_meshnode->getMaterial(i);
|
video::SMaterial& material = m_animated_meshnode->getMaterial(i);
|
||||||
material.TextureLayer[0].Texture = texture;
|
material.TextureLayer[0].Texture = texture;
|
||||||
material.setFlag(video::EMF_LIGHTING, false);
|
material.setFlag(video::EMF_LIGHTING, true);
|
||||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||||
|
|
||||||
// don't filter low-res textures, makes them look blurry
|
// don't filter low-res textures, makes them look blurry
|
||||||
@ -1130,10 +1139,12 @@ void GenericCAO::updateTextures(std::string mod)
|
|||||||
buf->getMaterial().AmbientColor = m_prop.colors[1];
|
buf->getMaterial().AmbientColor = m_prop.colors[1];
|
||||||
buf->getMaterial().DiffuseColor = m_prop.colors[1];
|
buf->getMaterial().DiffuseColor = m_prop.colors[1];
|
||||||
buf->getMaterial().SpecularColor = m_prop.colors[1];
|
buf->getMaterial().SpecularColor = m_prop.colors[1];
|
||||||
|
setMeshColor(mesh, m_prop.colors[1]);
|
||||||
} else if (!m_prop.colors.empty()) {
|
} else if (!m_prop.colors.empty()) {
|
||||||
buf->getMaterial().AmbientColor = m_prop.colors[0];
|
buf->getMaterial().AmbientColor = m_prop.colors[0];
|
||||||
buf->getMaterial().DiffuseColor = m_prop.colors[0];
|
buf->getMaterial().DiffuseColor = m_prop.colors[0];
|
||||||
buf->getMaterial().SpecularColor = m_prop.colors[0];
|
buf->getMaterial().SpecularColor = m_prop.colors[0];
|
||||||
|
setMeshColor(mesh, m_prop.colors[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
|
||||||
@ -1259,8 +1270,8 @@ void GenericCAO::processMessage(const std::string &data)
|
|||||||
collision_box.MinEdge *= BS;
|
collision_box.MinEdge *= BS;
|
||||||
collision_box.MaxEdge *= BS;
|
collision_box.MaxEdge *= BS;
|
||||||
player->setCollisionbox(collision_box);
|
player->setCollisionbox(collision_box);
|
||||||
player->setCanZoom(m_prop.can_zoom);
|
|
||||||
player->setEyeHeight(m_prop.eye_height);
|
player->setEyeHeight(m_prop.eye_height);
|
||||||
|
player->setZoomFOV(m_prop.zoom_fov);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
|
if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
|
||||||
|
@ -124,7 +124,10 @@ public:
|
|||||||
{
|
{
|
||||||
return ACTIVEOBJECT_TYPE_GENERIC;
|
return ACTIVEOBJECT_TYPE_GENERIC;
|
||||||
}
|
}
|
||||||
|
inline const ItemGroupList &getGroups() const
|
||||||
|
{
|
||||||
|
return m_armor_groups;
|
||||||
|
}
|
||||||
void initialize(const std::string &data);
|
void initialize(const std::string &data);
|
||||||
|
|
||||||
void processInitData(const std::string &data);
|
void processInitData(const std::string &data);
|
||||||
@ -143,6 +146,8 @@ public:
|
|||||||
return m_yaw;
|
return m_yaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool isImmortal();
|
||||||
|
|
||||||
scene::ISceneNode *getSceneNode();
|
scene::ISceneNode *getSceneNode();
|
||||||
|
|
||||||
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode();
|
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode();
|
||||||
|
@ -385,9 +385,16 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing()
|
|||||||
getSpecialTile(1, &tile_liquid);
|
getSpecialTile(1, &tile_liquid);
|
||||||
|
|
||||||
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(p.X, p.Y + 1, p.Z));
|
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(p.X, p.Y + 1, p.Z));
|
||||||
|
MapNode nbottom = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(p.X, p.Y - 1, p.Z));
|
||||||
c_flowing = nodedef->getId(f->liquid_alternative_flowing);
|
c_flowing = nodedef->getId(f->liquid_alternative_flowing);
|
||||||
c_source = nodedef->getId(f->liquid_alternative_source);
|
c_source = nodedef->getId(f->liquid_alternative_source);
|
||||||
top_is_same_liquid = (ntop.getContent() == c_flowing) || (ntop.getContent() == c_source);
|
top_is_same_liquid = (ntop.getContent() == c_flowing) || (ntop.getContent() == c_source);
|
||||||
|
draw_liquid_bottom = (nbottom.getContent() != c_flowing) && (nbottom.getContent() != c_source);
|
||||||
|
if (draw_liquid_bottom) {
|
||||||
|
const ContentFeatures &f2 = nodedef->get(nbottom.getContent());
|
||||||
|
if (f2.solidness > 1)
|
||||||
|
draw_liquid_bottom = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (data->m_smooth_lighting)
|
if (data->m_smooth_lighting)
|
||||||
return; // don't need to pre-compute anything in this case
|
return; // don't need to pre-compute anything in this case
|
||||||
@ -595,6 +602,24 @@ void MapblockMeshGenerator::drawLiquidTop()
|
|||||||
collector->append(tile_liquid_top, vertices, 4, quad_indices, 6);
|
collector->append(tile_liquid_top, vertices, 4, quad_indices, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapblockMeshGenerator::drawLiquidBottom()
|
||||||
|
{
|
||||||
|
video::S3DVertex vertices[4] = {
|
||||||
|
video::S3DVertex(-BS / 2, -BS / 2, -BS / 2, 0, 0, 0, color_liquid_top, 0, 0),
|
||||||
|
video::S3DVertex( BS / 2, -BS / 2, -BS / 2, 0, 0, 0, color_liquid_top, 1, 0),
|
||||||
|
video::S3DVertex( BS / 2, -BS / 2, BS / 2, 0, 0, 0, color_liquid_top, 1, 1),
|
||||||
|
video::S3DVertex(-BS / 2, -BS / 2, BS / 2, 0, 0, 0, color_liquid_top, 0, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (data->m_smooth_lighting)
|
||||||
|
vertices[i].Color = blendLightColor(vertices[i].Pos);
|
||||||
|
vertices[i].Pos += origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
collector->append(tile_liquid_top, vertices, 4, quad_indices, 6);
|
||||||
|
}
|
||||||
|
|
||||||
void MapblockMeshGenerator::drawLiquidNode()
|
void MapblockMeshGenerator::drawLiquidNode()
|
||||||
{
|
{
|
||||||
prepareLiquidNodeDrawing();
|
prepareLiquidNodeDrawing();
|
||||||
@ -603,6 +628,8 @@ void MapblockMeshGenerator::drawLiquidNode()
|
|||||||
drawLiquidSides();
|
drawLiquidSides();
|
||||||
if (!top_is_same_liquid)
|
if (!top_is_same_liquid)
|
||||||
drawLiquidTop();
|
drawLiquidTop();
|
||||||
|
if (draw_liquid_bottom)
|
||||||
|
drawLiquidBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapblockMeshGenerator::drawGlasslikeNode()
|
void MapblockMeshGenerator::drawGlasslikeNode()
|
||||||
|
@ -92,6 +92,7 @@ public:
|
|||||||
|
|
||||||
// liquid-specific
|
// liquid-specific
|
||||||
bool top_is_same_liquid;
|
bool top_is_same_liquid;
|
||||||
|
bool draw_liquid_bottom;
|
||||||
TileSpec tile_liquid;
|
TileSpec tile_liquid;
|
||||||
TileSpec tile_liquid_top;
|
TileSpec tile_liquid_top;
|
||||||
content_t c_flowing;
|
content_t c_flowing;
|
||||||
@ -112,6 +113,7 @@ public:
|
|||||||
f32 getCornerLevel(int i, int k);
|
f32 getCornerLevel(int i, int k);
|
||||||
void drawLiquidSides();
|
void drawLiquidSides();
|
||||||
void drawLiquidTop();
|
void drawLiquidTop();
|
||||||
|
void drawLiquidBottom();
|
||||||
|
|
||||||
// raillike-specific
|
// raillike-specific
|
||||||
// name of the group that enables connecting to raillike nodes of different kind
|
// name of the group that enables connecting to raillike nodes of different kind
|
||||||
|
@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "scripting_server.h"
|
#include "scripting_server.h"
|
||||||
#include "genericobject.h"
|
#include "genericobject.h"
|
||||||
|
#include "settings.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
std::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
|
std::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
|
||||||
@ -372,20 +373,20 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
|
|||||||
m_velocity += dtime * m_acceleration;
|
m_velocity += dtime * m_acceleration;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((m_prop.automatic_face_movement_dir) &&
|
if (m_prop.automatic_face_movement_dir &&
|
||||||
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001))
|
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) {
|
||||||
{
|
|
||||||
float optimal_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI
|
float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI
|
||||||
+ m_prop.automatic_face_movement_dir_offset;
|
+ m_prop.automatic_face_movement_dir_offset;
|
||||||
float max_rotation_delta =
|
float max_rotation_delta =
|
||||||
dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
|
dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
|
||||||
|
float delta = wrapDegrees_0_360(target_yaw - m_yaw);
|
||||||
|
|
||||||
if ((m_prop.automatic_face_movement_max_rotation_per_sec > 0) &&
|
if (delta > max_rotation_delta && 360 - delta > max_rotation_delta) {
|
||||||
(fabs(m_yaw - optimal_yaw) > max_rotation_delta)) {
|
m_yaw += (delta < 180) ? max_rotation_delta : -max_rotation_delta;
|
||||||
|
m_yaw = wrapDegrees_0_360(m_yaw);
|
||||||
m_yaw = optimal_yaw < m_yaw ? m_yaw - max_rotation_delta : m_yaw + max_rotation_delta;
|
|
||||||
} else {
|
} else {
|
||||||
m_yaw = optimal_yaw;
|
m_yaw = target_yaw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -801,7 +802,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t p
|
|||||||
m_prop.collisionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f);
|
m_prop.collisionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f);
|
||||||
m_prop.selectionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f);
|
m_prop.selectionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f);
|
||||||
m_prop.pointable = true;
|
m_prop.pointable = true;
|
||||||
// start of default appearance, this should be overwritten by LUA
|
// Start of default appearance, this should be overwritten by Lua
|
||||||
m_prop.visual = "upright_sprite";
|
m_prop.visual = "upright_sprite";
|
||||||
m_prop.visual_size = v2f(1, 2);
|
m_prop.visual_size = v2f(1, 2);
|
||||||
m_prop.textures.clear();
|
m_prop.textures.clear();
|
||||||
@ -811,13 +812,14 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t p
|
|||||||
m_prop.colors.emplace_back(255, 255, 255, 255);
|
m_prop.colors.emplace_back(255, 255, 255, 255);
|
||||||
m_prop.spritediv = v2s16(1,1);
|
m_prop.spritediv = v2s16(1,1);
|
||||||
m_prop.eye_height = 1.625f;
|
m_prop.eye_height = 1.625f;
|
||||||
// end of default appearance
|
// End of default appearance
|
||||||
m_prop.is_visible = true;
|
m_prop.is_visible = true;
|
||||||
m_prop.makes_footstep_sound = true;
|
m_prop.makes_footstep_sound = true;
|
||||||
m_prop.stepheight = PLAYER_DEFAULT_STEPHEIGHT * BS;
|
m_prop.stepheight = PLAYER_DEFAULT_STEPHEIGHT * BS;
|
||||||
m_prop.can_zoom = true;
|
|
||||||
m_hp = m_prop.hp_max;
|
m_hp = m_prop.hp_max;
|
||||||
m_breath = m_prop.breath_max;
|
m_breath = m_prop.breath_max;
|
||||||
|
// Disable zoom in survival mode using a value of 0
|
||||||
|
m_prop.zoom_fov = g_settings->getBool("creative_mode") ? 15.0f : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerSAO::~PlayerSAO()
|
PlayerSAO::~PlayerSAO()
|
||||||
@ -1399,26 +1401,38 @@ bool PlayerSAO::checkMovementCheat()
|
|||||||
too, and much more lightweight.
|
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) {
|
if (m_privs.count("fast") != 0)
|
||||||
// Fast speed
|
player_max_walk = m_player->movement_speed_fast; // Fast speed
|
||||||
player_max_speed = m_player->movement_speed_fast * m_physics_override_speed;
|
else
|
||||||
} else {
|
player_max_walk = m_player->movement_speed_walk; // Normal speed
|
||||||
// Normal speed
|
player_max_walk *= m_physics_override_speed;
|
||||||
player_max_speed = m_player->movement_speed_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,
|
||||||
// Tolerance. The lag pool does this a bit.
|
// until this can be verified correctly, tolerate higher jumping speeds
|
||||||
//player_max_speed *= 2.5;
|
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);
|
v3f diff = (m_base_position - m_last_good_position);
|
||||||
float d_vert = diff.Y;
|
float d_vert = diff.Y;
|
||||||
diff.Y = 0;
|
diff.Y = 0;
|
||||||
float d_horiz = diff.getLength();
|
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)
|
// FIXME: Checking downwards movement is not easily possible currently,
|
||||||
required_time = d_vert / player_max_speed; // Moving upwards
|
// 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)) {
|
if (m_move_pool.grab(required_time)) {
|
||||||
m_last_good_position = m_base_position;
|
m_last_good_position = m_base_position;
|
||||||
|
@ -58,6 +58,7 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("enable_remote_media_server", "true");
|
settings->setDefault("enable_remote_media_server", "true");
|
||||||
settings->setDefault("enable_client_modding", "false");
|
settings->setDefault("enable_client_modding", "false");
|
||||||
settings->setDefault("max_out_chat_queue_size", "20");
|
settings->setDefault("max_out_chat_queue_size", "20");
|
||||||
|
settings->setDefault("pause_on_lost_focus", "false");
|
||||||
|
|
||||||
// Keymap
|
// Keymap
|
||||||
settings->setDefault("remote_port", "30000");
|
settings->setDefault("remote_port", "30000");
|
||||||
@ -147,7 +148,6 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("3d_paralax_strength", "0.025");
|
settings->setDefault("3d_paralax_strength", "0.025");
|
||||||
settings->setDefault("tooltip_show_delay", "400");
|
settings->setDefault("tooltip_show_delay", "400");
|
||||||
settings->setDefault("tooltip_append_itemname", "false");
|
settings->setDefault("tooltip_append_itemname", "false");
|
||||||
settings->setDefault("zoom_fov", "15");
|
|
||||||
settings->setDefault("fps_max", "60");
|
settings->setDefault("fps_max", "60");
|
||||||
settings->setDefault("pause_fps_max", "20");
|
settings->setDefault("pause_fps_max", "20");
|
||||||
settings->setDefault("viewing_range", "100");
|
settings->setDefault("viewing_range", "100");
|
||||||
@ -163,8 +163,11 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("connected_glass", "false");
|
settings->setDefault("connected_glass", "false");
|
||||||
settings->setDefault("smooth_lighting", "true");
|
settings->setDefault("smooth_lighting", "true");
|
||||||
settings->setDefault("lighting_alpha", "0.0");
|
settings->setDefault("lighting_alpha", "0.0");
|
||||||
settings->setDefault("lighting_beta", "0.0");
|
settings->setDefault("lighting_beta", "1.5");
|
||||||
settings->setDefault("display_gamma", "1.0");
|
settings->setDefault("display_gamma", "1.0");
|
||||||
|
settings->setDefault("lighting_boost", "0.2");
|
||||||
|
settings->setDefault("lighting_boost_center", "0.5");
|
||||||
|
settings->setDefault("lighting_boost_spread", "0.2");
|
||||||
settings->setDefault("texture_path", "");
|
settings->setDefault("texture_path", "");
|
||||||
settings->setDefault("shader_path", "");
|
settings->setDefault("shader_path", "");
|
||||||
settings->setDefault("video_driver", "opengl");
|
settings->setDefault("video_driver", "opengl");
|
||||||
@ -178,7 +181,7 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("cloud_radius", "12");
|
settings->setDefault("cloud_radius", "12");
|
||||||
settings->setDefault("menu_clouds", "true");
|
settings->setDefault("menu_clouds", "true");
|
||||||
settings->setDefault("opaque_water", "false");
|
settings->setDefault("opaque_water", "false");
|
||||||
settings->setDefault("console_height", "1.0");
|
settings->setDefault("console_height", "0.6");
|
||||||
settings->setDefault("console_color", "(0,0,0)");
|
settings->setDefault("console_color", "(0,0,0)");
|
||||||
settings->setDefault("console_alpha", "200");
|
settings->setDefault("console_alpha", "200");
|
||||||
settings->setDefault("formspec_fullscreen_bg_color", "(0,0,0)");
|
settings->setDefault("formspec_fullscreen_bg_color", "(0,0,0)");
|
||||||
@ -327,7 +330,7 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("max_block_send_distance", "9");
|
settings->setDefault("max_block_send_distance", "9");
|
||||||
settings->setDefault("block_send_optimize_distance", "4");
|
settings->setDefault("block_send_optimize_distance", "4");
|
||||||
settings->setDefault("server_side_occlusion_culling", "true");
|
settings->setDefault("server_side_occlusion_culling", "true");
|
||||||
settings->setDefault("csm_flavour_limits", "3");
|
settings->setDefault("csm_flavour_limits", "18");
|
||||||
settings->setDefault("csm_flavour_noderange_limit", "8");
|
settings->setDefault("csm_flavour_noderange_limit", "8");
|
||||||
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
|
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
|
||||||
settings->setDefault("time_speed", "72");
|
settings->setDefault("time_speed", "72");
|
||||||
@ -347,6 +350,7 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("ignore_world_load_errors", "false");
|
settings->setDefault("ignore_world_load_errors", "false");
|
||||||
settings->setDefault("remote_media", "");
|
settings->setDefault("remote_media", "");
|
||||||
settings->setDefault("debug_log_level", "action");
|
settings->setDefault("debug_log_level", "action");
|
||||||
|
settings->setDefault("log_color", "detect");
|
||||||
settings->setDefault("emergequeue_limit_total", "256");
|
settings->setDefault("emergequeue_limit_total", "256");
|
||||||
settings->setDefault("emergequeue_limit_diskonly", "32");
|
settings->setDefault("emergequeue_limit_diskonly", "32");
|
||||||
settings->setDefault("emergequeue_limit_generate", "32");
|
settings->setDefault("emergequeue_limit_generate", "32");
|
||||||
|
1492
src/game.cpp
1492
src/game.cpp
File diff suppressed because it is too large
Load Diff
23
src/game.h
23
src/game.h
@ -26,16 +26,19 @@ class InputHandler;
|
|||||||
class ChatBackend; /* to avoid having to include chat.h */
|
class ChatBackend; /* to avoid having to include chat.h */
|
||||||
struct SubgameSpec;
|
struct SubgameSpec;
|
||||||
|
|
||||||
// Flags that can, or may, change during main game loop
|
struct Jitter {
|
||||||
struct GameUIFlags
|
f32 max, min, avg, counter, max_sample, min_sample, max_fraction;
|
||||||
{
|
};
|
||||||
bool show_chat;
|
|
||||||
bool show_hud;
|
struct RunStats {
|
||||||
bool show_minimap;
|
u32 drawtime;
|
||||||
bool force_fog_off;
|
|
||||||
bool show_debug;
|
Jitter dtime_jitter, busy_time_jitter;
|
||||||
bool show_profiler_graph;
|
};
|
||||||
bool disable_camera_update;
|
|
||||||
|
struct CameraOrientation {
|
||||||
|
f32 camera_yaw; // "right/left"
|
||||||
|
f32 camera_pitch; // "up/down"
|
||||||
};
|
};
|
||||||
|
|
||||||
void the_game(bool *kill,
|
void the_game(bool *kill,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
set(gui_SRCS
|
set(gui_SRCS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp
|
||||||
@ -9,5 +10,6 @@ set(gui_SRCS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/intlGUIEditBox.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/intlGUIEditBox.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/profilergraph.cpp
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
232
src/gui/guiConfirmRegistration.cpp
Normal file
232
src/gui/guiConfirmRegistration.cpp
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
|
||||||
|
<muhammadrifqipriyosusanto@gmail.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "guiConfirmRegistration.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include <IGUICheckBox.h>
|
||||||
|
#include <IGUIEditBox.h>
|
||||||
|
#include <IGUIButton.h>
|
||||||
|
#include <IGUIStaticText.h>
|
||||||
|
#include <IGUIFont.h>
|
||||||
|
|
||||||
|
#include "gettext.h"
|
||||||
|
|
||||||
|
// Continuing from guiPasswordChange.cpp
|
||||||
|
const int ID_confirmPassword = 262;
|
||||||
|
const int ID_confirm = 263;
|
||||||
|
const int ID_message = 264;
|
||||||
|
const int ID_cancel = 265;
|
||||||
|
|
||||||
|
GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
|
||||||
|
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client,
|
||||||
|
const std::string &playername, const std::string &password,
|
||||||
|
const std::string &address, bool *aborted) :
|
||||||
|
GUIModalMenu(env, parent, id, menumgr),
|
||||||
|
m_client(client), m_playername(playername), m_password(password),
|
||||||
|
m_address(address), m_aborted(aborted)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GUIConfirmRegistration::~GUIConfirmRegistration()
|
||||||
|
{
|
||||||
|
removeChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIConfirmRegistration::removeChildren()
|
||||||
|
{
|
||||||
|
const core::list<gui::IGUIElement *> &children = getChildren();
|
||||||
|
core::list<gui::IGUIElement *> children_copy;
|
||||||
|
for (gui::IGUIElement *i : children)
|
||||||
|
children_copy.push_back(i);
|
||||||
|
for (gui::IGUIElement *i : children_copy)
|
||||||
|
i->remove();
|
||||||
|
}
|
||||||
|
void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
|
||||||
|
{
|
||||||
|
acceptInput();
|
||||||
|
removeChildren();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculate new sizes and positions
|
||||||
|
*/
|
||||||
|
core::rect<s32> rect(screensize.X / 2 - 600 / 2, screensize.Y / 2 - 300 / 2,
|
||||||
|
screensize.X / 2 + 600 / 2, screensize.Y / 2 + 300 / 2);
|
||||||
|
|
||||||
|
DesiredRect = rect;
|
||||||
|
recalculateAbsolutePosition(false);
|
||||||
|
|
||||||
|
v2s32 size = rect.getSize();
|
||||||
|
v2s32 topleft_client(0, 0);
|
||||||
|
|
||||||
|
const wchar_t *text;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add stuff
|
||||||
|
*/
|
||||||
|
s32 ypos = 30;
|
||||||
|
{
|
||||||
|
std::string address = m_address;
|
||||||
|
if (address.empty())
|
||||||
|
address = "localhost";
|
||||||
|
core::rect<s32> rect(0, 0, 540, 90);
|
||||||
|
rect += topleft_client + v2s32(30, ypos);
|
||||||
|
static const std::string info_text_template = strgettext(
|
||||||
|
"You are about to join the server at %1$s with the "
|
||||||
|
"name \"%2$s\" for the first time. If you proceed, a "
|
||||||
|
"new account using your credentials will be created "
|
||||||
|
"on this server.\n"
|
||||||
|
"Please retype your password and click Register and "
|
||||||
|
"Join to confirm account creation or click Cancel to "
|
||||||
|
"abort.");
|
||||||
|
char info_text_buf[1024];
|
||||||
|
snprintf(info_text_buf, sizeof(info_text_buf), info_text_template.c_str(),
|
||||||
|
address.c_str(), m_playername.c_str());
|
||||||
|
Environment->addStaticText(narrow_to_wide_c(info_text_buf), rect, false,
|
||||||
|
true, this, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ypos += 120;
|
||||||
|
{
|
||||||
|
core::rect<s32> rect(0, 0, 540, 30);
|
||||||
|
rect += topleft_client + v2s32(30, ypos);
|
||||||
|
gui::IGUIEditBox *e = Environment->addEditBox(m_pass_confirm.c_str(),
|
||||||
|
rect, true, this, ID_confirmPassword);
|
||||||
|
e->setPasswordBox(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ypos += 90;
|
||||||
|
{
|
||||||
|
core::rect<s32> rect(0, 0, 230, 35);
|
||||||
|
rect = rect + v2s32(size.X / 2 - 220, ypos);
|
||||||
|
text = wgettext("Register and Join");
|
||||||
|
Environment->addButton(rect, this, ID_confirm, text);
|
||||||
|
delete[] text;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
core::rect<s32> rect(0, 0, 120, 35);
|
||||||
|
rect = rect + v2s32(size.X / 2 + 70, ypos);
|
||||||
|
text = wgettext("Cancel");
|
||||||
|
Environment->addButton(rect, this, ID_cancel, text);
|
||||||
|
delete[] text;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
core::rect<s32> rect(0, 0, 200, 20);
|
||||||
|
rect += topleft_client + v2s32(30, ypos - 40);
|
||||||
|
text = wgettext("Passwords do not match!");
|
||||||
|
IGUIElement *e = Environment->addStaticText(
|
||||||
|
text, rect, false, true, this, ID_message);
|
||||||
|
e->setVisible(false);
|
||||||
|
delete[] text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIConfirmRegistration::drawMenu()
|
||||||
|
{
|
||||||
|
gui::IGUISkin *skin = Environment->getSkin();
|
||||||
|
if (!skin)
|
||||||
|
return;
|
||||||
|
video::IVideoDriver *driver = Environment->getVideoDriver();
|
||||||
|
|
||||||
|
video::SColor bgcolor(140, 0, 0, 0);
|
||||||
|
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
|
||||||
|
|
||||||
|
gui::IGUIElement::draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIConfirmRegistration::closeMenu(bool goNext)
|
||||||
|
{
|
||||||
|
quitMenu();
|
||||||
|
if (goNext) {
|
||||||
|
m_client->confirmRegistration();
|
||||||
|
} else {
|
||||||
|
*m_aborted = true;
|
||||||
|
infostream << "Connect aborted [Escape]" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIConfirmRegistration::acceptInput()
|
||||||
|
{
|
||||||
|
gui::IGUIElement *e;
|
||||||
|
e = getElementFromId(ID_confirmPassword);
|
||||||
|
if (e)
|
||||||
|
m_pass_confirm = e->getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIConfirmRegistration::processInput()
|
||||||
|
{
|
||||||
|
std::wstring m_password_ws = narrow_to_wide(m_password);
|
||||||
|
if (m_password_ws != m_pass_confirm) {
|
||||||
|
gui::IGUIElement *e = getElementFromId(ID_message);
|
||||||
|
if (e)
|
||||||
|
e->setVisible(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIConfirmRegistration::OnEvent(const SEvent &event)
|
||||||
|
{
|
||||||
|
if (event.EventType == EET_KEY_INPUT_EVENT) {
|
||||||
|
if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) {
|
||||||
|
closeMenu(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) {
|
||||||
|
acceptInput();
|
||||||
|
if (processInput())
|
||||||
|
closeMenu(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.EventType != EET_GUI_EVENT)
|
||||||
|
return Parent ? Parent->OnEvent(event) : false;
|
||||||
|
|
||||||
|
if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) {
|
||||||
|
if (!canTakeFocus(event.GUIEvent.Element)) {
|
||||||
|
dstream << "GUIConfirmRegistration: Not allowing focus "
|
||||||
|
"change."
|
||||||
|
<< std::endl;
|
||||||
|
// Returning true disables focus change
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) {
|
||||||
|
switch (event.GUIEvent.Caller->getID()) {
|
||||||
|
case ID_confirm:
|
||||||
|
acceptInput();
|
||||||
|
if (processInput())
|
||||||
|
closeMenu(true);
|
||||||
|
return true;
|
||||||
|
case ID_cancel:
|
||||||
|
closeMenu(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (event.GUIEvent.EventType == gui::EGET_EDITBOX_ENTER) {
|
||||||
|
switch (event.GUIEvent.Caller->getID()) {
|
||||||
|
case ID_confirmPassword:
|
||||||
|
acceptInput();
|
||||||
|
if (processInput())
|
||||||
|
closeMenu(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
61
src/gui/guiConfirmRegistration.h
Normal file
61
src/gui/guiConfirmRegistration.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2018 srifqi, Muhammad Rifqi Priyo Susanto
|
||||||
|
<muhammadrifqipriyosusanto@gmail.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "irrlichttypes_extrabloated.h"
|
||||||
|
#include "modalMenu.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Client;
|
||||||
|
|
||||||
|
class GUIConfirmRegistration : public GUIModalMenu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
|
||||||
|
s32 id, IMenuManager *menumgr, Client *client,
|
||||||
|
const std::string &playername, const std::string &password,
|
||||||
|
const std::string &address, bool *aborted);
|
||||||
|
~GUIConfirmRegistration();
|
||||||
|
|
||||||
|
void removeChildren();
|
||||||
|
/*
|
||||||
|
Remove and re-add (or reposition) stuff
|
||||||
|
*/
|
||||||
|
void regenerateGui(v2u32 screensize);
|
||||||
|
|
||||||
|
void drawMenu();
|
||||||
|
|
||||||
|
void closeMenu(bool goNext);
|
||||||
|
|
||||||
|
void acceptInput();
|
||||||
|
|
||||||
|
bool processInput();
|
||||||
|
|
||||||
|
bool OnEvent(const SEvent &event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Client *m_client = nullptr;
|
||||||
|
const std::string &m_playername;
|
||||||
|
const std::string &m_password;
|
||||||
|
const std::string &m_address;
|
||||||
|
bool *m_aborted = nullptr;
|
||||||
|
std::wstring m_pass_confirm = L"";
|
||||||
|
};
|
@ -149,9 +149,8 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
|||||||
g_fontengine->getTextHeight());
|
g_fontengine->getTextHeight());
|
||||||
rect += v2s32(4, 0);
|
rect += v2s32(4, 0);
|
||||||
|
|
||||||
m_irr_toplefttext =
|
m_irr_toplefttext = gui::StaticText::add(RenderingEngine::get_gui_env(),
|
||||||
addStaticText(RenderingEngine::get_gui_env(), m_toplefttext,
|
m_toplefttext, rect, false, true, 0, -1);
|
||||||
rect, false, true, 0, -1);
|
|
||||||
|
|
||||||
//create formspecsource
|
//create formspecsource
|
||||||
m_formspecgui = new FormspecFormSource("");
|
m_formspecgui = new FormspecFormSource("");
|
||||||
@ -560,9 +559,8 @@ void GUIEngine::updateTopLeftTextSize()
|
|||||||
rect += v2s32(4, 0);
|
rect += v2s32(4, 0);
|
||||||
|
|
||||||
m_irr_toplefttext->remove();
|
m_irr_toplefttext->remove();
|
||||||
m_irr_toplefttext =
|
m_irr_toplefttext = gui::StaticText::add(RenderingEngine::get_gui_env(),
|
||||||
addStaticText(RenderingEngine::get_gui_env(), m_toplefttext,
|
m_toplefttext, rect, false, true, 0, -1);
|
||||||
rect, false, true, 0, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -39,11 +39,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "client/tile.h" // ITextureSource
|
#include "client/tile.h" // ITextureSource
|
||||||
#include "hud.h" // drawItemStack
|
#include "client/hud.h" // drawItemStack
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "gettime.h"
|
#include "gettime.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "scripting_server.h"
|
#include "scripting_server.h"
|
||||||
|
#include "mainmenumanager.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
@ -57,6 +58,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#if USE_FREETYPE && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
|
#if USE_FREETYPE && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
|
||||||
#include "intlGUIEditBox.h"
|
#include "intlGUIEditBox.h"
|
||||||
|
#include "mainmenumanager.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MY_CHECKPOS(a,b) \
|
#define MY_CHECKPOS(a,b) \
|
||||||
@ -129,6 +132,28 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
|
|||||||
delete m_text_dst;
|
delete m_text_dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client,
|
||||||
|
JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest)
|
||||||
|
{
|
||||||
|
if (cur_formspec == nullptr) {
|
||||||
|
cur_formspec = new GUIFormSpecMenu(joystick, guiroot, -1, &g_menumgr,
|
||||||
|
client, client->getTextureSource(), fs_src, txt_dest);
|
||||||
|
cur_formspec->doPause = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Caution: do not call (*cur_formspec)->drop() here --
|
||||||
|
the reference might outlive the menu, so we will
|
||||||
|
periodically check if *cur_formspec is the only
|
||||||
|
remaining reference (i.e. the menu was removed)
|
||||||
|
and delete it in that case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cur_formspec->setFormSource(fs_src);
|
||||||
|
cur_formspec->setTextDest(txt_dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::removeChildren()
|
void GUIFormSpecMenu::removeChildren()
|
||||||
{
|
{
|
||||||
const core::list<gui::IGUIElement*> &children = getChildren();
|
const core::list<gui::IGUIElement*> &children = getChildren();
|
||||||
@ -950,12 +975,12 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
|
|||||||
Environment->setFocus(e);
|
Environment->setFocus(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (label.length() >= 1)
|
if (label.length() >= 1) {
|
||||||
{
|
|
||||||
int font_height = g_fontengine->getTextHeight();
|
int font_height = g_fontengine->getTextHeight();
|
||||||
rect.UpperLeftCorner.Y -= font_height;
|
rect.UpperLeftCorner.Y -= font_height;
|
||||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
gui::StaticText::add(Environment, spec.flabel.c_str(), rect, false, true,
|
||||||
|
this, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
e->setPasswordBox(true,L'*');
|
e->setPasswordBox(true,L'*');
|
||||||
@ -1017,7 +1042,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
|
|||||||
|
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
// spec field id to 0, this stops submit searching for a value that isn't there
|
// spec field id to 0, this stops submit searching for a value that isn't there
|
||||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid);
|
gui::StaticText::add(Environment, spec.flabel.c_str(), rect, false, true, this,
|
||||||
|
spec.fid);
|
||||||
} else {
|
} else {
|
||||||
spec.send = true;
|
spec.send = true;
|
||||||
gui::IGUIElement *e;
|
gui::IGUIElement *e;
|
||||||
@ -1050,7 +1076,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
|
|||||||
int font_height = g_fontengine->getTextHeight();
|
int font_height = g_fontengine->getTextHeight();
|
||||||
rect.UpperLeftCorner.Y -= font_height;
|
rect.UpperLeftCorner.Y -= font_height;
|
||||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
gui::StaticText::add(Environment, spec.flabel.c_str(), rect, false, true,
|
||||||
|
this, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1162,7 +1189,8 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
|
|||||||
int font_height = g_fontengine->getTextHeight();
|
int font_height = g_fontengine->getTextHeight();
|
||||||
rect.UpperLeftCorner.Y -= font_height;
|
rect.UpperLeftCorner.Y -= font_height;
|
||||||
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
|
||||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0);
|
gui::StaticText::add(Environment, spec.flabel.c_str(), rect, false, true,
|
||||||
|
this, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parts.size() >= 6) {
|
if (parts.size() >= 6) {
|
||||||
@ -1237,11 +1265,9 @@ void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element)
|
|||||||
L"",
|
L"",
|
||||||
258+m_fields.size()
|
258+m_fields.size()
|
||||||
);
|
);
|
||||||
gui::IGUIStaticText *e =
|
gui::IGUIStaticText *e = gui::StaticText::add(Environment,
|
||||||
addStaticText(Environment, spec.flabel.c_str(),
|
spec.flabel.c_str(), rect, false, false, this, spec.fid);
|
||||||
rect, false, false, this, spec.fid);
|
e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER);
|
||||||
e->setTextAlignment(gui::EGUIA_UPPERLEFT,
|
|
||||||
gui::EGUIA_CENTER);
|
|
||||||
m_fields.push_back(spec);
|
m_fields.push_back(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1291,8 +1317,8 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &elemen
|
|||||||
L"",
|
L"",
|
||||||
258+m_fields.size()
|
258+m_fields.size()
|
||||||
);
|
);
|
||||||
gui::IGUIStaticText *t =
|
gui::IGUIStaticText *t = gui::StaticText::add(Environment, spec.flabel.c_str(),
|
||||||
addStaticText(Environment, spec.flabel.c_str(), rect, false, false, this, spec.fid);
|
rect, false, false, this, spec.fid);
|
||||||
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
|
t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
|
||||||
m_fields.push_back(spec);
|
m_fields.push_back(spec);
|
||||||
return;
|
return;
|
||||||
@ -2024,7 +2050,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
{
|
{
|
||||||
assert(!m_tooltip_element);
|
assert(!m_tooltip_element);
|
||||||
// Note: parent != this so that the tooltip isn't clipped by the menu rectangle
|
// Note: parent != this so that the tooltip isn't clipped by the menu rectangle
|
||||||
m_tooltip_element = addStaticText(Environment, L"",core::rect<s32>(0,0,110,18));
|
m_tooltip_element = gui::StaticText::add(Environment, L"",
|
||||||
|
core::rect<s32>(0, 0, 110, 18));
|
||||||
m_tooltip_element->enableOverrideColor(true);
|
m_tooltip_element->enableOverrideColor(true);
|
||||||
m_tooltip_element->setBackgroundColor(m_default_tooltip_bgcolor);
|
m_tooltip_element->setBackgroundColor(m_default_tooltip_bgcolor);
|
||||||
m_tooltip_element->setDrawBackground(true);
|
m_tooltip_element->setDrawBackground(true);
|
||||||
@ -3668,18 +3695,24 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
a->from_i = m_selected_item->i;
|
a->from_i = m_selected_item->i;
|
||||||
m_invmgr->inventoryAction(a);
|
m_invmgr->inventoryAction(a);
|
||||||
} else if (craft_amount > 0) {
|
} else if (craft_amount > 0) {
|
||||||
m_selected_content_guess = ItemStack(); // Clear
|
|
||||||
|
|
||||||
// Send IAction::Craft
|
|
||||||
|
|
||||||
assert(s.isValid());
|
assert(s.isValid());
|
||||||
assert(inv_s);
|
|
||||||
|
|
||||||
infostream << "Handing IAction::Craft to manager" << std::endl;
|
// if there are no items selected or the selected item
|
||||||
ICraftAction *a = new ICraftAction();
|
// belongs to craftresult list, proceed with crafting
|
||||||
a->count = craft_amount;
|
if (m_selected_item == NULL ||
|
||||||
a->craft_inv = s.inventoryloc;
|
!m_selected_item->isValid() || m_selected_item->listname == "craftresult") {
|
||||||
m_invmgr->inventoryAction(a);
|
|
||||||
|
m_selected_content_guess = ItemStack(); // Clear
|
||||||
|
|
||||||
|
assert(inv_s);
|
||||||
|
|
||||||
|
// 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
|
// If m_selected_amount has been decreased to zero, deselect
|
||||||
|
@ -291,6 +291,9 @@ public:
|
|||||||
|
|
||||||
~GUIFormSpecMenu();
|
~GUIFormSpecMenu();
|
||||||
|
|
||||||
|
static void create(GUIFormSpecMenu *&cur_formspec, Client *client,
|
||||||
|
JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest);
|
||||||
|
|
||||||
void setFormSpec(const std::string &formspec_string,
|
void setFormSpec(const std::string &formspec_string,
|
||||||
const InventoryLocation ¤t_inventory_location)
|
const InventoryLocation ¤t_inventory_location)
|
||||||
{
|
{
|
||||||
|
@ -1430,14 +1430,14 @@ void intlGUIEditBox::calculateScrollPos()
|
|||||||
// todo: adjust scrollbar
|
// todo: adjust scrollbar
|
||||||
}
|
}
|
||||||
|
|
||||||
// vertical scroll position
|
if (!WordWrap && !MultiLine)
|
||||||
if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y + VScrollPos)
|
return;
|
||||||
VScrollPos = CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y + VScrollPos;
|
|
||||||
|
|
||||||
else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y + VScrollPos)
|
// vertical scroll position
|
||||||
VScrollPos = CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y + VScrollPos;
|
if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y)
|
||||||
else
|
VScrollPos += CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y; // scrolling downwards
|
||||||
VScrollPos = 0;
|
else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y)
|
||||||
|
VScrollPos += CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y; // scrolling upwards
|
||||||
|
|
||||||
// todo: adjust scrollbar
|
// todo: adjust scrollbar
|
||||||
if (m_vscrollbar)
|
if (m_vscrollbar)
|
||||||
|
166
src/gui/profilergraph.cpp
Normal file
166
src/gui/profilergraph.cpp
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2018 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "profilergraph.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
void ProfilerGraph::put(const Profiler::GraphValues &values)
|
||||||
|
{
|
||||||
|
m_log.emplace_back(values);
|
||||||
|
|
||||||
|
while (m_log.size() > m_log_max_size)
|
||||||
|
m_log.erase(m_log.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfilerGraph::draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
|
||||||
|
gui::IGUIFont *font) const
|
||||||
|
{
|
||||||
|
// Do *not* use UNORDERED_MAP here as the order needs
|
||||||
|
// to be the same for each call to prevent flickering
|
||||||
|
std::map<std::string, Meta> m_meta;
|
||||||
|
|
||||||
|
for (const Piece &piece : m_log) {
|
||||||
|
for (const auto &i : piece.values) {
|
||||||
|
const std::string &id = i.first;
|
||||||
|
const float &value = i.second;
|
||||||
|
std::map<std::string, Meta>::iterator j = m_meta.find(id);
|
||||||
|
|
||||||
|
if (j == m_meta.end()) {
|
||||||
|
m_meta[id] = Meta(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < j->second.min)
|
||||||
|
j->second.min = value;
|
||||||
|
|
||||||
|
if (value > j->second.max)
|
||||||
|
j->second.max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign colors
|
||||||
|
static const video::SColor usable_colors[] = {video::SColor(255, 255, 100, 100),
|
||||||
|
video::SColor(255, 90, 225, 90),
|
||||||
|
video::SColor(255, 100, 100, 255),
|
||||||
|
video::SColor(255, 255, 150, 50),
|
||||||
|
video::SColor(255, 220, 220, 100)};
|
||||||
|
static const u32 usable_colors_count =
|
||||||
|
sizeof(usable_colors) / sizeof(*usable_colors);
|
||||||
|
u32 next_color_i = 0;
|
||||||
|
|
||||||
|
for (auto &i : m_meta) {
|
||||||
|
Meta &meta = i.second;
|
||||||
|
video::SColor color(255, 200, 200, 200);
|
||||||
|
|
||||||
|
if (next_color_i < usable_colors_count)
|
||||||
|
color = usable_colors[next_color_i++];
|
||||||
|
|
||||||
|
meta.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 graphh = 50;
|
||||||
|
s32 textx = x_left + m_log_max_size + 15;
|
||||||
|
s32 textx2 = textx + 200 - 15;
|
||||||
|
s32 meta_i = 0;
|
||||||
|
|
||||||
|
for (const auto &p : m_meta) {
|
||||||
|
const std::string &id = p.first;
|
||||||
|
const Meta &meta = p.second;
|
||||||
|
s32 x = x_left;
|
||||||
|
s32 y = y_bottom - meta_i * 50;
|
||||||
|
float show_min = meta.min;
|
||||||
|
float show_max = meta.max;
|
||||||
|
|
||||||
|
if (show_min >= -0.0001 && show_max >= -0.0001) {
|
||||||
|
if (show_min <= show_max * 0.5)
|
||||||
|
show_min = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 texth = 15;
|
||||||
|
char buf[10];
|
||||||
|
snprintf(buf, 10, "%.3g", show_max);
|
||||||
|
font->draw(utf8_to_wide(buf).c_str(),
|
||||||
|
core::rect<s32>(textx, y - graphh, textx2,
|
||||||
|
y - graphh + texth),
|
||||||
|
meta.color);
|
||||||
|
snprintf(buf, 10, "%.3g", show_min);
|
||||||
|
font->draw(utf8_to_wide(buf).c_str(),
|
||||||
|
core::rect<s32>(textx, y - texth, textx2, y), meta.color);
|
||||||
|
font->draw(utf8_to_wide(id).c_str(),
|
||||||
|
core::rect<s32>(textx, y - graphh / 2 - texth / 2, textx2,
|
||||||
|
y - graphh / 2 + texth / 2),
|
||||||
|
meta.color);
|
||||||
|
s32 graph1y = y;
|
||||||
|
s32 graph1h = graphh;
|
||||||
|
bool relativegraph = (show_min != 0 && show_min != show_max);
|
||||||
|
float lastscaledvalue = 0.0;
|
||||||
|
bool lastscaledvalue_exists = false;
|
||||||
|
|
||||||
|
for (const Piece &piece : m_log) {
|
||||||
|
float value = 0;
|
||||||
|
bool value_exists = false;
|
||||||
|
Profiler::GraphValues::const_iterator k = piece.values.find(id);
|
||||||
|
|
||||||
|
if (k != piece.values.end()) {
|
||||||
|
value = k->second;
|
||||||
|
value_exists = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value_exists) {
|
||||||
|
x++;
|
||||||
|
lastscaledvalue_exists = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scaledvalue = 1.0;
|
||||||
|
|
||||||
|
if (show_max != show_min)
|
||||||
|
scaledvalue = (value - show_min) / (show_max - show_min);
|
||||||
|
|
||||||
|
if (scaledvalue == 1.0 && value == 0) {
|
||||||
|
x++;
|
||||||
|
lastscaledvalue_exists = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relativegraph) {
|
||||||
|
if (lastscaledvalue_exists) {
|
||||||
|
s32 ivalue1 = lastscaledvalue * graph1h;
|
||||||
|
s32 ivalue2 = scaledvalue * graph1h;
|
||||||
|
driver->draw2DLine(
|
||||||
|
v2s32(x - 1, graph1y - ivalue1),
|
||||||
|
v2s32(x, graph1y - ivalue2),
|
||||||
|
meta.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastscaledvalue = scaledvalue;
|
||||||
|
lastscaledvalue_exists = true;
|
||||||
|
} else {
|
||||||
|
s32 ivalue = scaledvalue * graph1h;
|
||||||
|
driver->draw2DLine(v2s32(x, graph1y),
|
||||||
|
v2s32(x, graph1y - ivalue), meta.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_i++;
|
||||||
|
}
|
||||||
|
}
|
61
src/gui/profilergraph.h
Normal file
61
src/gui/profilergraph.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Minetest
|
||||||
|
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SColor.h>
|
||||||
|
#include <deque>
|
||||||
|
#include <utility>
|
||||||
|
#include <IGUIFont.h>
|
||||||
|
#include <IVideoDriver.h>
|
||||||
|
#include "profiler.h"
|
||||||
|
|
||||||
|
/* Profiler display */
|
||||||
|
class ProfilerGraph
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct Piece
|
||||||
|
{
|
||||||
|
Piece(Profiler::GraphValues v) : values(std::move(v)) {}
|
||||||
|
Profiler::GraphValues values;
|
||||||
|
};
|
||||||
|
struct Meta
|
||||||
|
{
|
||||||
|
float min;
|
||||||
|
float max;
|
||||||
|
video::SColor color;
|
||||||
|
Meta(float initial = 0,
|
||||||
|
video::SColor color = video::SColor(255, 255, 255, 255)) :
|
||||||
|
min(initial),
|
||||||
|
max(initial), color(color)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::deque<Piece> m_log;
|
||||||
|
|
||||||
|
public:
|
||||||
|
u32 m_log_max_size = 200;
|
||||||
|
|
||||||
|
ProfilerGraph() = default;
|
||||||
|
|
||||||
|
void put(const Profiler::GraphValues &values);
|
||||||
|
|
||||||
|
void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
|
||||||
|
gui::IGUIFont *font) const;
|
||||||
|
};
|
798
src/hud.cpp
798
src/hud.cpp
@ -1,775 +1,39 @@
|
|||||||
/*
|
|
||||||
Minetest
|
|
||||||
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
|
||||||
Copyright (C) 2010-2013 blue42u, Jonathon Anderson <anderjon@umail.iu.edu>
|
|
||||||
Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2.1 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hud.h"
|
#include "hud.h"
|
||||||
#include "settings.h"
|
|
||||||
#include "util/numeric.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "client.h"
|
|
||||||
#include "inventory.h"
|
|
||||||
#include "shader.h"
|
|
||||||
#include "client/tile.h"
|
|
||||||
#include "localplayer.h"
|
|
||||||
#include "camera.h"
|
|
||||||
#include "porting.h"
|
|
||||||
#include "fontengine.h"
|
|
||||||
#include "guiscalingfilter.h"
|
|
||||||
#include "mesh.h"
|
|
||||||
#include "wieldmesh.h"
|
|
||||||
#include "client/renderingengine.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_TOUCHSCREENGUI
|
|
||||||
#include "gui/touchscreengui.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
|
const struct EnumString es_HudElementType[] =
|
||||||
Inventory *inventory)
|
|
||||||
{
|
{
|
||||||
driver = RenderingEngine::get_video_driver();
|
{HUD_ELEM_IMAGE, "image"},
|
||||||
this->guienv = guienv;
|
{HUD_ELEM_TEXT, "text"},
|
||||||
this->client = client;
|
{HUD_ELEM_STATBAR, "statbar"},
|
||||||
this->player = player;
|
{HUD_ELEM_INVENTORY, "inventory"},
|
||||||
this->inventory = inventory;
|
{HUD_ELEM_WAYPOINT, "waypoint"},
|
||||||
|
{0, NULL},
|
||||||
m_hud_scaling = g_settings->getFloat("hud_scaling");
|
|
||||||
m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
|
|
||||||
RenderingEngine::getDisplayDensity() + 0.5f);
|
|
||||||
m_hotbar_imagesize *= m_hud_scaling;
|
|
||||||
m_padding = m_hotbar_imagesize / 12;
|
|
||||||
|
|
||||||
for (auto &hbar_color : hbar_colors)
|
|
||||||
hbar_color = video::SColor(255, 255, 255, 255);
|
|
||||||
|
|
||||||
tsrc = client->getTextureSource();
|
|
||||||
|
|
||||||
v3f crosshair_color = g_settings->getV3F("crosshair_color");
|
|
||||||
u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
|
|
||||||
u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
|
|
||||||
u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
|
|
||||||
u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
|
|
||||||
crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
|
|
||||||
|
|
||||||
v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
|
|
||||||
u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
|
|
||||||
u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
|
|
||||||
u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
|
|
||||||
selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
|
|
||||||
|
|
||||||
use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
|
|
||||||
|
|
||||||
m_selection_boxes.clear();
|
|
||||||
m_halo_boxes.clear();
|
|
||||||
|
|
||||||
std::string mode_setting = g_settings->get("node_highlighting");
|
|
||||||
|
|
||||||
if (mode_setting == "halo") {
|
|
||||||
m_mode = HIGHLIGHT_HALO;
|
|
||||||
} else if (mode_setting == "none") {
|
|
||||||
m_mode = HIGHLIGHT_NONE;
|
|
||||||
} else {
|
|
||||||
m_mode = HIGHLIGHT_BOX;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_selection_material.Lighting = false;
|
|
||||||
|
|
||||||
if (g_settings->getBool("enable_shaders")) {
|
|
||||||
IShaderSource *shdrsrc = client->getShaderSource();
|
|
||||||
u16 shader_id = shdrsrc->getShader(
|
|
||||||
m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1);
|
|
||||||
m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
|
|
||||||
} else {
|
|
||||||
m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_mode == HIGHLIGHT_BOX) {
|
|
||||||
m_selection_material.Thickness =
|
|
||||||
rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
|
|
||||||
} else if (m_mode == HIGHLIGHT_HALO) {
|
|
||||||
m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png"));
|
|
||||||
m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
|
|
||||||
} else {
|
|
||||||
m_selection_material.MaterialType = video::EMT_SOLID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Hud::~Hud()
|
|
||||||
{
|
|
||||||
if (m_selection_mesh)
|
|
||||||
m_selection_mesh->drop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
|
|
||||||
bool selected)
|
|
||||||
{
|
|
||||||
if (selected) {
|
|
||||||
/* draw hihlighting around selected item */
|
|
||||||
if (use_hotbar_selected_image) {
|
|
||||||
core::rect<s32> imgrect2 = rect;
|
|
||||||
imgrect2.UpperLeftCorner.X -= (m_padding*2);
|
|
||||||
imgrect2.UpperLeftCorner.Y -= (m_padding*2);
|
|
||||||
imgrect2.LowerRightCorner.X += (m_padding*2);
|
|
||||||
imgrect2.LowerRightCorner.Y += (m_padding*2);
|
|
||||||
video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
|
|
||||||
core::dimension2di imgsize(texture->getOriginalSize());
|
|
||||||
draw2DImageFilterScaled(driver, texture, imgrect2,
|
|
||||||
core::rect<s32>(core::position2d<s32>(0,0), imgsize),
|
|
||||||
NULL, hbar_colors, true);
|
|
||||||
} else {
|
|
||||||
video::SColor c_outside(255,255,0,0);
|
|
||||||
//video::SColor c_outside(255,0,0,0);
|
|
||||||
//video::SColor c_inside(255,192,192,192);
|
|
||||||
s32 x1 = rect.UpperLeftCorner.X;
|
|
||||||
s32 y1 = rect.UpperLeftCorner.Y;
|
|
||||||
s32 x2 = rect.LowerRightCorner.X;
|
|
||||||
s32 y2 = rect.LowerRightCorner.Y;
|
|
||||||
// Black base borders
|
|
||||||
driver->draw2DRectangle(c_outside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x1 - m_padding, y1 - m_padding),
|
|
||||||
v2s32(x2 + m_padding, y1)
|
|
||||||
), NULL);
|
|
||||||
driver->draw2DRectangle(c_outside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x1 - m_padding, y2),
|
|
||||||
v2s32(x2 + m_padding, y2 + m_padding)
|
|
||||||
), NULL);
|
|
||||||
driver->draw2DRectangle(c_outside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x1 - m_padding, y1),
|
|
||||||
v2s32(x1, y2)
|
|
||||||
), NULL);
|
|
||||||
driver->draw2DRectangle(c_outside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x2, y1),
|
|
||||||
v2s32(x2 + m_padding, y2)
|
|
||||||
), NULL);
|
|
||||||
/*// Light inside borders
|
|
||||||
driver->draw2DRectangle(c_inside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x1 - padding/2, y1 - padding/2),
|
|
||||||
v2s32(x2 + padding/2, y1)
|
|
||||||
), NULL);
|
|
||||||
driver->draw2DRectangle(c_inside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x1 - padding/2, y2),
|
|
||||||
v2s32(x2 + padding/2, y2 + padding/2)
|
|
||||||
), NULL);
|
|
||||||
driver->draw2DRectangle(c_inside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x1 - padding/2, y1),
|
|
||||||
v2s32(x1, y2)
|
|
||||||
), NULL);
|
|
||||||
driver->draw2DRectangle(c_inside,
|
|
||||||
core::rect<s32>(
|
|
||||||
v2s32(x2, y1),
|
|
||||||
v2s32(x2 + padding/2, y2)
|
|
||||||
), NULL);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
video::SColor bgcolor2(128, 0, 0, 0);
|
|
||||||
if (!use_hotbar_image)
|
|
||||||
driver->draw2DRectangle(bgcolor2, rect, NULL);
|
|
||||||
drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL,
|
|
||||||
client, selected ? IT_ROT_SELECTED : IT_ROT_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//NOTE: selectitem = 0 -> no selected; selectitem 1-based
|
|
||||||
void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
|
|
||||||
s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_TOUCHSCREENGUI
|
|
||||||
if (g_touchscreengui && inv_offset == 0)
|
|
||||||
g_touchscreengui->resetHud();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
s32 height = m_hotbar_imagesize + m_padding * 2;
|
|
||||||
s32 width = (itemcount - inv_offset) * (m_hotbar_imagesize + m_padding * 2);
|
|
||||||
|
|
||||||
if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
|
|
||||||
s32 tmp = height;
|
|
||||||
height = width;
|
|
||||||
width = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Position of upper left corner of bar
|
|
||||||
v2s32 pos = screen_offset;
|
|
||||||
pos.X *= m_hud_scaling * RenderingEngine::getDisplayDensity();
|
|
||||||
pos.Y *= m_hud_scaling * RenderingEngine::getDisplayDensity();
|
|
||||||
pos += upperleftpos;
|
|
||||||
|
|
||||||
// Store hotbar_image in member variable, used by drawItem()
|
|
||||||
if (hotbar_image != player->hotbar_image) {
|
|
||||||
hotbar_image = player->hotbar_image;
|
|
||||||
if (!hotbar_image.empty())
|
|
||||||
use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
|
|
||||||
else
|
|
||||||
use_hotbar_image = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store hotbar_selected_image in member variable, used by drawItem()
|
|
||||||
if (hotbar_selected_image != player->hotbar_selected_image) {
|
|
||||||
hotbar_selected_image = player->hotbar_selected_image;
|
|
||||||
if (!hotbar_selected_image.empty())
|
|
||||||
use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
|
|
||||||
else
|
|
||||||
use_hotbar_selected_image = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw customized item background
|
|
||||||
if (use_hotbar_image) {
|
|
||||||
core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
|
|
||||||
width+m_padding/2, height+m_padding/2);
|
|
||||||
core::rect<s32> rect2 = imgrect2 + pos;
|
|
||||||
video::ITexture *texture = tsrc->getTexture(hotbar_image);
|
|
||||||
core::dimension2di imgsize(texture->getOriginalSize());
|
|
||||||
draw2DImageFilterScaled(driver, texture, rect2,
|
|
||||||
core::rect<s32>(core::position2d<s32>(0,0), imgsize),
|
|
||||||
NULL, hbar_colors, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw items
|
|
||||||
core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
|
|
||||||
for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) {
|
|
||||||
s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
|
|
||||||
|
|
||||||
v2s32 steppos;
|
|
||||||
switch (direction) {
|
|
||||||
case HUD_DIR_RIGHT_LEFT:
|
|
||||||
steppos = v2s32(-(m_padding + (i - inv_offset) * fullimglen), m_padding);
|
|
||||||
break;
|
|
||||||
case HUD_DIR_TOP_BOTTOM:
|
|
||||||
steppos = v2s32(m_padding, m_padding + (i - inv_offset) * fullimglen);
|
|
||||||
break;
|
|
||||||
case HUD_DIR_BOTTOM_TOP:
|
|
||||||
steppos = v2s32(m_padding, -(m_padding + (i - inv_offset) * fullimglen));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
steppos = v2s32(m_padding + (i - inv_offset) * fullimglen, m_padding);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i + 1) == selectitem);
|
|
||||||
|
|
||||||
#ifdef HAVE_TOUCHSCREENGUI
|
|
||||||
if (g_touchscreengui)
|
|
||||||
g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Hud::drawLuaElements(const v3s16 &camera_offset)
|
|
||||||
{
|
|
||||||
u32 text_height = g_fontengine->getTextHeight();
|
|
||||||
irr::gui::IGUIFont* font = g_fontengine->getFont();
|
|
||||||
for (size_t i = 0; i != player->maxHudId(); i++) {
|
|
||||||
HudElement *e = player->getHud(i);
|
|
||||||
if (!e)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
|
|
||||||
floor(e->pos.Y * (float) m_screensize.Y + 0.5));
|
|
||||||
switch (e->type) {
|
|
||||||
case HUD_ELEM_IMAGE: {
|
|
||||||
video::ITexture *texture = tsrc->getTexture(e->text);
|
|
||||||
if (!texture)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const video::SColor color(255, 255, 255, 255);
|
|
||||||
const video::SColor colors[] = {color, color, color, color};
|
|
||||||
core::dimension2di imgsize(texture->getOriginalSize());
|
|
||||||
v2s32 dstsize(imgsize.Width * e->scale.X,
|
|
||||||
imgsize.Height * e->scale.Y);
|
|
||||||
if (e->scale.X < 0)
|
|
||||||
dstsize.X = m_screensize.X * (e->scale.X * -0.01);
|
|
||||||
if (e->scale.Y < 0)
|
|
||||||
dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
|
|
||||||
v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
|
|
||||||
(e->align.Y - 1.0) * dstsize.Y / 2);
|
|
||||||
core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
|
|
||||||
rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
|
|
||||||
draw2DImageFilterScaled(driver, texture, rect,
|
|
||||||
core::rect<s32>(core::position2d<s32>(0,0), imgsize),
|
|
||||||
NULL, colors, true);
|
|
||||||
break; }
|
|
||||||
case HUD_ELEM_TEXT: {
|
|
||||||
video::SColor color(255, (e->number >> 16) & 0xFF,
|
|
||||||
(e->number >> 8) & 0xFF,
|
|
||||||
(e->number >> 0) & 0xFF);
|
|
||||||
core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
|
|
||||||
std::wstring text = unescape_translate(utf8_to_wide(e->text));
|
|
||||||
core::dimension2d<u32> textsize = font->getDimension(text.c_str());
|
|
||||||
v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
|
|
||||||
(e->align.Y - 1.0) * (textsize.Height / 2));
|
|
||||||
v2s32 offs(e->offset.X, e->offset.Y);
|
|
||||||
font->draw(text.c_str(), size + pos + offset + offs, color);
|
|
||||||
break; }
|
|
||||||
case HUD_ELEM_STATBAR: {
|
|
||||||
v2s32 offs(e->offset.X, e->offset.Y);
|
|
||||||
drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
|
|
||||||
break; }
|
|
||||||
case HUD_ELEM_INVENTORY: {
|
|
||||||
InventoryList *inv = inventory->getList(e->text);
|
|
||||||
drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0,
|
|
||||||
inv, e->item, e->dir);
|
|
||||||
break; }
|
|
||||||
case HUD_ELEM_WAYPOINT: {
|
|
||||||
v3f p_pos = player->getPosition() / BS;
|
|
||||||
v3f w_pos = e->world_pos * BS;
|
|
||||||
float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
|
|
||||||
scene::ICameraSceneNode* camera =
|
|
||||||
RenderingEngine::get_scene_manager()->getActiveCamera();
|
|
||||||
w_pos -= intToFloat(camera_offset, BS);
|
|
||||||
core::matrix4 trans = camera->getProjectionMatrix();
|
|
||||||
trans *= camera->getViewMatrix();
|
|
||||||
f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
|
|
||||||
trans.multiplyWith1x4Matrix(transformed_pos);
|
|
||||||
if (transformed_pos[3] < 0)
|
|
||||||
break;
|
|
||||||
f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
|
|
||||||
core::reciprocal(transformed_pos[3]);
|
|
||||||
pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
|
|
||||||
pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
|
|
||||||
video::SColor color(255, (e->number >> 16) & 0xFF,
|
|
||||||
(e->number >> 8) & 0xFF,
|
|
||||||
(e->number >> 0) & 0xFF);
|
|
||||||
core::rect<s32> size(0, 0, 200, 2 * text_height);
|
|
||||||
std::wstring text = unescape_translate(utf8_to_wide(e->name));
|
|
||||||
font->draw(text.c_str(), size + pos, color);
|
|
||||||
std::ostringstream os;
|
|
||||||
os << distance << e->text;
|
|
||||||
text = unescape_translate(utf8_to_wide(os.str()));
|
|
||||||
pos.Y += text_height;
|
|
||||||
font->draw(text.c_str(), size + pos, color);
|
|
||||||
break; }
|
|
||||||
default:
|
|
||||||
infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
|
|
||||||
" of hud element ID " << i << " due to unrecognized type" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
|
|
||||||
s32 count, v2s32 offset, v2s32 size)
|
|
||||||
{
|
|
||||||
const video::SColor color(255, 255, 255, 255);
|
|
||||||
const video::SColor colors[] = {color, color, color, color};
|
|
||||||
|
|
||||||
video::ITexture *stat_texture = tsrc->getTexture(texture);
|
|
||||||
if (!stat_texture)
|
|
||||||
return;
|
|
||||||
|
|
||||||
core::dimension2di srcd(stat_texture->getOriginalSize());
|
|
||||||
core::dimension2di dstd;
|
|
||||||
if (size == v2s32()) {
|
|
||||||
dstd = srcd;
|
|
||||||
} else {
|
|
||||||
float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity();
|
|
||||||
dstd.Height = size.Y * size_factor;
|
|
||||||
dstd.Width = size.X * size_factor;
|
|
||||||
offset.X *= size_factor;
|
|
||||||
offset.Y *= size_factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
v2s32 p = pos;
|
|
||||||
if (corner & HUD_CORNER_LOWER)
|
|
||||||
p -= dstd.Height;
|
|
||||||
|
|
||||||
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++) {
|
|
||||||
core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
|
|
||||||
core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
|
|
||||||
|
|
||||||
dstrect += p;
|
|
||||||
draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
|
|
||||||
p += steppos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count % 2 == 1) {
|
|
||||||
dsthalfrect += p;
|
|
||||||
draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Hud::drawHotbar(u16 playeritem) {
|
|
||||||
|
|
||||||
v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
|
|
||||||
|
|
||||||
InventoryList *mainlist = inventory->getList("main");
|
|
||||||
if (mainlist == NULL) {
|
|
||||||
//silently ignore this we may not be initialized completely
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 hotbar_itemcount = player->hud_hotbar_itemcount;
|
|
||||||
s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
|
|
||||||
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
|
|
||||||
|
|
||||||
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
|
||||||
if ( (float) width / (float) window_size.X <=
|
|
||||||
g_settings->getFloat("hud_hotbar_max_width")) {
|
|
||||||
if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
|
|
||||||
drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pos.X += width/4;
|
|
||||||
|
|
||||||
v2s32 secondpos = pos;
|
|
||||||
pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
|
|
||||||
|
|
||||||
if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
|
|
||||||
drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
|
|
||||||
mainlist, playeritem + 1, 0);
|
|
||||||
drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
|
|
||||||
hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////// compatibility code to be removed //////////////
|
|
||||||
// this is ugly as hell but there's no other way to keep compatibility to
|
|
||||||
// old servers
|
|
||||||
if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) {
|
|
||||||
drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
|
|
||||||
floor(1 * (float) m_screensize.Y + 0.5)),
|
|
||||||
HUD_CORNER_UPPER, 0, "heart.png",
|
|
||||||
player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
|
|
||||||
(player->getBreath() < 11)) {
|
|
||||||
drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
|
|
||||||
floor(1 * (float) m_screensize.Y + 0.5)),
|
|
||||||
HUD_CORNER_UPPER, 0, "bubble.png",
|
|
||||||
player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
|
|
||||||
}
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Hud::drawCrosshair()
|
|
||||||
{
|
|
||||||
if (use_crosshair_image) {
|
|
||||||
video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
|
|
||||||
v2u32 size = crosshair->getOriginalSize();
|
|
||||||
v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
|
|
||||||
m_displaycenter.Y - (size.Y / 2));
|
|
||||||
driver->draw2DImage(crosshair, lsize,
|
|
||||||
core::rect<s32>(0, 0, size.X, size.Y),
|
|
||||||
0, crosshair_argb, true);
|
|
||||||
} else {
|
|
||||||
driver->draw2DLine(m_displaycenter - v2s32(10, 0),
|
|
||||||
m_displaycenter + v2s32(10, 0), crosshair_argb);
|
|
||||||
driver->draw2DLine(m_displaycenter - v2s32(0, 10),
|
|
||||||
m_displaycenter + v2s32(0, 10), crosshair_argb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
|
|
||||||
{
|
|
||||||
m_camera_offset = camera_offset;
|
|
||||||
m_selection_pos = pos;
|
|
||||||
m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hud::drawSelectionMesh()
|
|
||||||
{
|
|
||||||
if (m_mode == HIGHLIGHT_BOX) {
|
|
||||||
// Draw 3D selection boxes
|
|
||||||
video::SMaterial oldmaterial = driver->getMaterial2D();
|
|
||||||
driver->setMaterial(m_selection_material);
|
|
||||||
for (std::vector<aabb3f>::const_iterator
|
|
||||||
i = m_selection_boxes.begin();
|
|
||||||
i != m_selection_boxes.end(); ++i) {
|
|
||||||
aabb3f box = aabb3f(
|
|
||||||
i->MinEdge + m_selection_pos_with_offset,
|
|
||||||
i->MaxEdge + m_selection_pos_with_offset);
|
|
||||||
|
|
||||||
u32 r = (selectionbox_argb.getRed() *
|
|
||||||
m_selection_mesh_color.getRed() / 255);
|
|
||||||
u32 g = (selectionbox_argb.getGreen() *
|
|
||||||
m_selection_mesh_color.getGreen() / 255);
|
|
||||||
u32 b = (selectionbox_argb.getBlue() *
|
|
||||||
m_selection_mesh_color.getBlue() / 255);
|
|
||||||
driver->draw3DBox(box, video::SColor(255, r, g, b));
|
|
||||||
}
|
|
||||||
driver->setMaterial(oldmaterial);
|
|
||||||
} else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
|
|
||||||
// Draw selection mesh
|
|
||||||
video::SMaterial oldmaterial = driver->getMaterial2D();
|
|
||||||
driver->setMaterial(m_selection_material);
|
|
||||||
setMeshColor(m_selection_mesh, m_selection_mesh_color);
|
|
||||||
video::SColor face_color(0,
|
|
||||||
MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
|
|
||||||
MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
|
|
||||||
MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
|
|
||||||
setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
|
|
||||||
face_color);
|
|
||||||
scene::IMesh* mesh = cloneMesh(m_selection_mesh);
|
|
||||||
translateMesh(mesh, m_selection_pos_with_offset);
|
|
||||||
u32 mc = m_selection_mesh->getMeshBufferCount();
|
|
||||||
for (u32 i = 0; i < mc; i++) {
|
|
||||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
|
||||||
driver->drawMeshBuffer(buf);
|
|
||||||
}
|
|
||||||
mesh->drop();
|
|
||||||
driver->setMaterial(oldmaterial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hud::updateSelectionMesh(const v3s16 &camera_offset)
|
|
||||||
{
|
|
||||||
m_camera_offset = camera_offset;
|
|
||||||
if (m_mode != HIGHLIGHT_HALO)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_selection_mesh) {
|
|
||||||
m_selection_mesh->drop();
|
|
||||||
m_selection_mesh = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_selection_boxes.empty()) {
|
|
||||||
// No pointed object
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// New pointed object, create new mesh.
|
|
||||||
|
|
||||||
// Texture UV coordinates for selection boxes
|
|
||||||
static f32 texture_uv[24] = {
|
|
||||||
0,0,1,1,
|
|
||||||
0,0,1,1,
|
|
||||||
0,0,1,1,
|
|
||||||
0,0,1,1,
|
|
||||||
0,0,1,1,
|
|
||||||
0,0,1,1
|
|
||||||
};
|
|
||||||
|
|
||||||
// Use single halo box instead of multiple overlapping boxes.
|
|
||||||
// Temporary solution - problem can be solved with multiple
|
|
||||||
// rendering targets, or some method to remove inner surfaces.
|
|
||||||
// Thats because of halo transparency.
|
|
||||||
|
|
||||||
aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
|
|
||||||
m_halo_boxes.clear();
|
|
||||||
|
|
||||||
for (const auto &selection_box : m_selection_boxes) {
|
|
||||||
halo_box.addInternalBox(selection_box);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_halo_boxes.push_back(halo_box);
|
|
||||||
m_selection_mesh = convertNodeboxesToMesh(
|
|
||||||
m_halo_boxes, texture_uv, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Hud::resizeHotbar() {
|
|
||||||
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
|
|
||||||
|
|
||||||
if (m_screensize != window_size) {
|
|
||||||
m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
|
|
||||||
RenderingEngine::getDisplayDensity() + 0.5);
|
|
||||||
m_hotbar_imagesize *= m_hud_scaling;
|
|
||||||
m_padding = m_hotbar_imagesize / 12;
|
|
||||||
m_screensize = window_size;
|
|
||||||
m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MeshTimeInfo {
|
|
||||||
u64 time;
|
|
||||||
scene::IMesh *mesh;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void drawItemStack(video::IVideoDriver *driver,
|
const struct EnumString es_HudElementStat[] =
|
||||||
gui::IGUIFont *font,
|
|
||||||
const ItemStack &item,
|
|
||||||
const core::rect<s32> &rect,
|
|
||||||
const core::rect<s32> *clip,
|
|
||||||
Client *client,
|
|
||||||
ItemRotationKind rotation_kind)
|
|
||||||
{
|
{
|
||||||
static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
|
{HUD_STAT_POS, "position"},
|
||||||
static thread_local bool enable_animations =
|
{HUD_STAT_POS, "pos"}, /* Deprecated, only for compatibility's sake */
|
||||||
g_settings->getBool("inventory_items_animations");
|
{HUD_STAT_NAME, "name"},
|
||||||
|
{HUD_STAT_SCALE, "scale"},
|
||||||
|
{HUD_STAT_TEXT, "text"},
|
||||||
|
{HUD_STAT_NUMBER, "number"},
|
||||||
|
{HUD_STAT_ITEM, "item"},
|
||||||
|
{HUD_STAT_DIR, "direction"},
|
||||||
|
{HUD_STAT_ALIGN, "alignment"},
|
||||||
|
{HUD_STAT_OFFSET, "offset"},
|
||||||
|
{HUD_STAT_WORLD_POS, "world_pos"},
|
||||||
|
{0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
if (item.empty()) {
|
const struct EnumString es_HudBuiltinElement[] =
|
||||||
if (rotation_kind < IT_ROT_NONE) {
|
{
|
||||||
rotation_time_infos[rotation_kind].mesh = NULL;
|
{HUD_FLAG_HOTBAR_VISIBLE, "hotbar"},
|
||||||
}
|
{HUD_FLAG_HEALTHBAR_VISIBLE, "healthbar"},
|
||||||
return;
|
{HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"},
|
||||||
}
|
{HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"},
|
||||||
|
{HUD_FLAG_BREATHBAR_VISIBLE, "breathbar"},
|
||||||
const ItemDefinition &def = item.getDefinition(client->idef());
|
{HUD_FLAG_MINIMAP_VISIBLE, "minimap"},
|
||||||
ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
|
{0, NULL},
|
||||||
|
};
|
||||||
if (imesh && imesh->mesh) {
|
|
||||||
scene::IMesh *mesh = imesh->mesh;
|
|
||||||
driver->clearZBuffer();
|
|
||||||
s32 delta = 0;
|
|
||||||
if (rotation_kind < IT_ROT_NONE) {
|
|
||||||
MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
|
|
||||||
if (mesh != ti.mesh) {
|
|
||||||
ti.mesh = mesh;
|
|
||||||
ti.time = porting::getTimeMs();
|
|
||||||
} else {
|
|
||||||
delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
core::rect<s32> oldViewPort = driver->getViewPort();
|
|
||||||
core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
|
|
||||||
core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
|
|
||||||
core::matrix4 ProjMatrix;
|
|
||||||
ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
|
|
||||||
driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
|
|
||||||
driver->setTransform(video::ETS_VIEW, ProjMatrix);
|
|
||||||
core::matrix4 matrix;
|
|
||||||
matrix.makeIdentity();
|
|
||||||
|
|
||||||
if (enable_animations) {
|
|
||||||
float timer_f = (float) delta / 5000.0;
|
|
||||||
matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
driver->setTransform(video::ETS_WORLD, matrix);
|
|
||||||
driver->setViewPort(rect);
|
|
||||||
|
|
||||||
video::SColor basecolor =
|
|
||||||
client->idef()->getItemstackColor(item, client);
|
|
||||||
|
|
||||||
u32 mc = mesh->getMeshBufferCount();
|
|
||||||
for (u32 j = 0; j < mc; ++j) {
|
|
||||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
|
||||||
// we can modify vertices relatively fast,
|
|
||||||
// because these meshes are not buffered.
|
|
||||||
assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
|
|
||||||
video::SColor c = basecolor;
|
|
||||||
if (imesh->buffer_colors.size() > j) {
|
|
||||||
ItemPartColor *p = &imesh->buffer_colors[j];
|
|
||||||
if (p->override_base)
|
|
||||||
c = p->color;
|
|
||||||
}
|
|
||||||
if (imesh->needs_shading)
|
|
||||||
colorizeMeshBuffer(buf, &c);
|
|
||||||
else
|
|
||||||
setMeshBufferColor(buf, c);
|
|
||||||
video::SMaterial &material = buf->getMaterial();
|
|
||||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
|
||||||
material.Lighting = false;
|
|
||||||
driver->setMaterial(material);
|
|
||||||
driver->drawMeshBuffer(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
driver->setTransform(video::ETS_VIEW, oldViewMat);
|
|
||||||
driver->setTransform(video::ETS_PROJECTION, oldProjMat);
|
|
||||||
driver->setViewPort(oldViewPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(def.type == ITEM_TOOL && item.wear != 0)
|
|
||||||
{
|
|
||||||
// Draw a progressbar
|
|
||||||
float barheight = rect.getHeight()/16;
|
|
||||||
float barpad_x = rect.getWidth()/16;
|
|
||||||
float barpad_y = rect.getHeight()/16;
|
|
||||||
core::rect<s32> progressrect(
|
|
||||||
rect.UpperLeftCorner.X + barpad_x,
|
|
||||||
rect.LowerRightCorner.Y - barpad_y - barheight,
|
|
||||||
rect.LowerRightCorner.X - barpad_x,
|
|
||||||
rect.LowerRightCorner.Y - barpad_y);
|
|
||||||
|
|
||||||
// Shrink progressrect by amount of tool damage
|
|
||||||
float wear = item.wear / 65535.0;
|
|
||||||
int progressmid =
|
|
||||||
wear * progressrect.UpperLeftCorner.X +
|
|
||||||
(1-wear) * progressrect.LowerRightCorner.X;
|
|
||||||
|
|
||||||
// Compute progressbar color
|
|
||||||
// wear = 0.0: green
|
|
||||||
// wear = 0.5: yellow
|
|
||||||
// wear = 1.0: red
|
|
||||||
video::SColor color(255,255,255,255);
|
|
||||||
int wear_i = MYMIN(floor(wear * 600), 511);
|
|
||||||
wear_i = MYMIN(wear_i + 10, 511);
|
|
||||||
if(wear_i <= 255)
|
|
||||||
color.set(255, wear_i, 255, 0);
|
|
||||||
else
|
|
||||||
color.set(255, 255, 511-wear_i, 0);
|
|
||||||
|
|
||||||
core::rect<s32> progressrect2 = progressrect;
|
|
||||||
progressrect2.LowerRightCorner.X = progressmid;
|
|
||||||
driver->draw2DRectangle(color, progressrect2, clip);
|
|
||||||
|
|
||||||
color = video::SColor(255,0,0,0);
|
|
||||||
progressrect2 = progressrect;
|
|
||||||
progressrect2.UpperLeftCorner.X = progressmid;
|
|
||||||
driver->draw2DRectangle(color, progressrect2, clip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(font != NULL && item.count >= 2)
|
|
||||||
{
|
|
||||||
// Get the item count as a string
|
|
||||||
std::string text = itos(item.count);
|
|
||||||
v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
|
|
||||||
v2s32 sdim(dim.X,dim.Y);
|
|
||||||
|
|
||||||
core::rect<s32> rect2(
|
|
||||||
/*rect.UpperLeftCorner,
|
|
||||||
core::dimension2d<u32>(rect.getWidth(), 15)*/
|
|
||||||
rect.LowerRightCorner - sdim,
|
|
||||||
sdim
|
|
||||||
);
|
|
||||||
|
|
||||||
video::SColor bgcolor(128,0,0,0);
|
|
||||||
driver->draw2DRectangle(bgcolor, rect2, clip);
|
|
||||||
|
|
||||||
video::SColor color(255,255,255,255);
|
|
||||||
font->draw(text.c_str(), rect2, color, false, false, clip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
114
src/hud.h
114
src/hud.h
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
Copyright (C) 2017 red-001 <red-001@outlook.ie>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -17,10 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#ifndef HUD_HEADER
|
||||||
|
#define HUD_HEADER
|
||||||
|
|
||||||
#include "irrlichttypes_extrabloated.h"
|
#include "irrlichttypes_extrabloated.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "common/c_types.h"
|
||||||
|
|
||||||
#define HUD_DIR_LEFT_RIGHT 0
|
#define HUD_DIR_LEFT_RIGHT 0
|
||||||
#define HUD_DIR_RIGHT_LEFT 1
|
#define HUD_DIR_RIGHT_LEFT 1
|
||||||
@ -89,111 +92,8 @@ struct HudElement {
|
|||||||
v2s32 size;
|
v2s32 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef SERVER
|
extern const EnumString es_HudElementType[];
|
||||||
|
extern const EnumString es_HudElementStat[];
|
||||||
#include <vector>
|
extern const EnumString es_HudBuiltinElement[];
|
||||||
#include <IGUIFont.h>
|
|
||||||
#include "irr_aabb3d.h"
|
|
||||||
|
|
||||||
class Client;
|
|
||||||
class ITextureSource;
|
|
||||||
class Inventory;
|
|
||||||
class InventoryList;
|
|
||||||
class LocalPlayer;
|
|
||||||
struct ItemStack;
|
|
||||||
|
|
||||||
class Hud {
|
|
||||||
public:
|
|
||||||
video::IVideoDriver *driver;
|
|
||||||
scene::ISceneManager* smgr;
|
|
||||||
gui::IGUIEnvironment *guienv;
|
|
||||||
Client *client;
|
|
||||||
LocalPlayer *player;
|
|
||||||
Inventory *inventory;
|
|
||||||
ITextureSource *tsrc;
|
|
||||||
|
|
||||||
video::SColor crosshair_argb;
|
|
||||||
video::SColor selectionbox_argb;
|
|
||||||
bool use_crosshair_image = false;
|
|
||||||
std::string hotbar_image = "";
|
|
||||||
bool use_hotbar_image = false;
|
|
||||||
std::string hotbar_selected_image = "";
|
|
||||||
bool use_hotbar_selected_image = false;
|
|
||||||
|
|
||||||
Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
|
|
||||||
Inventory *inventory);
|
|
||||||
~Hud();
|
|
||||||
|
|
||||||
void drawHotbar(u16 playeritem);
|
|
||||||
void resizeHotbar();
|
|
||||||
void drawCrosshair();
|
|
||||||
void drawSelectionMesh();
|
|
||||||
void updateSelectionMesh(const v3s16 &camera_offset);
|
|
||||||
|
|
||||||
std::vector<aabb3f> *getSelectionBoxes()
|
|
||||||
{ return &m_selection_boxes; }
|
|
||||||
|
|
||||||
void setSelectionPos(const v3f &pos, const v3s16 &camera_offset);
|
|
||||||
|
|
||||||
v3f getSelectionPos() const
|
|
||||||
{ return m_selection_pos; }
|
|
||||||
|
|
||||||
void setSelectionMeshColor(const video::SColor &color)
|
|
||||||
{ m_selection_mesh_color = color; }
|
|
||||||
|
|
||||||
void setSelectedFaceNormal(const v3f &face_normal)
|
|
||||||
{ m_selected_face_normal = face_normal; }
|
|
||||||
|
|
||||||
void drawLuaElements(const v3s16 &camera_offset);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
|
|
||||||
s32 count, v2s32 offset, v2s32 size=v2s32());
|
|
||||||
|
|
||||||
void drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
|
|
||||||
s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction);
|
|
||||||
|
|
||||||
void drawItem(const ItemStack &item, const core::rect<s32>& rect,
|
|
||||||
bool selected);
|
|
||||||
|
|
||||||
float m_hud_scaling; // cached minetest setting
|
|
||||||
v3s16 m_camera_offset;
|
|
||||||
v2u32 m_screensize;
|
|
||||||
v2s32 m_displaycenter;
|
|
||||||
s32 m_hotbar_imagesize; // Takes hud_scaling into account, updated by resizeHotbar()
|
|
||||||
s32 m_padding; // Takes hud_scaling into account, updated by resizeHotbar()
|
|
||||||
video::SColor hbar_colors[4];
|
|
||||||
|
|
||||||
std::vector<aabb3f> m_selection_boxes;
|
|
||||||
std::vector<aabb3f> m_halo_boxes;
|
|
||||||
v3f m_selection_pos;
|
|
||||||
v3f m_selection_pos_with_offset;
|
|
||||||
|
|
||||||
scene::IMesh *m_selection_mesh = nullptr;
|
|
||||||
video::SColor m_selection_mesh_color;
|
|
||||||
v3f m_selected_face_normal;
|
|
||||||
|
|
||||||
video::SMaterial m_selection_material;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
HIGHLIGHT_BOX,
|
|
||||||
HIGHLIGHT_HALO,
|
|
||||||
HIGHLIGHT_NONE } m_mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ItemRotationKind {
|
|
||||||
IT_ROT_SELECTED,
|
|
||||||
IT_ROT_HOVERED,
|
|
||||||
IT_ROT_DRAGGED,
|
|
||||||
IT_ROT_NONE, // Must be last, also serves as number
|
|
||||||
};
|
|
||||||
|
|
||||||
void drawItemStack(video::IVideoDriver *driver,
|
|
||||||
gui::IGUIFont *font,
|
|
||||||
const ItemStack &item,
|
|
||||||
const core::rect<s32> &rect,
|
|
||||||
const core::rect<s32> *clip,
|
|
||||||
Client *client,
|
|
||||||
ItemRotationKind rotation_kind);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <vector3d.h>
|
#include <vector3d.h>
|
||||||
|
|
||||||
typedef core::vector3df v3f;
|
typedef core::vector3df v3f;
|
||||||
|
typedef core::vector3d<double> v3d;
|
||||||
typedef core::vector3d<s16> v3s16;
|
typedef core::vector3d<s16> v3s16;
|
||||||
typedef core::vector3d<u16> v3u16;
|
typedef core::vector3d<u16> v3u16;
|
||||||
typedef core::vector3d<s32> v3s32;
|
typedef core::vector3d<s32> v3s32;
|
||||||
|
@ -42,6 +42,60 @@ namespace gui
|
|||||||
//! destructor
|
//! destructor
|
||||||
virtual ~StaticText();
|
virtual ~StaticText();
|
||||||
|
|
||||||
|
static irr::gui::IGUIStaticText *add(
|
||||||
|
irr::gui::IGUIEnvironment *guienv,
|
||||||
|
const EnrichedString &text,
|
||||||
|
const core::rect< s32 > &rectangle,
|
||||||
|
bool border = false,
|
||||||
|
bool wordWrap = true,
|
||||||
|
irr::gui::IGUIElement *parent = NULL,
|
||||||
|
s32 id = -1,
|
||||||
|
bool fillBackground = false)
|
||||||
|
{
|
||||||
|
if (parent == NULL) {
|
||||||
|
// parent is NULL, so we must find one, or we need not to drop
|
||||||
|
// result, but then there will be a memory leak.
|
||||||
|
//
|
||||||
|
// What Irrlicht does is to use guienv as a parent, but the problem
|
||||||
|
// is that guienv is here only an IGUIEnvironment, while it is a
|
||||||
|
// CGUIEnvironment in Irrlicht, which inherits from both IGUIElement
|
||||||
|
// and IGUIEnvironment.
|
||||||
|
//
|
||||||
|
// A solution would be to dynamic_cast guienv to a
|
||||||
|
// IGUIElement*, but Irrlicht is shipped without rtti support
|
||||||
|
// in some distributions, causing the dymanic_cast to segfault.
|
||||||
|
//
|
||||||
|
// Thus, to find the parent, we create a dummy StaticText and ask
|
||||||
|
// for its parent, and then remove it.
|
||||||
|
irr::gui::IGUIStaticText *dummy_text =
|
||||||
|
guienv->addStaticText(L"", rectangle, border, wordWrap,
|
||||||
|
parent, id, fillBackground);
|
||||||
|
parent = dummy_text->getParent();
|
||||||
|
dummy_text->remove();
|
||||||
|
}
|
||||||
|
irr::gui::IGUIStaticText *result = new irr::gui::StaticText(
|
||||||
|
text, border, guienv, parent,
|
||||||
|
id, rectangle, fillBackground);
|
||||||
|
|
||||||
|
result->setWordWrap(wordWrap);
|
||||||
|
result->drop();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irr::gui::IGUIStaticText *add(
|
||||||
|
irr::gui::IGUIEnvironment *guienv,
|
||||||
|
const wchar_t *text,
|
||||||
|
const core::rect< s32 > &rectangle,
|
||||||
|
bool border = false,
|
||||||
|
bool wordWrap = true,
|
||||||
|
irr::gui::IGUIElement *parent = NULL,
|
||||||
|
s32 id = -1,
|
||||||
|
bool fillBackground = false)
|
||||||
|
{
|
||||||
|
return add(guienv, EnrichedString(text), rectangle, border, wordWrap, parent,
|
||||||
|
id, fillBackground);
|
||||||
|
}
|
||||||
|
|
||||||
//! draws the element and its children
|
//! draws the element and its children
|
||||||
virtual void draw();
|
virtual void draw();
|
||||||
|
|
||||||
@ -171,46 +225,6 @@ namespace gui
|
|||||||
|
|
||||||
} // end namespace irr
|
} // end namespace irr
|
||||||
|
|
||||||
inline irr::gui::IGUIStaticText *addStaticText(
|
|
||||||
irr::gui::IGUIEnvironment *guienv,
|
|
||||||
const EnrichedString &text,
|
|
||||||
const core::rect< s32 > &rectangle,
|
|
||||||
bool border = false,
|
|
||||||
bool wordWrap = true,
|
|
||||||
irr::gui::IGUIElement *parent = NULL,
|
|
||||||
s32 id = -1,
|
|
||||||
bool fillBackground = false)
|
|
||||||
{
|
|
||||||
if (parent == NULL) {
|
|
||||||
// parent is NULL, so we must find one, or we need not to drop
|
|
||||||
// result, but then there will be a memory leak.
|
|
||||||
//
|
|
||||||
// What Irrlicht does is to use guienv as a parent, but the problem
|
|
||||||
// is that guienv is here only an IGUIEnvironment, while it is a
|
|
||||||
// CGUIEnvironment in Irrlicht, which inherits from both IGUIElement
|
|
||||||
// and IGUIEnvironment.
|
|
||||||
//
|
|
||||||
// A solution would be to dynamic_cast guienv to a
|
|
||||||
// IGUIElement*, but Irrlicht is shipped without rtti support
|
|
||||||
// in some distributions, causing the dymanic_cast to segfault.
|
|
||||||
//
|
|
||||||
// Thus, to find the parent, we create a dummy StaticText and ask
|
|
||||||
// for its parent, and then remove it.
|
|
||||||
irr::gui::IGUIStaticText *dummy_text =
|
|
||||||
guienv->addStaticText(L"", rectangle, border, wordWrap,
|
|
||||||
parent, id, fillBackground);
|
|
||||||
parent = dummy_text->getParent();
|
|
||||||
dummy_text->remove();
|
|
||||||
}
|
|
||||||
irr::gui::IGUIStaticText *result = new irr::gui::StaticText(
|
|
||||||
text, border, guienv, parent,
|
|
||||||
id, rectangle, fillBackground);
|
|
||||||
|
|
||||||
result->setWordWrap(wordWrap);
|
|
||||||
result->drop();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
|
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
|
||||||
{
|
{
|
||||||
// dynamic_cast not possible due to some distributions shipped
|
// dynamic_cast not possible due to some distributions shipped
|
||||||
@ -225,7 +239,15 @@ inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedS
|
|||||||
|
|
||||||
#else // USE_FREETYPE
|
#else // USE_FREETYPE
|
||||||
|
|
||||||
inline irr::gui::IGUIStaticText *addStaticText(
|
namespace irr
|
||||||
|
{
|
||||||
|
namespace gui
|
||||||
|
{
|
||||||
|
|
||||||
|
class StaticText
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static irr::gui::IGUIStaticText *add(
|
||||||
irr::gui::IGUIEnvironment *guienv,
|
irr::gui::IGUIEnvironment *guienv,
|
||||||
const EnrichedString &text,
|
const EnrichedString &text,
|
||||||
const core::rect< s32 > &rectangle,
|
const core::rect< s32 > &rectangle,
|
||||||
@ -234,9 +256,14 @@ inline irr::gui::IGUIStaticText *addStaticText(
|
|||||||
irr::gui::IGUIElement *parent = NULL,
|
irr::gui::IGUIElement *parent = NULL,
|
||||||
s32 id = -1,
|
s32 id = -1,
|
||||||
bool fillBackground = false)
|
bool fillBackground = false)
|
||||||
{
|
{
|
||||||
return guienv->addStaticText(text.c_str(), rectangle, border, wordWrap, parent, id, fillBackground);
|
return guienv->addStaticText(text.c_str(), rectangle, border, wordWrap, parent, id, fillBackground);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace gui
|
||||||
|
|
||||||
|
} // end namespace irr
|
||||||
|
|
||||||
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
|
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedString &text)
|
||||||
{
|
{
|
||||||
@ -245,18 +272,6 @@ inline void setStaticText(irr::gui::IGUIStaticText *static_text, const EnrichedS
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline irr::gui::IGUIStaticText *addStaticText(
|
|
||||||
irr::gui::IGUIEnvironment *guienv,
|
|
||||||
const wchar_t *text,
|
|
||||||
const core::rect< s32 > &rectangle,
|
|
||||||
bool border = false,
|
|
||||||
bool wordWrap = true,
|
|
||||||
irr::gui::IGUIElement *parent = NULL,
|
|
||||||
s32 id = -1,
|
|
||||||
bool fillBackground = false) {
|
|
||||||
return addStaticText(guienv, EnrichedString(text), rectangle, border, wordWrap, parent, id, fillBackground);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const wchar_t *text)
|
inline void setStaticText(irr::gui::IGUIStaticText *static_text, const wchar_t *text)
|
||||||
{
|
{
|
||||||
setStaticText(static_text, EnrichedString(text));
|
setStaticText(static_text, EnrichedString(text));
|
||||||
|
@ -24,38 +24,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
|
|
||||||
// Length of LIGHT_MAX+1 means LIGHT_MAX is the last value.
|
static u8 light_LUT[LIGHT_SUN + 1];
|
||||||
// LIGHT_SUN is read as LIGHT_MAX from here.
|
|
||||||
|
|
||||||
u8 light_LUT[LIGHT_MAX+1];
|
// The const ref to light_LUT is what is actually used in the code
|
||||||
|
|
||||||
// the const ref to light_LUT is what is actually used in the code.
|
|
||||||
const u8 *light_decode_table = light_LUT;
|
const u8 *light_decode_table = light_LUT;
|
||||||
|
|
||||||
/** Initialize or update the light value tables using the specified \p gamma.
|
// Initialize or update the light value tables using the specified gamma
|
||||||
*/
|
|
||||||
void set_light_table(float gamma)
|
void set_light_table(float gamma)
|
||||||
{
|
{
|
||||||
// lighting curve derivatives
|
// Lighting curve derivatives
|
||||||
const float alpha = g_settings->getFloat("lighting_alpha");
|
const float alpha = g_settings->getFloat("lighting_alpha");
|
||||||
const float beta = g_settings->getFloat("lighting_beta");
|
const float beta = g_settings->getFloat("lighting_beta");
|
||||||
// lighting curve coefficients
|
// Lighting curve coefficients
|
||||||
const float a = alpha + beta - 2;
|
const float a = alpha + beta - 2.0f;
|
||||||
const float b = 3 - 2 * alpha - beta;
|
const float b = 3.0f - 2.0f * alpha - beta;
|
||||||
const float c = alpha;
|
const float c = alpha;
|
||||||
// gamma correction
|
// Mid boost
|
||||||
gamma = rangelim(gamma, 0.5, 3.0);
|
const float d = g_settings->getFloat("lighting_boost");
|
||||||
|
const float e = g_settings->getFloat("lighting_boost_center");
|
||||||
|
const float f = g_settings->getFloat("lighting_boost_spread");
|
||||||
|
// Gamma correction
|
||||||
|
gamma = rangelim(gamma, 0.5f, 3.0f);
|
||||||
|
|
||||||
for (size_t i = 0; i < LIGHT_MAX; i++) {
|
for (size_t i = 0; i < LIGHT_SUN; i++) {
|
||||||
float x = i;
|
float x = i;
|
||||||
x /= LIGHT_MAX;
|
x /= LIGHT_SUN;
|
||||||
float brightness = a * x * x * x + b * x * x + c * x;
|
float brightness = a * x * x * x + b * x * x + c * x;
|
||||||
brightness = powf(brightness, 1.0 / gamma);
|
float boost = d * std::exp(-((x - e) * (x - e)) / (2.0f * f * f));
|
||||||
light_LUT[i] = rangelim((u32)(255 * brightness), 0, 255);
|
brightness = powf(brightness + boost, 1.0f / gamma);
|
||||||
|
light_LUT[i] = rangelim((u32)(255.0f * brightness), 0, 255);
|
||||||
if (i > 1 && light_LUT[i] <= light_LUT[i - 1])
|
if (i > 1 && light_LUT[i] <= light_LUT[i - 1])
|
||||||
light_LUT[i] = light_LUT[i - 1] + 1;
|
light_LUT[i] = light_LUT[i - 1] + 1;
|
||||||
}
|
}
|
||||||
light_LUT[LIGHT_MAX] = 255;
|
light_LUT[LIGHT_SUN] = 255;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
15
src/light.h
15
src/light.h
@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cassert>
|
||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -54,11 +54,12 @@ inline u8 diminish_light(u8 light, u8 distance)
|
|||||||
|
|
||||||
inline u8 undiminish_light(u8 light)
|
inline u8 undiminish_light(u8 light)
|
||||||
{
|
{
|
||||||
|
assert(light <= LIGHT_SUN);
|
||||||
// We don't know if light should undiminish from this particular 0.
|
// We don't know if light should undiminish from this particular 0.
|
||||||
// Thus, keep it at 0.
|
// Thus, keep it at 0.
|
||||||
if (light == 0)
|
if (light == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (light == LIGHT_MAX)
|
if (light >= LIGHT_MAX)
|
||||||
return light;
|
return light;
|
||||||
|
|
||||||
return light + 1;
|
return light + 1;
|
||||||
@ -84,9 +85,9 @@ extern const u8 *light_decode_table;
|
|||||||
// 0 <= return value <= 255
|
// 0 <= return value <= 255
|
||||||
inline u8 decode_light(u8 light)
|
inline u8 decode_light(u8 light)
|
||||||
{
|
{
|
||||||
if (light > LIGHT_MAX)
|
// assert(light <= LIGHT_SUN);
|
||||||
light = LIGHT_MAX;
|
if (light > LIGHT_SUN)
|
||||||
|
light = LIGHT_SUN;
|
||||||
return light_decode_table[light];
|
return light_decode_table[light];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,8 +99,8 @@ inline float decode_light_f(float light_f)
|
|||||||
|
|
||||||
if (i <= 0)
|
if (i <= 0)
|
||||||
return (float)light_decode_table[0] / 255.0;
|
return (float)light_decode_table[0] / 255.0;
|
||||||
if (i >= LIGHT_MAX)
|
if (i >= LIGHT_SUN)
|
||||||
return (float)light_decode_table[LIGHT_MAX] / 255.0;
|
return (float)light_decode_table[LIGHT_SUN] / 255.0;
|
||||||
|
|
||||||
float v1 = (float)light_decode_table[i - 1] / 255.0;
|
float v1 = (float)light_decode_table[i - 1] / 255.0;
|
||||||
float v2 = (float)light_decode_table[i] / 255.0;
|
float v2 = (float)light_decode_table[i] / 255.0;
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
|
#include "settings.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
@ -142,8 +143,8 @@ public:
|
|||||||
|
|
||||||
void setCollisionbox(const aabb3f &box) { m_collisionbox = box; }
|
void setCollisionbox(const aabb3f &box) { m_collisionbox = box; }
|
||||||
|
|
||||||
bool getCanZoom() const { return m_can_zoom; }
|
float getZoomFOV() const { return m_zoom_fov; }
|
||||||
void setCanZoom(bool can_zoom) { m_can_zoom = can_zoom; }
|
void setZoomFOV(float zoom_fov) { m_zoom_fov = zoom_fov; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void accelerateHorizontal(const v3f &target_speed, const f32 max_increase);
|
void accelerateHorizontal(const v3f &target_speed, const f32 max_increase);
|
||||||
@ -181,8 +182,8 @@ private:
|
|||||||
bool camera_barely_in_ceiling = false;
|
bool camera_barely_in_ceiling = false;
|
||||||
aabb3f m_collisionbox = aabb3f(-BS * 0.30f, 0.0f, -BS * 0.30f, BS * 0.30f,
|
aabb3f m_collisionbox = aabb3f(-BS * 0.30f, 0.0f, -BS * 0.30f, BS * 0.30f,
|
||||||
BS * 1.75f, BS * 0.30f);
|
BS * 1.75f, BS * 0.30f);
|
||||||
bool m_can_zoom = true;
|
|
||||||
float m_eye_height = 1.625f;
|
float m_eye_height = 1.625f;
|
||||||
|
float m_zoom_fov = 0.0f;
|
||||||
|
|
||||||
GenericCAO *m_cao = nullptr;
|
GenericCAO *m_cao = nullptr;
|
||||||
Client *m_client;
|
Client *m_client;
|
||||||
|
@ -347,13 +347,10 @@ void StringBuffer::push_back(char c)
|
|||||||
flush(std::string(buffer, buffer_index));
|
flush(std::string(buffer, buffer_index));
|
||||||
buffer_index = 0;
|
buffer_index = 0;
|
||||||
} else {
|
} else {
|
||||||
int index = buffer_index;
|
buffer[buffer_index++] = c;
|
||||||
buffer[index++] = c;
|
if (buffer_index >= BUFFER_LENGTH) {
|
||||||
if (index >= BUFFER_LENGTH) {
|
|
||||||
flush(std::string(buffer, buffer_index));
|
flush(std::string(buffer, buffer_index));
|
||||||
buffer_index = 0;
|
buffer_index = 0;
|
||||||
} else {
|
|
||||||
buffer_index = index;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
40
src/log.h
40
src/log.h
@ -25,6 +25,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#if !defined(_WIN32) // POSIX
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include "settings.h"
|
||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
|
|
||||||
class ILogOutput;
|
class ILogOutput;
|
||||||
@ -106,15 +110,51 @@ public:
|
|||||||
StreamLogOutput(std::ostream &stream) :
|
StreamLogOutput(std::ostream &stream) :
|
||||||
m_stream(stream)
|
m_stream(stream)
|
||||||
{
|
{
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
is_tty = isatty(fileno(stdout));
|
||||||
|
#else
|
||||||
|
is_tty = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void logRaw(LogLevel lev, const std::string &line)
|
void logRaw(LogLevel lev, const std::string &line)
|
||||||
{
|
{
|
||||||
|
static const std::string use_logcolor = g_settings->get("log_color");
|
||||||
|
|
||||||
|
bool colored = use_logcolor == "detect" ? is_tty : use_logcolor == "yes";
|
||||||
|
if (colored)
|
||||||
|
switch (lev) {
|
||||||
|
case LL_ERROR:
|
||||||
|
// error is red
|
||||||
|
m_stream << "\033[91m";
|
||||||
|
break;
|
||||||
|
case LL_WARNING:
|
||||||
|
// warning is yellow
|
||||||
|
m_stream << "\033[93m";
|
||||||
|
break;
|
||||||
|
case LL_INFO:
|
||||||
|
// info is a bit dark
|
||||||
|
m_stream << "\033[37m";
|
||||||
|
break;
|
||||||
|
case LL_VERBOSE:
|
||||||
|
// verbose is darker than info
|
||||||
|
m_stream << "\033[2m";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// action is white
|
||||||
|
colored = false;
|
||||||
|
}
|
||||||
|
|
||||||
m_stream << line << std::endl;
|
m_stream << line << std::endl;
|
||||||
|
|
||||||
|
if (colored)
|
||||||
|
// reset to white color
|
||||||
|
m_stream << "\033[0m";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::ostream &m_stream;
|
std::ostream &m_stream;
|
||||||
|
bool is_tty;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileLogOutput : public ICombinedLogOutput {
|
class FileLogOutput : public ICombinedLogOutput {
|
||||||
|
192
src/mapblock.cpp
192
src/mapblock.cpp
@ -132,198 +132,6 @@ std::string MapBlock::getModifiedReasonString()
|
|||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Propagates sunlight down through the block.
|
|
||||||
Doesn't modify nodes that are not affected by sunlight.
|
|
||||||
|
|
||||||
Returns false if sunlight at bottom block is invalid.
|
|
||||||
Returns true if sunlight at bottom block is valid.
|
|
||||||
Returns true if bottom block doesn't exist.
|
|
||||||
|
|
||||||
If there is a block above, continues from it.
|
|
||||||
If there is no block above, assumes there is sunlight, unless
|
|
||||||
is_underground is set or highest node is water.
|
|
||||||
|
|
||||||
All sunlighted nodes are added to light_sources.
|
|
||||||
|
|
||||||
if remove_light==true, sets non-sunlighted nodes black.
|
|
||||||
|
|
||||||
if black_air_left!=NULL, it is set to true if non-sunlighted
|
|
||||||
air is left in block.
|
|
||||||
*/
|
|
||||||
bool MapBlock::propagateSunlight(std::set<v3s16> & light_sources,
|
|
||||||
bool remove_light, bool *black_air_left)
|
|
||||||
{
|
|
||||||
INodeDefManager *nodemgr = m_gamedef->ndef();
|
|
||||||
|
|
||||||
// Whether the sunlight at the top of the bottom block is valid
|
|
||||||
bool block_below_is_valid = true;
|
|
||||||
|
|
||||||
v3s16 pos_relative = getPosRelative();
|
|
||||||
|
|
||||||
for(s16 x=0; x<MAP_BLOCKSIZE; x++)
|
|
||||||
{
|
|
||||||
for(s16 z=0; z<MAP_BLOCKSIZE; z++)
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
bool no_sunlight = false;
|
|
||||||
//bool no_top_block = false;
|
|
||||||
|
|
||||||
// Check if node above block has sunlight
|
|
||||||
|
|
||||||
bool is_valid_position;
|
|
||||||
MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z),
|
|
||||||
&is_valid_position);
|
|
||||||
if (is_valid_position)
|
|
||||||
{
|
|
||||||
if(n.getContent() == CONTENT_IGNORE)
|
|
||||||
{
|
|
||||||
// Trust heuristics
|
|
||||||
no_sunlight = is_underground;
|
|
||||||
}
|
|
||||||
else if(n.getLight(LIGHTBANK_DAY, m_gamedef->ndef()) != LIGHT_SUN)
|
|
||||||
{
|
|
||||||
no_sunlight = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//no_top_block = true;
|
|
||||||
|
|
||||||
// NOTE: This makes over-ground roofed places sunlighted
|
|
||||||
// Assume sunlight, unless is_underground==true
|
|
||||||
if(is_underground)
|
|
||||||
{
|
|
||||||
no_sunlight = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MapNode n = getNodeNoEx(v3s16(x, MAP_BLOCKSIZE-1, z));
|
|
||||||
if (!m_gamedef->ndef()->get(n).sunlight_propagates) {
|
|
||||||
no_sunlight = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// NOTE: As of now, this just would make everything dark.
|
|
||||||
// No sunlight here
|
|
||||||
//no_sunlight = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if 0 // Doesn't work; nothing gets light.
|
|
||||||
bool no_sunlight = true;
|
|
||||||
bool no_top_block = false;
|
|
||||||
// Check if node above block has sunlight
|
|
||||||
try{
|
|
||||||
MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
|
|
||||||
if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
|
|
||||||
{
|
|
||||||
no_sunlight = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(InvalidPositionException &e)
|
|
||||||
{
|
|
||||||
no_top_block = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*std::cout<<"("<<x<<","<<z<<"): "
|
|
||||||
<<"no_top_block="<<no_top_block
|
|
||||||
<<", is_underground="<<is_underground
|
|
||||||
<<", no_sunlight="<<no_sunlight
|
|
||||||
<<std::endl;*/
|
|
||||||
|
|
||||||
s16 y = MAP_BLOCKSIZE-1;
|
|
||||||
|
|
||||||
// This makes difference to diminishing in water.
|
|
||||||
bool stopped_to_solid_object = false;
|
|
||||||
|
|
||||||
u8 current_light = no_sunlight ? 0 : LIGHT_SUN;
|
|
||||||
|
|
||||||
for(; y >= 0; y--)
|
|
||||||
{
|
|
||||||
v3s16 pos(x, y, z);
|
|
||||||
MapNode &n = getNodeRef(pos);
|
|
||||||
|
|
||||||
if(current_light == 0)
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
else if(current_light == LIGHT_SUN && nodemgr->get(n).sunlight_propagates)
|
|
||||||
{
|
|
||||||
// Do nothing: Sunlight is continued
|
|
||||||
} else if (!nodemgr->get(n).light_propagates) {
|
|
||||||
// A solid object is on the way.
|
|
||||||
stopped_to_solid_object = true;
|
|
||||||
|
|
||||||
// Light stops.
|
|
||||||
current_light = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Diminish light
|
|
||||||
current_light = diminish_light(current_light);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 old_light = n.getLight(LIGHTBANK_DAY, nodemgr);
|
|
||||||
|
|
||||||
if(current_light > old_light || remove_light)
|
|
||||||
{
|
|
||||||
n.setLight(LIGHTBANK_DAY, current_light, nodemgr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(diminish_light(current_light) != 0)
|
|
||||||
{
|
|
||||||
light_sources.insert(pos_relative + pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(current_light == 0 && stopped_to_solid_object)
|
|
||||||
{
|
|
||||||
if(black_air_left)
|
|
||||||
{
|
|
||||||
*black_air_left = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Whether or not the block below should see LIGHT_SUN
|
|
||||||
bool sunlight_should_go_down = (current_light == LIGHT_SUN);
|
|
||||||
|
|
||||||
/*
|
|
||||||
If the block below hasn't already been marked invalid:
|
|
||||||
|
|
||||||
Check if the node below the block has proper sunlight at top.
|
|
||||||
If not, the block below is invalid.
|
|
||||||
|
|
||||||
Ignore non-transparent nodes as they always have no light
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(block_below_is_valid)
|
|
||||||
{
|
|
||||||
MapNode n = getNodeParent(v3s16(x, -1, z), &is_valid_position);
|
|
||||||
if (is_valid_position) {
|
|
||||||
if(nodemgr->get(n).light_propagates)
|
|
||||||
{
|
|
||||||
if(n.getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN
|
|
||||||
&& !sunlight_should_go_down)
|
|
||||||
block_below_is_valid = false;
|
|
||||||
else if(n.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN
|
|
||||||
&& sunlight_should_go_down)
|
|
||||||
block_below_is_valid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*std::cout<<"InvalidBlockException for bottom block node"
|
|
||||||
<<std::endl;*/
|
|
||||||
// Just no block below, no need to panic.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return block_below_is_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MapBlock::copyTo(VoxelManipulator &dst)
|
void MapBlock::copyTo(VoxelManipulator &dst)
|
||||||
{
|
{
|
||||||
v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
|
v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
|
||||||
|
@ -348,10 +348,6 @@ public:
|
|||||||
setNode(x0 + x, y0 + y, z0 + z, node);
|
setNode(x0 + x, y0 + y, z0 + z, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// See comments in mapblock.cpp
|
|
||||||
bool propagateSunlight(std::set<v3s16> &light_sources,
|
|
||||||
bool remove_light=false, bool *black_air_left=NULL);
|
|
||||||
|
|
||||||
// Copies data to VoxelManipulator to getPosRelative()
|
// Copies data to VoxelManipulator to getPosRelative()
|
||||||
void copyTo(VoxelManipulator &dst);
|
void copyTo(VoxelManipulator &dst);
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
|
|||||||
Both light banks
|
Both light banks
|
||||||
*/
|
*/
|
||||||
static u16 getSmoothLightCombined(const v3s16 &p,
|
static u16 getSmoothLightCombined(const v3s16 &p,
|
||||||
const std::array<v3s16,8> &dirs, MeshMakeData *data, bool node_solid)
|
const std::array<v3s16,8> &dirs, MeshMakeData *data)
|
||||||
{
|
{
|
||||||
INodeDefManager *ndef = data->m_client->ndef();
|
INodeDefManager *ndef = data->m_client->ndef();
|
||||||
|
|
||||||
@ -206,8 +206,14 @@ static u16 getSmoothLightCombined(const v3s16 &p,
|
|||||||
u16 light_day = 0;
|
u16 light_day = 0;
|
||||||
u16 light_night = 0;
|
u16 light_night = 0;
|
||||||
|
|
||||||
auto add_node = [&] (int i) -> const ContentFeatures& {
|
auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
|
||||||
|
if (obstructed) {
|
||||||
|
ambient_occlusion++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
|
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
|
||||||
|
if (n.getContent() == CONTENT_IGNORE)
|
||||||
|
return true;
|
||||||
const ContentFeatures &f = ndef->get(n);
|
const ContentFeatures &f = ndef->get(n);
|
||||||
if (f.light_source > light_source_max)
|
if (f.light_source > light_source_max)
|
||||||
light_source_max = f.light_source;
|
light_source_max = f.light_source;
|
||||||
@ -219,37 +225,24 @@ static u16 getSmoothLightCombined(const v3s16 &p,
|
|||||||
} else {
|
} else {
|
||||||
ambient_occlusion++;
|
ambient_occlusion++;
|
||||||
}
|
}
|
||||||
return f;
|
return f.light_propagates;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (node_solid) {
|
std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
|
||||||
ambient_occlusion = 3;
|
add_node(0);
|
||||||
bool corner_obstructed = true;
|
bool opaque1 = !add_node(1);
|
||||||
for (int i = 0; i < 2; ++i) {
|
bool opaque2 = !add_node(2);
|
||||||
if (add_node(i).light_propagates)
|
bool opaque3 = !add_node(3);
|
||||||
corner_obstructed = false;
|
obstructed[0] = opaque1 && opaque2;
|
||||||
}
|
obstructed[1] = opaque1 && opaque3;
|
||||||
add_node(2);
|
obstructed[2] = opaque2 && opaque3;
|
||||||
add_node(3);
|
for (u8 k = 0; k < 3; ++k)
|
||||||
if (corner_obstructed)
|
if (add_node(k + 4, obstructed[k]))
|
||||||
ambient_occlusion++;
|
obstructed[3] = false;
|
||||||
else
|
if (add_node(7, obstructed[3])) { // wrap light around nodes
|
||||||
add_node(4);
|
ambient_occlusion -= 3;
|
||||||
} else {
|
for (u8 k = 0; k < 3; ++k)
|
||||||
std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
|
add_node(k + 4, !obstructed[k]);
|
||||||
add_node(0);
|
|
||||||
bool opaque1 = !add_node(1).light_propagates;
|
|
||||||
bool opaque2 = !add_node(2).light_propagates;
|
|
||||||
bool opaque3 = !add_node(3).light_propagates;
|
|
||||||
obstructed[0] = opaque1 && opaque2;
|
|
||||||
obstructed[1] = opaque1 && opaque3;
|
|
||||||
obstructed[2] = opaque2 && opaque3;
|
|
||||||
for (int k = 0; k < 4; ++k) {
|
|
||||||
if (obstructed[k])
|
|
||||||
ambient_occlusion++;
|
|
||||||
else if (add_node(k + 4).light_propagates)
|
|
||||||
obstructed[3] = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (light_count == 0) {
|
if (light_count == 0) {
|
||||||
@ -277,7 +270,7 @@ static u16 getSmoothLightCombined(const v3s16 &p,
|
|||||||
g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
|
g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
|
||||||
|
|
||||||
// Table of gamma space multiply factors.
|
// Table of gamma space multiply factors.
|
||||||
static const float light_amount[3] = {
|
static thread_local const float light_amount[3] = {
|
||||||
powf(0.75, 1.0 / ao_gamma),
|
powf(0.75, 1.0 / ao_gamma),
|
||||||
powf(0.5, 1.0 / ao_gamma),
|
powf(0.5, 1.0 / ao_gamma),
|
||||||
powf(0.25, 1.0 / ao_gamma)
|
powf(0.25, 1.0 / ao_gamma)
|
||||||
@ -304,43 +297,7 @@ static u16 getSmoothLightCombined(const v3s16 &p,
|
|||||||
*/
|
*/
|
||||||
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
|
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
|
||||||
{
|
{
|
||||||
v3s16 neighbor_offset1, neighbor_offset2;
|
return getSmoothLightTransparent(p + face_dir, corner - 2 * face_dir, data);
|
||||||
|
|
||||||
/*
|
|
||||||
* face_dir, neighbor_offset1 and neighbor_offset2 define an
|
|
||||||
* orthonormal basis which is used to define the offsets of the 8
|
|
||||||
* surrounding nodes and to differentiate the "distance" (by going only
|
|
||||||
* along directly neighboring nodes) relative to the node at p.
|
|
||||||
* Apart from the node at p, only the 4 nodes which contain face_dir
|
|
||||||
* can contribute light.
|
|
||||||
*/
|
|
||||||
if (face_dir.X != 0) {
|
|
||||||
neighbor_offset1 = v3s16(0, corner.Y, 0);
|
|
||||||
neighbor_offset2 = v3s16(0, 0, corner.Z);
|
|
||||||
} else if (face_dir.Y != 0) {
|
|
||||||
neighbor_offset1 = v3s16(0, 0, corner.Z);
|
|
||||||
neighbor_offset2 = v3s16(corner.X, 0, 0);
|
|
||||||
} else if (face_dir.Z != 0) {
|
|
||||||
neighbor_offset1 = v3s16(corner.X,0,0);
|
|
||||||
neighbor_offset2 = v3s16(0,corner.Y,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::array<v3s16,8> dirs = {{
|
|
||||||
// Always shine light
|
|
||||||
neighbor_offset1 + face_dir,
|
|
||||||
neighbor_offset2 + face_dir,
|
|
||||||
v3s16(0,0,0),
|
|
||||||
face_dir,
|
|
||||||
|
|
||||||
// Can be obstructed
|
|
||||||
neighbor_offset1 + neighbor_offset2 + face_dir,
|
|
||||||
|
|
||||||
// Do not shine light, only for ambient occlusion
|
|
||||||
neighbor_offset1,
|
|
||||||
neighbor_offset2,
|
|
||||||
neighbor_offset1 + neighbor_offset2
|
|
||||||
}};
|
|
||||||
return getSmoothLightCombined(p, dirs, data, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -363,7 +320,7 @@ u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData
|
|||||||
v3s16(0,corner.Y,corner.Z),
|
v3s16(0,corner.Y,corner.Z),
|
||||||
v3s16(corner.X,corner.Y,corner.Z)
|
v3s16(corner.X,corner.Y,corner.Z)
|
||||||
}};
|
}};
|
||||||
return getSmoothLightCombined(p, dirs, data, false);
|
return getSmoothLightCombined(p, dirs, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
|
void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2010-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2010-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2013-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -301,10 +301,8 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
|
|||||||
|
|
||||||
|
|
||||||
void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
|
void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
|
||||||
s16 *floors, s16 *ceilings, u16 *num_floors, u16 *num_ceilings)
|
std::vector<s16> &floors, std::vector<s16> &ceilings)
|
||||||
{
|
{
|
||||||
u16 floor_i = 0;
|
|
||||||
u16 ceiling_i = 0;
|
|
||||||
const v3s16 &em = vm->m_area.getExtent();
|
const v3s16 &em = vm->m_area.getExtent();
|
||||||
|
|
||||||
bool is_walkable = false;
|
bool is_walkable = false;
|
||||||
@ -318,19 +316,14 @@ void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
|
|||||||
is_walkable = ndef->get(mn).walkable;
|
is_walkable = ndef->get(mn).walkable;
|
||||||
|
|
||||||
if (is_walkable && !walkable_above) {
|
if (is_walkable && !walkable_above) {
|
||||||
floors[floor_i] = y;
|
floors.push_back(y);
|
||||||
floor_i++;
|
|
||||||
} else if (!is_walkable && walkable_above) {
|
} else if (!is_walkable && walkable_above) {
|
||||||
ceilings[ceiling_i] = y + 1;
|
ceilings.push_back(y + 1);
|
||||||
ceiling_i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->m_area.add_y(em, vi, -1);
|
vm->m_area.add_y(em, vi, -1);
|
||||||
walkable_above = is_walkable;
|
walkable_above = is_walkable;
|
||||||
}
|
}
|
||||||
|
|
||||||
*num_floors = floor_i;
|
|
||||||
*num_ceilings = ceiling_i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2013-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -194,7 +194,7 @@ public:
|
|||||||
s16 findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax);
|
s16 findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax);
|
||||||
void updateHeightmap(v3s16 nmin, v3s16 nmax);
|
void updateHeightmap(v3s16 nmin, v3s16 nmax);
|
||||||
void getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
|
void getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
|
||||||
s16 *floors, s16 *ceilings, u16 *num_floors, u16 *num_ceilings);
|
std::vector<s16> &floors, std::vector<s16> &ceilings);
|
||||||
|
|
||||||
void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax);
|
void updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax);
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2016 paramat, Matt Gregory
|
Copyright (C) 2017-2018 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
|
||||||
Copyright (C) 2010-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2010-2018 paramat
|
||||||
Copyright (C) 2017 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
|
Copyright (C) 2010-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2010-2016 paramat, Matt Gregory
|
Copyright (C) 2017-2018 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
|
||||||
Copyright (C) 2010-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2010-2018 paramat
|
||||||
Copyright (C) 2017 vlapsley, Vaughan Lapsley <vlapsley@gmail.com>
|
Copyright (C) 2010-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2015-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2015-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2015-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
Copyright (C) 2015-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2015-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
Fractal formulas from http://www.bugman123.com/Hypercomplex/index.html
|
Fractal formulas from http://www.bugman123.com/Hypercomplex/index.html
|
||||||
by Paul Nylander, and from http://www.fractalforums.com, thank you.
|
by Paul Nylander, and from http://www.fractalforums.com, thank you.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2013-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2013-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2013-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2013-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
|
Copyright (C) 2013-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2013-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
Copyright (C) 2015-2017 paramat
|
Copyright (C) 2015-2018 paramat
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2014-2017 paramat
|
Copyright (C) 2014-2018 paramat
|
||||||
Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2014-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Minetest
|
Minetest
|
||||||
Copyright (C) 2014-2017 paramat
|
Copyright (C) 2014-2018 paramat
|
||||||
Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
Copyright (C) 2014-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user