pull/49/head
Elias Fleckenstein 2021-05-13 18:06:47 +02:00
commit f3e741dad1
144 changed files with 2058 additions and 5453 deletions

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
./cmake-build-*
./build/*
./cache/*
Dockerfile

View File

@ -70,7 +70,9 @@ Feature requests are welcome but take a moment to see if your idea follows the r
## Translations ## Translations
Translations of Minetest are performed using Weblate. You can access the project page with a list of current languages [here](https://hosted.weblate.org/projects/minetest/minetest/). The core translations of Minetest are performed using Weblate. You can access the project page with a list of current languages [here](https://hosted.weblate.org/projects/minetest/minetest/).
Builtin (the component which contains things like server messages, chat command descriptions, privilege descriptions) is translated separately; it needs to be translated by editing a `.tr` text file. See [Translation](https://dev.minetest.net/Translation) for more information.
## Donations ## Donations

View File

@ -13,6 +13,8 @@ on:
- 'util/buildbot/**' - 'util/buildbot/**'
- 'util/ci/**' - 'util/ci/**'
- '.github/workflows/**.yml' - '.github/workflows/**.yml'
- 'Dockerfile'
- '.dockerignore'
pull_request: pull_request:
paths: paths:
- 'lib/**.[ch]' - 'lib/**.[ch]'
@ -24,6 +26,8 @@ on:
- 'util/buildbot/**' - 'util/buildbot/**'
- 'util/ci/**' - 'util/ci/**'
- '.github/workflows/**.yml' - '.github/workflows/**.yml'
- 'Dockerfile'
- '.dockerignore'
jobs: jobs:
# This is our minor gcc compiler # This is our minor gcc compiler
@ -76,7 +80,7 @@ jobs:
- name: Install deps - name: Install deps
run: | run: |
source ./util/ci/common.sh source ./util/ci/common.sh
install_linux_deps clang-3.9 install_linux_deps clang-3.9 gdb
- name: Build - name: Build
run: | run: |
@ -85,10 +89,14 @@ jobs:
CC: clang-3.9 CC: clang-3.9
CXX: clang++-3.9 CXX: clang++-3.9
- name: Test - name: Unittest
run: | run: |
./bin/minetest --run-unittests ./bin/minetest --run-unittests
- name: Integration test
run: |
./util/test_multiplayer.sh
# This is the current clang version # This is the current clang version
clang_9: clang_9:
runs-on: ubuntu-18.04 runs-on: ubuntu-18.04

View File

@ -9,7 +9,7 @@ stages:
- deploy - deploy
variables: variables:
IRRLICHT_TAG: "1.9.0mt0" IRRLICHT_TAG: "1.9.0mt1"
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git" MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
@ -26,7 +26,7 @@ variables:
- cd .. - cd ..
- mkdir cmakebuild - mkdir cmakebuild
- cd cmakebuild - cd cmakebuild
- cmake -DIRRLICHT_LIBRARY=$PWD/../irrlicht/lib/Linux/libIrrlicht.a -DIRRLICHT_INCLUDE_DIR=$PWD/../irrlicht/include -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE .. - cmake -DIRRLICHT_LIBRARY=$PWD/../irrlicht/lib/Linux/libIrrlichtMt.a -DIRRLICHT_INCLUDE_DIR=$PWD/../irrlicht/include -DCMAKE_INSTALL_PREFIX=../artifact/minetest/usr/ -DCMAKE_BUILD_TYPE=Release -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE -DBUILD_SERVER=TRUE ..
- make -j2 - make -j2
- make install - make install
artifacts: artifacts:
@ -171,10 +171,10 @@ build:fedora-28:
## ##
.generic_win_template: .generic_win_template:
image: ubuntu:bionic image: ubuntu:focal
before_script: before_script:
- apt-get update - apt-get update
- apt-get install -y wget xz-utils unzip git cmake gettext - DEBIAN_FRONTEND=noninteractive apt-get install -y wget xz-utils unzip git cmake gettext
- wget -nv http://minetest.kitsunemimi.pw/mingw-w64-${WIN_ARCH}_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz - wget -nv http://minetest.kitsunemimi.pw/mingw-w64-${WIN_ARCH}_9.2.0_ubuntu18.04.tar.xz -O mingw.tar.xz
- tar -xaf mingw.tar.xz -C /usr - tar -xaf mingw.tar.xz -C /usr
@ -184,13 +184,13 @@ build:fedora-28:
artifacts: artifacts:
expire_in: 1h expire_in: 1h
paths: paths:
- _build/* - build/build/*.zip
.package_win_template: .package_win_template:
extends: .generic_win_template extends: .generic_win_template
stage: package stage: package
script: script:
- unzip _build/minetest-*.zip - unzip build/build/*.zip
- cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libgcc*.dll minetest-*-win*/bin/ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libgcc*.dll minetest-*-win*/bin/
- cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libstdc++*.dll minetest-*-win*/bin/ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libstdc++*.dll minetest-*-win*/bin/
- cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libwinpthread*.dll minetest-*-win*/bin/ - cp -p /usr/${WIN_ARCH}-w64-mingw32/bin/libwinpthread*.dll minetest-*-win*/bin/

View File

@ -20,7 +20,7 @@ read_globals = {
string = {fields = {"split", "trim"}}, string = {fields = {"split", "trim"}},
table = {fields = {"copy", "getn", "indexof", "insert_all", "combine"}}, table = {fields = {"copy", "getn", "indexof", "insert_all", "combine"}},
math = {fields = {"hypot"}}, math = {fields = {"hypot", "round"}},
} }
globals = { globals = {

View File

@ -60,9 +60,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
# This is done here so that relative search paths are more reasonable # This is done here so that relative search paths are more reasonable
find_package(Irrlicht) find_package(Irrlicht)
if(BUILD_CLIENT AND NOT IRRLICHT_FOUND) if(BUILD_CLIENT AND NOT IRRLICHT_FOUND)
message(FATAL_ERROR "Irrlicht is required to build the client, but it was not found.") message(FATAL_ERROR "IrrlichtMt is required to build the client, but it was not found.")
elseif(IRRLICHT_INCLUDE_DIR STREQUAL "") elseif(NOT IRRLICHT_INCLUDE_DIR)
message(FATAL_ERROR "Irrlicht headers are required to build the server, but none found.") message(FATAL_ERROR "Irrlicht or IrrlichtMt headers are required to build the server, but none found.")
endif() endif()
include(CheckSymbolExists) include(CheckSymbolExists)
@ -71,7 +71,7 @@ unset(HAS_FORKED_IRRLICHT CACHE)
check_symbol_exists(IRRLICHT_VERSION_MT "IrrCompileConfig.h" HAS_FORKED_IRRLICHT) check_symbol_exists(IRRLICHT_VERSION_MT "IrrCompileConfig.h" HAS_FORKED_IRRLICHT)
if(NOT HAS_FORKED_IRRLICHT) if(NOT HAS_FORKED_IRRLICHT)
string(CONCAT EXPLANATION_MSG string(CONCAT EXPLANATION_MSG
"Irrlicht found, but it is not Minetest's Irrlicht fork. " "Irrlicht found, but it is not IrrlichtMt (Minetest's Irrlicht fork). "
"The Minetest team has forked Irrlicht to make their own customizations. " "The Minetest team has forked Irrlicht to make their own customizations. "
"It can be found here: https://github.com/minetest/irrlicht") "It can be found here: https://github.com/minetest/irrlicht")
if(BUILD_CLIENT) if(BUILD_CLIENT)

View File

@ -1,6 +1,7 @@
FROM alpine:3.11 FROM alpine:3.13
ENV MINETEST_GAME_VERSION master ENV MINETEST_GAME_VERSION master
ENV IRRLICHT_VERSION master
COPY .git /usr/src/minetest/.git COPY .git /usr/src/minetest/.git
COPY CMakeLists.txt /usr/src/minetest/CMakeLists.txt COPY CMakeLists.txt /usr/src/minetest/CMakeLists.txt
@ -18,9 +19,7 @@ COPY textures /usr/src/minetest/textures
WORKDIR /usr/src/minetest WORKDIR /usr/src/minetest
RUN apk add --no-cache git build-base irrlicht-dev cmake bzip2-dev libpng-dev \ RUN apk add --no-cache git build-base cmake sqlite-dev curl-dev zlib-dev \
jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev \
libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev \
gmp-dev jsoncpp-dev postgresql-dev luajit-dev ca-certificates && \ gmp-dev jsoncpp-dev postgresql-dev luajit-dev ca-certificates && \
git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \ git clone --depth=1 -b ${MINETEST_GAME_VERSION} https://github.com/minetest/minetest_game.git ./games/minetest_game && \
rm -fr ./games/minetest_game/.git rm -fr ./games/minetest_game/.git
@ -36,6 +35,9 @@ RUN git clone --recursive https://github.com/jupp0r/prometheus-cpp/ && \
make -j2 && \ make -j2 && \
make install make install
RUN git clone --depth=1 https://github.com/minetest/irrlicht/ -b ${IRRLICHT_VERSION} && \
cp -r irrlicht/include /usr/include/irrlichtmt
WORKDIR /usr/src/minetest WORKDIR /usr/src/minetest
RUN mkdir build && \ RUN mkdir build && \
cd build && \ cd build && \
@ -49,7 +51,7 @@ RUN mkdir build && \
make -j2 && \ make -j2 && \
make install make install
FROM alpine:3.11 FROM alpine:3.13
RUN apk add --no-cache sqlite-libs curl gmp libstdc++ libgcc libpq luajit jsoncpp && \ RUN apk add --no-cache sqlite-libs curl gmp libstdc++ libgcc libpq luajit jsoncpp && \
adduser -D minetest --uid 30000 -h /var/lib/minetest && \ adduser -D minetest --uid 30000 -h /var/lib/minetest && \

View File

@ -87,7 +87,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Irrlicht Irrlicht
--------------- ---------------
This program uses the Irrlicht Engine. http://irrlicht.sourceforge.net/ This program uses IrrlichtMt, Minetest's fork of
the Irrlicht Engine. http://irrlicht.sourceforge.net/
The Irrlicht Engine License The Irrlicht Engine License

View File

@ -133,8 +133,8 @@ Compiling
| Dependency | Version | Commentary | | Dependency | Version | Commentary |
|------------|---------|------------| |------------|---------|------------|
| GCC | 4.9+ | Can be replaced with Clang 3.4+ | | GCC | 4.9+ | Can be replaced with Clang 3.4+ |
| CMake | 2.6+ | | | CMake | 3.5+ | |
| Irrlicht | - | Custom version required, see https://github.com/minetest/irrlicht | | IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
| SQLite3 | 3.0+ | | | SQLite3 | 3.0+ | |
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present | | LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present | | GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
@ -209,7 +209,7 @@ Run it:
- You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`. - You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`.
- You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`. - You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`.
- Debug build is slower, but gives much more useful output in a debugger. - Debug build is slower, but gives much more useful output in a debugger.
- If you build a bare server you don't need to have the Irrlicht library installed. - If you build a bare server you don't need to have the Irrlicht or IrrlichtMt library installed.
- In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlicht/include`. - In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlicht/include`.
### CMake options ### CMake options
@ -229,7 +229,7 @@ General options and their default values:
ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal) ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal)
ENABLE_FREETYPE=ON - Build with FreeType2; Allows using TTF fonts ENABLE_FREETYPE=ON - Build with FreeType2; Allows using TTF fonts
ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations ENABLE_GETTEXT=ON - Build with Gettext; Allows using translations
ENABLE_GLES=OFF - Build for OpenGL ES instead of OpenGL (requires support by Irrlicht) ENABLE_GLES=OFF - Build for OpenGL ES instead of OpenGL (requires support by IrrlichtMt)
ENABLE_LEVELDB=ON - Build with LevelDB; Enables use of LevelDB map backend ENABLE_LEVELDB=ON - Build with LevelDB; Enables use of LevelDB map backend
ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended) ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended)
ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend
@ -259,9 +259,9 @@ Library specific options:
GETTEXT_INCLUDE_DIR - Only when building with gettext; directory that contains iconv.h GETTEXT_INCLUDE_DIR - Only when building with gettext; directory that contains iconv.h
GETTEXT_LIBRARY - Only when building with gettext on Windows; path to libintl.dll.a GETTEXT_LIBRARY - Only when building with gettext on Windows; path to libintl.dll.a
GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe
IRRLICHT_DLL - Only on Windows; path to Irrlicht.dll IRRLICHT_DLL - Only on Windows; path to IrrlichtMt.dll
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h
IRRLICHT_LIBRARY - Path to libIrrlicht.a/libIrrlicht.so/libIrrlicht.dll.a/Irrlicht.lib IRRLICHT_LIBRARY - Path to libIrrlichtMt.a/libIrrlichtMt.so/libIrrlichtMt.dll.a/IrrlichtMt.lib
LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h
LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll

View File

@ -14,7 +14,7 @@ include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := Irrlicht LOCAL_MODULE := Irrlicht
LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlicht.a LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlichtMt.a
include $(PREBUILT_STATIC_LIBRARY) include $(PREBUILT_STATIC_LIBRARY)
#include $(CLEAR_VARS) #include $(CLEAR_VARS)
@ -47,18 +47,6 @@ LOCAL_MODULE := OpenAL
LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a
include $(PREBUILT_STATIC_LIBRARY) include $(PREBUILT_STATIC_LIBRARY)
# You can use `OpenSSL and Crypto` instead `mbedTLS mbedx509 mbedcrypto`,
#but it increase APK size on ~0.7MB
#include $(CLEAR_VARS)
#LOCAL_MODULE := OpenSSL
#LOCAL_SRC_FILES := deps/Android/OpenSSL/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libssl.a
#include $(PREBUILT_STATIC_LIBRARY)
#include $(CLEAR_VARS)
#LOCAL_MODULE := Crypto
#LOCAL_SRC_FILES := deps/Android/OpenSSL/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcrypto.a
#include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := Vorbis LOCAL_MODULE := Vorbis
LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a
@ -207,7 +195,6 @@ LOCAL_SRC_FILES += \
LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c
LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT android_native_app_glue $(PROFILER_LIBS) #LevelDB LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT android_native_app_glue $(PROFILER_LIBS) #LevelDB
#OpenSSL Crypto
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES

View File

@ -244,6 +244,15 @@ function math.factorial(x)
return v return v
end end
function math.round(x)
if x >= 0 then
return math.floor(x + 0.5)
end
return math.ceil(x - 0.5)
end
function core.formspec_escape(text) function core.formspec_escape(text)
if text ~= nil then if text ~= nil then
text = string.gsub(text,"\\","\\\\") text = string.gsub(text,"\\","\\\\")

View File

@ -48,6 +48,25 @@ describe("vector", function()
assert.same({ x = 41, y = 52, z = 63 }, vector.offset(vector.new(1, 2, 3), 40, 50, 60)) assert.same({ x = 41, y = 52, z = 63 }, vector.offset(vector.new(1, 2, 3), 40, 50, 60))
end) end)
it("to_string()", function()
local v = vector.new(1, 2, 3.14)
assert.same("(1, 2, 3.14)", vector.to_string(v))
end)
it("from_string()", function()
local v = vector.new(1, 2, 3.14)
assert.same({v, 13}, {vector.from_string("(1, 2, 3.14)")})
assert.same({v, 12}, {vector.from_string("(1,2 ,3.14)")})
assert.same({v, 12}, {vector.from_string("(1,2,3.14,)")})
assert.same({v, 11}, {vector.from_string("(1 2 3.14)")})
assert.same({v, 15}, {vector.from_string("( 1, 2, 3.14 )")})
assert.same({v, 15}, {vector.from_string(" ( 1, 2, 3.14) ")})
assert.same({vector.new(), 8}, {vector.from_string("(0,0,0) ( 1, 2, 3.14) ")})
assert.same({v, 22}, {vector.from_string("(0,0,0) ( 1, 2, 3.14) ", 8)})
assert.same({v, 22}, {vector.from_string("(0,0,0) ( 1, 2, 3.14) ", 9)})
assert.same(nil, vector.from_string("nothing"))
end)
-- This function is needed because of floating point imprecision. -- This function is needed because of floating point imprecision.
local function almost_equal(a, b) local function almost_equal(a, b)
if type(a) == "number" then if type(a) == "number" then

View File

@ -12,6 +12,22 @@ function vector.new(a, b, c)
return {x=0, y=0, z=0} return {x=0, y=0, z=0}
end end
function vector.from_string(s, init)
local x, y, z, np = string.match(s, "^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]" ..
"%s*([^%s,]+)%s*[,%s]?%s*%)()", init)
x = tonumber(x)
y = tonumber(y)
z = tonumber(z)
if not (x and y and z) then
return nil
end
return {x = x, y = y, z = z}, np
end
function vector.to_string(v)
return string.format("(%g, %g, %g)", v.x, v.y, v.z)
end
function vector.equals(a, b) function vector.equals(a, b)
return a.x == b.x and return a.x == b.x and
a.y == b.y and a.y == b.y and
@ -41,9 +57,9 @@ end
function vector.round(v) function vector.round(v)
return { return {
x = math.floor(v.x + 0.5), x = math.round(v.x),
y = math.floor(v.y + 0.5), y = math.round(v.y),
z = math.floor(v.z + 0.5) z = math.round(v.z)
} }
end end

View File

@ -75,9 +75,9 @@ core.register_on_chat_message(function(name, message)
local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs) local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs)
if has_privs then if has_privs then
core.set_last_run_mod(cmd_def.mod_origin) core.set_last_run_mod(cmd_def.mod_origin)
local t_before = minetest.get_us_time() local t_before = core.get_us_time()
local success, result = cmd_def.func(name, param) local success, result = cmd_def.func(name, param)
local delay = (minetest.get_us_time() - t_before) / 1000000 local delay = (core.get_us_time() - t_before) / 1000000
if success == false and result == nil then if success == false and result == nil then
core.chat_send_player(name, "-!- "..S("Invalid command usage.")) core.chat_send_player(name, "-!- "..S("Invalid command usage."))
local help_def = core.registered_chatcommands["help"] local help_def = core.registered_chatcommands["help"]
@ -91,11 +91,12 @@ core.register_on_chat_message(function(name, message)
if delay > msg_time_threshold then if delay > msg_time_threshold then
-- Show how much time it took to execute the command -- Show how much time it took to execute the command
if result then if result then
result = result .. result = result .. core.colorize("#f3d2ff", S(" (@1 s)",
minetest.colorize("#f3d2ff", " (%.5g s)"):format(delay) string.format("%.5f", delay)))
else else
result = minetest.colorize("#f3d2ff", result = core.colorize("#f3d2ff", S(
"Command execution took %.5f s"):format(delay) "Command execution took @1 s",
string.format("%.5f", delay)))
end end
end end
if result then if result then
@ -166,6 +167,18 @@ core.register_chatcommand("admin", {
end, end,
}) })
local function privileges_of(name, privs)
if not privs then
privs = core.get_player_privs(name)
end
local privstr = core.privs_to_string(privs, ", ")
if privstr == "" then
return S("@1 does not have any privileges.", name)
else
return S("Privileges of @1: @2", name, privstr)
end
end
core.register_chatcommand("privs", { core.register_chatcommand("privs", {
params = S("[<name>]"), params = S("[<name>]"),
description = S("Show privileges of yourself or another player"), description = S("Show privileges of yourself or another player"),
@ -175,9 +188,7 @@ core.register_chatcommand("privs", {
if not core.player_exists(name) then if not core.player_exists(name) then
return false, S("Player @1 does not exist.", name) return false, S("Player @1 does not exist.", name)
end end
return true, S("Privileges of @1: @2", name, return true, privileges_of(name)
core.privs_to_string(
core.get_player_privs(name), ", "))
end, end,
}) })
@ -226,7 +237,10 @@ local function handle_grant_command(caller, grantname, grantprivstr)
core.string_to_privs(core.settings:get("basic_privs") or "interact,shout") core.string_to_privs(core.settings:get("basic_privs") or "interact,shout")
for priv, _ in pairs(grantprivs) do for priv, _ in pairs(grantprivs) do
if not basic_privs[priv] and not caller_privs.privs then if not basic_privs[priv] and not caller_privs.privs then
return false, S("Your privileges are insufficient.") return false, S("Your privileges are insufficient. "..
"'@1' only allows you to grant: @2",
"basic_privs",
core.privs_to_string(basic_privs, ', '))
end end
if not core.registered_privileges[priv] then if not core.registered_privileges[priv] then
privs_unknown = privs_unknown .. S("Unknown privilege: @1", priv) .. "\n" privs_unknown = privs_unknown .. S("Unknown privilege: @1", priv) .. "\n"
@ -245,15 +259,13 @@ local function handle_grant_command(caller, grantname, grantprivstr)
if grantname ~= caller then if grantname ~= caller then
core.chat_send_player(grantname, core.chat_send_player(grantname,
S("@1 granted you privileges: @2", caller, S("@1 granted you privileges: @2", caller,
core.privs_to_string(grantprivs, ' '))) core.privs_to_string(grantprivs, ', ')))
end end
return true, S("Privileges of @1: @2", grantname, return true, privileges_of(grantname)
core.privs_to_string(
core.get_player_privs(grantname), ' '))
end end
core.register_chatcommand("grant", { core.register_chatcommand("grant", {
params = S("<name> (<privilege> | all)"), params = S("<name> (<privilege> [, <privilege2> [<...>]] | all)"),
description = S("Give privileges to player"), description = S("Give privileges to player"),
func = function(name, param) func = function(name, param)
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)") local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
@ -265,7 +277,7 @@ core.register_chatcommand("grant", {
}) })
core.register_chatcommand("grantme", { core.register_chatcommand("grantme", {
params = S("<privilege> | all"), params = S("<privilege> [, <privilege2> [<...>]] | all"),
description = S("Grant privileges to yourself"), description = S("Grant privileges to yourself"),
func = function(name, param) func = function(name, param)
if param == "" then if param == "" then
@ -285,16 +297,13 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
return false, S("Player @1 does not exist.", revokename) return false, S("Player @1 does not exist.", revokename)
end end
local revokeprivs = core.string_to_privs(revokeprivstr)
local privs = core.get_player_privs(revokename) local privs = core.get_player_privs(revokename)
local basic_privs =
core.string_to_privs(core.settings:get("basic_privs") or "interact,shout")
for priv, _ in pairs(revokeprivs) do
if not basic_privs[priv] and not caller_privs.privs then
return false, S("Your privileges are insufficient.")
end
end
local revokeprivs = core.string_to_privs(revokeprivstr)
local is_singleplayer = core.is_singleplayer()
local is_admin = not is_singleplayer
and revokename == core.settings:get("name")
and revokename ~= ""
if revokeprivstr == "all" then if revokeprivstr == "all" then
revokeprivs = privs revokeprivs = privs
privs = {} privs = {}
@ -304,27 +313,73 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
end end
end end
local privs_unknown = ""
local basic_privs =
core.string_to_privs(core.settings:get("basic_privs") or "interact,shout")
local irrevokable = {}
local has_irrevokable_priv = false
for priv, _ in pairs(revokeprivs) do
if not basic_privs[priv] and not caller_privs.privs then
return false, S("Your privileges are insufficient. "..
"'@1' only allows you to revoke: @2",
"basic_privs",
core.privs_to_string(basic_privs, ', '))
end
local def = core.registered_privileges[priv]
if not def then
privs_unknown = privs_unknown .. S("Unknown privilege: @1", priv) .. "\n"
elseif is_singleplayer and def.give_to_singleplayer then
irrevokable[priv] = true
elseif is_admin and def.give_to_admin then
irrevokable[priv] = true
end
end
for priv, _ in pairs(irrevokable) do
revokeprivs[priv] = nil
has_irrevokable_priv = true
end
if privs_unknown ~= "" then
return false, privs_unknown
end
if has_irrevokable_priv then
if is_singleplayer then
core.chat_send_player(caller,
S("Note: Cannot revoke in singleplayer: @1",
core.privs_to_string(irrevokable, ', ')))
elseif is_admin then
core.chat_send_player(caller,
S("Note: Cannot revoke from admin: @1",
core.privs_to_string(irrevokable, ', ')))
end
end
local revokecount = 0
for priv, _ in pairs(revokeprivs) do for priv, _ in pairs(revokeprivs) do
-- call the on_revoke callbacks -- call the on_revoke callbacks
core.run_priv_callbacks(revokename, priv, caller, "revoke") core.run_priv_callbacks(revokename, priv, caller, "revoke")
revokecount = revokecount + 1
end end
core.set_player_privs(revokename, privs) core.set_player_privs(revokename, privs)
local new_privs = core.get_player_privs(revokename)
if revokecount == 0 then
return false, S("No privileges were revoked.")
end
core.log("action", caller..' revoked (' core.log("action", caller..' revoked ('
..core.privs_to_string(revokeprivs, ', ') ..core.privs_to_string(revokeprivs, ', ')
..') privileges from '..revokename) ..') privileges from '..revokename)
if revokename ~= caller then if revokename ~= caller then
core.chat_send_player(revokename, core.chat_send_player(revokename,
S("@1 revoked privileges from you: @2", caller, S("@1 revoked privileges from you: @2", caller,
core.privs_to_string(revokeprivs, ' '))) core.privs_to_string(revokeprivs, ', ')))
end end
return true, S("Privileges of @1: @2", revokename, return true, privileges_of(revokename, new_privs)
core.privs_to_string(
core.get_player_privs(revokename), ' '))
end end
core.register_chatcommand("revoke", { core.register_chatcommand("revoke", {
params = S("<name> (<privilege> | all)"), params = S("<name> (<privilege> [, <privilege2> [<...>]] | all)"),
description = S("Remove privileges from player"), description = S("Remove privileges from player"),
privs = {}, privs = {},
func = function(name, param) func = function(name, param)
@ -337,7 +392,7 @@ core.register_chatcommand("revoke", {
}) })
core.register_chatcommand("revokeme", { core.register_chatcommand("revokeme", {
params = S("<privilege> | all"), params = S("<privilege> [, <privilege2> [<...>]] | all"),
description = S("Revoke privileges from yourself"), description = S("Revoke privileges from yourself"),
privs = {}, privs = {},
func = function(name, param) func = function(name, param)

View File

@ -84,9 +84,6 @@ core.register_entity(":__builtin:falling_node", {
local textures local textures
if def.tiles and def.tiles[1] then if def.tiles and def.tiles[1] then
local tile = def.tiles[1] local tile = def.tiles[1]
if def.drawtype == "torchlike" and def.paramtype2 ~= "wallmounted" then
tile = def.tiles[2] or def.tiles[1]
end
if type(tile) == "table" then if type(tile) == "table" then
tile = tile.name tile = tile.name
end end
@ -147,11 +144,7 @@ core.register_entity(":__builtin:falling_node", {
-- Rotate entity -- Rotate entity
if def.drawtype == "torchlike" then if def.drawtype == "torchlike" then
if def.paramtype2 == "wallmounted" then self.object:set_yaw(math.pi*0.25)
self.object:set_yaw(math.pi*0.25)
else
self.object:set_yaw(-math.pi*0.25)
end
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh") elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
and (def.wield_image == "" or def.wield_image == nil)) and (def.wield_image == "" or def.wield_image == nil))
or def.drawtype == "signlike" or def.drawtype == "signlike"
@ -165,8 +158,12 @@ core.register_entity(":__builtin:falling_node", {
if euler then if euler then
self.object:set_rotation(euler) self.object:set_rotation(euler)
end end
elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted") then elseif (def.paramtype2 == "wallmounted" or def.paramtype2 == "colorwallmounted" or def.drawtype == "signlike") then
local rot = node.param2 % 8 local rot = node.param2 % 8
if (def.drawtype == "signlike" and def.paramtype2 ~= "wallmounted" and def.paramtype2 ~= "colorwallmounted") then
-- Change rotation to "floor" by default for non-wallmounted paramtype2
rot = 1
end
local pitch, yaw, roll = 0, 0, 0 local pitch, yaw, roll = 0, 0, 0
if def.drawtype == "nodebox" or def.drawtype == "mesh" then if def.drawtype == "nodebox" or def.drawtype == "mesh" then
if rot == 0 then if rot == 0 then
@ -208,6 +205,14 @@ core.register_entity(":__builtin:falling_node", {
end end
end end
self.object:set_rotation({x=pitch, y=yaw, z=roll}) self.object:set_rotation({x=pitch, y=yaw, z=roll})
elseif (def.drawtype == "mesh" and def.paramtype2 == "degrotate") then
local p2 = (node.param2 - (def.place_param2 or 0)) % 240
local yaw = (p2 / 240) * (math.pi * 2)
self.object:set_yaw(yaw)
elseif (def.drawtype == "mesh" and def.paramtype2 == "colordegrotate") then
local p2 = (node.param2 % 32 - (def.place_param2 or 0) % 32) % 24
local yaw = (p2 / 24) * (math.pi * 2)
self.object:set_yaw(yaw)
end end
end end
end, end,
@ -407,7 +412,7 @@ local function convert_to_falling_node(pos, node)
obj:get_luaentity():set_node(node, metatable) obj:get_luaentity():set_node(node, metatable)
core.remove_node(pos) core.remove_node(pos)
return true return true, obj
end end
function core.spawn_falling_node(pos) function core.spawn_falling_node(pos)

View File

@ -19,6 +19,7 @@ core.features = {
object_step_has_moveresult = true, object_step_has_moveresult = true,
direct_velocity_on_players = true, direct_velocity_on_players = true,
use_texture_alpha_string_modes = true, use_texture_alpha_string_modes = true,
degrotate_240_steps = true,
} }
function core.has_feature(arg) function core.has_feature(arg)

View File

@ -135,7 +135,7 @@ end
function core.is_colored_paramtype(ptype) function core.is_colored_paramtype(ptype)
return (ptype == "color") or (ptype == "colorfacedir") or return (ptype == "color") or (ptype == "colorfacedir") or
(ptype == "colorwallmounted") (ptype == "colorwallmounted") or (ptype == "colordegrotate")
end end
function core.strip_param2_color(param2, paramtype2) function core.strip_param2_color(param2, paramtype2)
@ -146,6 +146,8 @@ function core.strip_param2_color(param2, paramtype2)
param2 = math.floor(param2 / 32) * 32 param2 = math.floor(param2 / 32) * 32
elseif paramtype2 == "colorwallmounted" then elseif paramtype2 == "colorwallmounted" then
param2 = math.floor(param2 / 8) * 8 param2 = math.floor(param2 / 8) * 8
elseif paramtype2 == "colordegrotate" then
param2 = math.floor(param2 / 32) * 32
end end
-- paramtype2 == "color" requires no modification. -- paramtype2 == "color" requires no modification.
return param2 return param2
@ -323,6 +325,8 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2,
color_divisor = 8 color_divisor = 8
elseif def.paramtype2 == "colorfacedir" then elseif def.paramtype2 == "colorfacedir" then
color_divisor = 32 color_divisor = 32
elseif def.paramtype2 == "colordegrotate" then
color_divisor = 32
end end
if color_divisor then if color_divisor then
local color = math.floor(metatable.palette_index / color_divisor) local color = math.floor(metatable.palette_index / color_divisor)

View File

@ -32,7 +32,13 @@ end
core.register_privilege("interact", S("Can interact with things and modify the world")) core.register_privilege("interact", S("Can interact with things and modify the world"))
core.register_privilege("shout", S("Can speak in chat")) core.register_privilege("shout", S("Can speak in chat"))
core.register_privilege("basic_privs", S("Can modify 'shout' and 'interact' privileges"))
local basic_privs =
core.string_to_privs((core.settings:get("basic_privs") or "shout,interact"))
local basic_privs_desc = S("Can modify basic privileges (@1)",
core.privs_to_string(basic_privs, ', '))
core.register_privilege("basic_privs", basic_privs_desc)
core.register_privilege("privs", S("Can modify privileges")) core.register_privilege("privs", S("Can modify privileges"))
core.register_privilege("teleport", { core.register_privilege("teleport", {

View File

@ -2,6 +2,8 @@
Empty command.=Leerer Befehl. Empty command.=Leerer Befehl.
Invalid command: @1=Ungültiger Befehl: @1 Invalid command: @1=Ungültiger Befehl: @1
Invalid command usage.=Ungültige Befehlsverwendung. Invalid command usage.=Ungültige Befehlsverwendung.
(@1 s)= (@1 s)
Command execution took @1 s=Befehlsausführung brauchte @1 s
You don't have permission to run this command (missing privileges: @1).=Sie haben keine Erlaubnis, diesen Befehl auszuführen (fehlende Privilegien: @1). You don't have permission to run this command (missing privileges: @1).=Sie haben keine Erlaubnis, diesen Befehl auszuführen (fehlende Privilegien: @1).
Unable to get position of player @1.=Konnte Position vom Spieler @1 nicht ermitteln. Unable to get position of player @1.=Konnte Position vom Spieler @1 nicht ermitteln.
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Ungültiges Gebietsformat. Erwartet: (x1,y1,z1) (x2,y2,z2) Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Ungültiges Gebietsformat. Erwartet: (x1,y1,z1) (x2,y2,z2)
@ -10,24 +12,30 @@ Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pi
Show the name of the server owner=Den Namen des Servereigentümers zeigen Show the name of the server owner=Den Namen des Servereigentümers zeigen
The administrator of this server is @1.=Der Administrator dieses Servers ist @1. The administrator of this server is @1.=Der Administrator dieses Servers ist @1.
There's no administrator named in the config file.=In der Konfigurationsdatei wurde kein Administrator angegeben. There's no administrator named in the config file.=In der Konfigurationsdatei wurde kein Administrator angegeben.
@1 does not have any privileges.=@1 hat keine Privilegien.
Privileges of @1: @2=Privilegien von @1: @2
[<name>]=[<Name>] [<name>]=[<Name>]
Show privileges of yourself or another player=Ihre eigenen Privilegien oder die eines anderen Spielers anzeigen Show privileges of yourself or another player=Ihre eigenen Privilegien oder die eines anderen Spielers anzeigen
Player @1 does not exist.=Spieler @1 existiert nicht. Player @1 does not exist.=Spieler @1 existiert nicht.
Privileges of @1: @2=Privilegien von @1: @2
<privilege>=<Privileg> <privilege>=<Privileg>
Return list of all online players with privilege=Liste aller Spieler mit einem Privileg ausgeben Return list of all online players with privilege=Liste aller Spieler mit einem Privileg ausgeben
Invalid parameters (see /help haspriv).=Ungültige Parameter (siehe „/help haspriv“). Invalid parameters (see /help haspriv).=Ungültige Parameter (siehe „/help haspriv“).
Unknown privilege!=Unbekanntes Privileg! Unknown privilege!=Unbekanntes Privileg!
Players online with the "@1" privilege: @2=Derzeit online spielende Spieler mit dem „@1“-Privileg: @2 Players online with the "@1" privilege: @2=Derzeit online spielende Spieler mit dem „@1“-Privileg: @2
Your privileges are insufficient.=Ihre Privilegien sind unzureichend. Your privileges are insufficient.=Ihre Privilegien sind unzureichend.
Your privileges are insufficient. '@1' only allows you to grant: @2=Ihre Privilegien sind unzureichend. Mit „@1“ können Sie nur folgendes gewähren: @2
Unknown privilege: @1=Unbekanntes Privileg: @1 Unknown privilege: @1=Unbekanntes Privileg: @1
@1 granted you privileges: @2=@1 gewährte Ihnen Privilegien: @2 @1 granted you privileges: @2=@1 gewährte Ihnen Privilegien: @2
<name> (<privilege> | all)=<Name> (<Privileg> | all) <name> (<privilege> [, <privilege2> [<...>]] | all)=<Name> (<Privileg> [, <Privileg2> [<...>]] | all)
Give privileges to player=Privileg an Spieler vergeben Give privileges to player=Privileg an Spieler vergeben
Invalid parameters (see /help grant).=Ungültige Parameter (siehe „/help grant“). Invalid parameters (see /help grant).=Ungültige Parameter (siehe „/help grant“).
<privilege> | all=<Privileg> | all <privilege> [, <privilege2> [<...>]] | all=<Privileg> [, <Privileg2> [<...>]] | all
Grant privileges to yourself=Privilegien an Ihnen selbst vergeben Grant privileges to yourself=Privilegien an Ihnen selbst vergeben
Invalid parameters (see /help grantme).=Ungültige Parameter (siehe „/help grantme“). Invalid parameters (see /help grantme).=Ungültige Parameter (siehe „/help grantme“).
Your privileges are insufficient. '@1' only allows you to revoke: @2=Ihre Privilegien sind unzureichend. Mit „@1“ können Sie nur folgendes entziehen: @2
Note: Cannot revoke in singleplayer: @1=Anmerkung: Im Einzelspielermodus kann man folgendes nicht entziehen: @1
Note: Cannot revoke from admin: @1=Anmerkung: Vom Admin kann man folgendes nicht entziehen: @1
No privileges were revoked.=Es wurden keine Privilegien entzogen.
@1 revoked privileges from you: @2=@1 entfernte Privilegien von Ihnen: @2 @1 revoked privileges from you: @2=@1 entfernte Privilegien von Ihnen: @2
Remove privileges from player=Privilegien von Spieler entfernen Remove privileges from player=Privilegien von Spieler entfernen
Invalid parameters (see /help revoke).=Ungültige Parameter (siehe „/help revoke“). Invalid parameters (see /help revoke).=Ungültige Parameter (siehe „/help revoke“).
@ -156,7 +164,6 @@ Kicked @1.=@1 hinausgeworfen.
Clear all objects in world=Alle Objekte in der Welt löschen Clear all objects in world=Alle Objekte in der Welt löschen
Invalid usage, see /help clearobjects.=Ungültige Verwendung, siehe /help clearobjects. Invalid usage, see /help clearobjects.=Ungültige Verwendung, siehe /help clearobjects.
Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=Lösche alle Objekte. Dies kann eine lange Zeit dauern. Eine Netzwerkzeitüberschreitung könnte für Sie auftreten. (von @1) Clearing all objects. This may take a long time. You may experience a timeout. (by @1)=Lösche alle Objekte. Dies kann eine lange Zeit dauern. Eine Netzwerkzeitüberschreitung könnte für Sie auftreten. (von @1)
Objects cleared.=Objekte gelöscht.
Cleared all objects.=Alle Objekte gelöscht. Cleared all objects.=Alle Objekte gelöscht.
<name> <message>=<Name> <Nachricht> <name> <message>=<Name> <Nachricht>
Send a direct message to a player=Eine Direktnachricht an einen Spieler senden Send a direct message to a player=Eine Direktnachricht an einen Spieler senden
@ -184,7 +191,6 @@ Available commands:=Verfügbare Befehle:
Command not available: @1=Befehl nicht verfügbar: @1 Command not available: @1=Befehl nicht verfügbar: @1
[all | privs | <cmd>]=[all | privs | <Befehl>] [all | privs | <cmd>]=[all | privs | <Befehl>]
Get help for commands or list privileges=Hilfe für Befehle erhalten oder Privilegien auflisten Get help for commands or list privileges=Hilfe für Befehle erhalten oder Privilegien auflisten
Available privileges:=Verfügbare Privilegien:
Command=Befehl Command=Befehl
Parameters=Parameter Parameters=Parameter
For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste. For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste.
@ -194,16 +200,20 @@ Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /h
Close=Schließen Close=Schließen
Privilege=Privileg Privilege=Privileg
Description=Beschreibung Description=Beschreibung
Available privileges:=Verfügbare Privilegien:
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]] print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]]
Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten
Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben. Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben.
Statistics were reset.=Statistiken wurden zurückgesetzt. Statistics were reset.=Statistiken wurden zurückgesetzt.
Usage: @1=Verwendung: @1 Usage: @1=Verwendung: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format kann entweder „txt“, „csv“, „lua“, „json“ oder „json_pretty“ sein (die Struktur kann sich in Zukunft ändern). Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format kann entweder „txt“, „csv“, „lua“, „json“ oder „json_pretty“ sein (die Struktur kann sich in Zukunft ändern).
@1 joined the game.=@1 ist dem Spiel beigetreten.
@1 left the game.=@1 hat das Spiel verlassen.
@1 left the game (timed out).=@1 hat das Spiel verlassen (Netzwerkzeitüberschreitung).
(no description)=(keine Beschreibung) (no description)=(keine Beschreibung)
Can interact with things and modify the world=Kann mit Dingen interagieren und die Welt verändern Can interact with things and modify the world=Kann mit Dingen interagieren und die Welt verändern
Can speak in chat=Kann im Chat sprechen Can speak in chat=Kann im Chat sprechen
Can modify 'shout' and 'interact' privileges=Kann die „shout“- und „interact“-Privilegien anpassen Can modify basic privileges (@1)=Kann grundlegende Privilegien anpassen (@1)
Can modify privileges=Kann Privilegien anpassen Can modify privileges=Kann Privilegien anpassen
Can teleport self=Kann sich selbst teleportieren Can teleport self=Kann sich selbst teleportieren
Can teleport other players=Kann andere Spieler teleportieren Can teleport other players=Kann andere Spieler teleportieren
@ -223,3 +233,8 @@ Unknown Item=Unbekannter Gegenstand
Air=Luft Air=Luft
Ignore=Ignorieren Ignore=Ignorieren
You can't place 'ignore' nodes!=Sie können keine „ignore“-Blöcke platzieren! You can't place 'ignore' nodes!=Sie können keine „ignore“-Blöcke platzieren!
Values below show absolute/relative times spend per server step by the instrumented function.=Die unten angegebenen Werte zeigen absolute/relative Zeitspannen, die je Server-Step von der instrumentierten Funktion in Anspruch genommen wurden.
A total of @1 sample(s) were taken.=Es wurden insgesamt @1 Datenpunkt(e) aufgezeichnet.
The output is limited to '@1'.=Die Ausgabe ist beschränkt auf „@1“.
Saving of profile failed: @1=Speichern des Profils fehlgeschlagen: @1
Profile saved to @1=Profil abgespeichert nach @1

View File

@ -2,6 +2,8 @@
Empty command.=Comando vuoto. Empty command.=Comando vuoto.
Invalid command: @1=Comando non valido: @1 Invalid command: @1=Comando non valido: @1
Invalid command usage.=Utilizzo del comando non valido. Invalid command usage.=Utilizzo del comando non valido.
(@1 s)=
Command execution took @1 s=
You don't have permission to run this command (missing privileges: @1).=Non hai il permesso di eseguire questo comando (privilegi mancanti: @1). You don't have permission to run this command (missing privileges: @1).=Non hai il permesso di eseguire questo comando (privilegi mancanti: @1).
Unable to get position of player @1.=Impossibile ottenere la posizione del giocatore @1. Unable to get position of player @1.=Impossibile ottenere la posizione del giocatore @1.
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Formato dell'area non corretto. Richiesto: (x1,y1,z1) (x2,y2,z2) Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=Formato dell'area non corretto. Richiesto: (x1,y1,z1) (x2,y2,z2)
@ -10,24 +12,30 @@ Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pi
Show the name of the server owner=Mostra il nome del proprietario del server Show the name of the server owner=Mostra il nome del proprietario del server
The administrator of this server is @1.=L'amministratore di questo server è @1. The administrator of this server is @1.=L'amministratore di questo server è @1.
There's no administrator named in the config file.=Non c'è nessun amministratore nel file di configurazione. There's no administrator named in the config file.=Non c'è nessun amministratore nel file di configurazione.
@1 does not have any privileges.=
Privileges of @1: @2=Privilegi di @1: @2
[<name>]=[<nome>] [<name>]=[<nome>]
Show privileges of yourself or another player=Mostra i privilegi propri o di un altro giocatore Show privileges of yourself or another player=Mostra i privilegi propri o di un altro giocatore
Player @1 does not exist.=Il giocatore @1 non esiste. Player @1 does not exist.=Il giocatore @1 non esiste.
Privileges of @1: @2=Privilegi di @1: @2
<privilege>=<privilegio> <privilege>=<privilegio>
Return list of all online players with privilege=Ritorna una lista di tutti i giocatori connessi col tale privilegio Return list of all online players with privilege=Ritorna una lista di tutti i giocatori connessi col tale privilegio
Invalid parameters (see /help haspriv).=Parametri non validi (vedi /help haspriv). Invalid parameters (see /help haspriv).=Parametri non validi (vedi /help haspriv).
Unknown privilege!=Privilegio sconosciuto! Unknown privilege!=Privilegio sconosciuto!
Players online with the "@1" privilege: @2=Giocatori connessi con il privilegio "@1": @2 Players online with the "@1" privilege: @2=Giocatori connessi con il privilegio "@1": @2
Your privileges are insufficient.=I tuoi privilegi sono insufficienti. Your privileges are insufficient.=I tuoi privilegi sono insufficienti.
Your privileges are insufficient. '@1' only allows you to grant: @2=
Unknown privilege: @1=Privilegio sconosciuto: @1 Unknown privilege: @1=Privilegio sconosciuto: @1
@1 granted you privileges: @2=@1 ti ha assegnato i seguenti privilegi: @2 @1 granted you privileges: @2=@1 ti ha assegnato i seguenti privilegi: @2
<name> (<privilege> | all)=<nome> (<privilegio> | all) <name> (<privilege> [, <privilege2> [<...>]] | all)=
Give privileges to player=Dà privilegi al giocatore Give privileges to player=Dà privilegi al giocatore
Invalid parameters (see /help grant).=Parametri non validi (vedi /help grant). Invalid parameters (see /help grant).=Parametri non validi (vedi /help grant).
<privilege> | all=<privilegio> | all <privilege> [, <privilege2> [<...>]] | all=
Grant privileges to yourself=Assegna dei privilegi a te stessǝ Grant privileges to yourself=Assegna dei privilegi a te stessǝ
Invalid parameters (see /help grantme).=Parametri non validi (vedi /help grantme). Invalid parameters (see /help grantme).=Parametri non validi (vedi /help grantme).
Your privileges are insufficient. '@1' only allows you to revoke: @2=
Note: Cannot revoke in singleplayer: @1=
Note: Cannot revoke from admin: @1=
No privileges were revoked.=
@1 revoked privileges from you: @2=@1 ti ha revocato i seguenti privilegi: @2 @1 revoked privileges from you: @2=@1 ti ha revocato i seguenti privilegi: @2
Remove privileges from player=Rimuove privilegi dal giocatore Remove privileges from player=Rimuove privilegi dal giocatore
Invalid parameters (see /help revoke).=Parametri non validi (vedi /help revoke). Invalid parameters (see /help revoke).=Parametri non validi (vedi /help revoke).
@ -183,7 +191,6 @@ Available commands:=Comandi disponibili:
Command not available: @1=Comando non disponibile: @1 Command not available: @1=Comando non disponibile: @1
[all | privs | <cmd>]=[all | privs | <comando>] [all | privs | <cmd>]=[all | privs | <comando>]
Get help for commands or list privileges=Richiama la finestra d'aiuto dei comandi o dei privilegi Get help for commands or list privileges=Richiama la finestra d'aiuto dei comandi o dei privilegi
Available privileges:=Privilegi disponibili:
Command=Comando Command=Comando
Parameters=Parametri Parameters=Parametri
For more information, click on any entry in the list.=Per più informazioni, clicca su una qualsiasi voce dell'elenco. For more information, click on any entry in the list.=Per più informazioni, clicca su una qualsiasi voce dell'elenco.
@ -193,16 +200,20 @@ Available commands: (see also: /help <cmd>)=Comandi disponibili: (vedi anche /he
Close=Chiudi Close=Chiudi
Privilege=Privilegio Privilege=Privilegio
Description=Descrizione Description=Descrizione
Available privileges:=Privilegi disponibili:
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filtro>] | dump [<filtro>] | save [<formato> [<filtro>]] | reset print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filtro>] | dump [<filtro>] | save [<formato> [<filtro>]] | reset
Handle the profiler and profiling data=Gestisce il profiler e i dati da esso elaborati Handle the profiler and profiling data=Gestisce il profiler e i dati da esso elaborati
Statistics written to action log.=Statistiche scritte nel log delle azioni. Statistics written to action log.=Statistiche scritte nel log delle azioni.
Statistics were reset.=Le statistiche sono state resettate. Statistics were reset.=Le statistiche sono state resettate.
Usage: @1=Utilizzo: @1 Usage: @1=Utilizzo: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=I formati supportati sono txt, csv, lua, json e json_pretty (le strutture potrebbero essere soggetti a cambiamenti). Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=I formati supportati sono txt, csv, lua, json e json_pretty (le strutture potrebbero essere soggetti a cambiamenti).
@1 joined the game.=
@1 left the game.=
@1 left the game (timed out).=
(no description)=(nessuna descrizione) (no description)=(nessuna descrizione)
Can interact with things and modify the world=Si può interagire con le cose e modificare il mondo Can interact with things and modify the world=Si può interagire con le cose e modificare il mondo
Can speak in chat=Si può parlare in chat Can speak in chat=Si può parlare in chat
Can modify 'shout' and 'interact' privileges=Si possono modificare i privilegi 'shout' e 'interact' Can modify basic privileges (@1)=
Can modify privileges=Si possono modificare i privilegi Can modify privileges=Si possono modificare i privilegi
Can teleport self=Si può teletrasportare se stessз Can teleport self=Si può teletrasportare se stessз
Can teleport other players=Si possono teletrasportare gli altri giocatori Can teleport other players=Si possono teletrasportare gli altri giocatori
@ -222,3 +233,15 @@ Unknown Item=Oggetto sconosciuto
Air=Aria Air=Aria
Ignore=Ignora Ignore=Ignora
You can't place 'ignore' nodes!=Non puoi piazzare nodi 'ignore'! You can't place 'ignore' nodes!=Non puoi piazzare nodi 'ignore'!
Values below show absolute/relative times spend per server step by the instrumented function.=
A total of @1 sample(s) were taken.=
The output is limited to '@1'.=
Saving of profile failed: @1=
Profile saved to @1=
##### not used anymore #####
<name> (<privilege> | all)=<nome> (<privilegio> | all)
<privilege> | all=<privilegio> | all
Can modify 'shout' and 'interact' privileges=Si possono modificare i privilegi 'shout' e 'interact'

View File

@ -2,6 +2,8 @@
Empty command.= Empty command.=
Invalid command: @1= Invalid command: @1=
Invalid command usage.= Invalid command usage.=
(@1 s)=
Command execution took @1 s=
You don't have permission to run this command (missing privileges: @1).= You don't have permission to run this command (missing privileges: @1).=
Unable to get position of player @1.= Unable to get position of player @1.=
Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)= Incorrect area format. Expected: (x1,y1,z1) (x2,y2,z2)=
@ -10,24 +12,30 @@ Show chat action (e.g., '/me orders a pizza' displays '<player name> orders a pi
Show the name of the server owner= Show the name of the server owner=
The administrator of this server is @1.= The administrator of this server is @1.=
There's no administrator named in the config file.= There's no administrator named in the config file.=
@1 does not have any privileges.=
Privileges of @1: @2=
[<name>]= [<name>]=
Show privileges of yourself or another player= Show privileges of yourself or another player=
Player @1 does not exist.= Player @1 does not exist.=
Privileges of @1: @2=
<privilege>= <privilege>=
Return list of all online players with privilege= Return list of all online players with privilege=
Invalid parameters (see /help haspriv).= Invalid parameters (see /help haspriv).=
Unknown privilege!= Unknown privilege!=
Players online with the "@1" privilege: @2= Players online with the "@1" privilege: @2=
Your privileges are insufficient.= Your privileges are insufficient.=
Your privileges are insufficient. '@1' only allows you to grant: @2=
Unknown privilege: @1= Unknown privilege: @1=
@1 granted you privileges: @2= @1 granted you privileges: @2=
<name> (<privilege> | all)= <name> (<privilege> [, <privilege2> [<...>]] | all)=
Give privileges to player= Give privileges to player=
Invalid parameters (see /help grant).= Invalid parameters (see /help grant).=
<privilege> | all= <privilege> [, <privilege2> [<...>]] | all=
Grant privileges to yourself= Grant privileges to yourself=
Invalid parameters (see /help grantme).= Invalid parameters (see /help grantme).=
Your privileges are insufficient. '@1' only allows you to revoke: @2=
Note: Cannot revoke in singleplayer: @1=
Note: Cannot revoke from admin: @1=
No privileges were revoked.=
@1 revoked privileges from you: @2= @1 revoked privileges from you: @2=
Remove privileges from player= Remove privileges from player=
Invalid parameters (see /help revoke).= Invalid parameters (see /help revoke).=
@ -183,7 +191,6 @@ Available commands:=
Command not available: @1= Command not available: @1=
[all | privs | <cmd>]= [all | privs | <cmd>]=
Get help for commands or list privileges= Get help for commands or list privileges=
Available privileges:=
Command= Command=
Parameters= Parameters=
For more information, click on any entry in the list.= For more information, click on any entry in the list.=
@ -193,16 +200,20 @@ Available commands: (see also: /help <cmd>)=
Close= Close=
Privilege= Privilege=
Description= Description=
Available privileges:=
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset= print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
Handle the profiler and profiling data= Handle the profiler and profiling data=
Statistics written to action log.= Statistics written to action log.=
Statistics were reset.= Statistics were reset.=
Usage: @1= Usage: @1=
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).= Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=
@1 joined the game.=
@1 left the game.=
@1 left the game (timed out).=
(no description)= (no description)=
Can interact with things and modify the world= Can interact with things and modify the world=
Can speak in chat= Can speak in chat=
Can modify 'shout' and 'interact' privileges= Can modify basic privileges (@1)=
Can modify privileges= Can modify privileges=
Can teleport self= Can teleport self=
Can teleport other players= Can teleport other players=
@ -222,3 +233,8 @@ Unknown Item=
Air= Air=
Ignore= Ignore=
You can't place 'ignore' nodes!= You can't place 'ignore' nodes!=
Values below show absolute/relative times spend per server step by the instrumented function.=
A total of @1 sample(s) were taken.=
The output is limited to '@1'.=
Saving of profile failed: @1=
Profile saved to @1=

View File

@ -49,7 +49,7 @@ local tabs = {}
tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua") tabs.settings = dofile(menupath .. DIR_DELIM .. "tab_settings.lua")
tabs.content = dofile(menupath .. DIR_DELIM .. "tab_content.lua") tabs.content = dofile(menupath .. DIR_DELIM .. "tab_content.lua")
tabs.credits = dofile(menupath .. DIR_DELIM .. "tab_credits.lua") tabs.about = dofile(menupath .. DIR_DELIM .. "tab_about.lua")
tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua") tabs.local_game = dofile(menupath .. DIR_DELIM .. "tab_local.lua")
tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua") tabs.play_online = dofile(menupath .. DIR_DELIM .. "tab_online.lua")
@ -98,7 +98,7 @@ local function init_globals()
tv_main:add(tabs.content) tv_main:add(tabs.content)
tv_main:add(tabs.settings) tv_main:add(tabs.settings)
tv_main:add(tabs.credits) tv_main:add(tabs.about)
tv_main:set_global_event_handler(main_event_handler) tv_main:set_global_event_handler(main_event_handler)
tv_main:set_fixed_size(false) tv_main:set_fixed_size(false)

View File

@ -90,8 +90,11 @@ function serverlistmgr.sync()
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local function get_favorites_path() local function get_favorites_path(folder)
local base = core.get_user_path() .. DIR_DELIM .. "client" .. DIR_DELIM .. "serverlist" .. DIR_DELIM local base = core.get_user_path() .. DIR_DELIM .. "client" .. DIR_DELIM .. "serverlist" .. DIR_DELIM
if folder then
return base
end
return base .. core.settings:get("serverlist_file") return base .. core.settings:get("serverlist_file")
end end
@ -103,9 +106,8 @@ local function save_favorites(favorites)
core.settings:set("serverlist_file", filename:sub(1, #filename - 4) .. ".json") core.settings:set("serverlist_file", filename:sub(1, #filename - 4) .. ".json")
end end
local path = get_favorites_path() assert(core.create_dir(get_favorites_path(true)))
core.create_dir(path) core.safe_file_write(get_favorites_path(), core.write_json(favorites))
core.safe_file_write(path, core.write_json(favorites))
end end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -107,8 +107,8 @@ local function buildCreditList(source)
end end
return { return {
name = "credits", name = "about",
caption = fgettext("Credits"), caption = fgettext("About"),
cbf_formspec = function(tabview, name, tabdata) cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png" local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version() local version = core.get_version()
@ -131,11 +131,16 @@ return {
buildCreditList(previous_contributors) .. "," .. buildCreditList(previous_contributors) .. "," ..
";1]" ";1]"
-- Render information
fs = fs .. "label[0.75,4.9;" ..
fgettext("Active renderer:") .. "\n" ..
core.formspec_escape(core.get_screen_info().render_info) .. "]"
if PLATFORM ~= "Android" then if PLATFORM ~= "Android" then
fs = fs .. "tooltip[userdata;" .. fs = fs .. "tooltip[userdata;" ..
fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" .. fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" ..
"and texture packs in a file manager / explorer.") .. "]" "and texture packs in a file manager / explorer.") .. "]"
fs = fs .. "button[0,4.75;3.5,1;userdata;" .. fgettext("Open User Data Directory") .. "]" fs = fs .. "button[0,4;3.5,1;userdata;" .. fgettext("Open User Data Directory") .. "]"
end end
return fs return fs

View File

@ -516,18 +516,17 @@ bilinear_filter (Bilinear filtering) bool false
trilinear_filter (Trilinear filtering) bool false trilinear_filter (Trilinear filtering) bool false
# Filtered textures can blend RGB values with fully-transparent neighbors, # Filtered textures can blend RGB values with fully-transparent neighbors,
# which PNG optimizers usually discard, sometimes resulting in a dark or # which PNG optimizers usually discard, often resulting in dark or
# light edge to transparent textures. Apply this filter to clean that up # light edges to transparent textures. Apply a filter to clean that up
# at texture load time. # at texture load time. This is automatically enabled if mipmapping is enabled.
texture_clean_transparent (Clean transparent textures) bool false texture_clean_transparent (Clean transparent textures) bool false
# When using bilinear/trilinear/anisotropic filters, low-resolution textures # When using bilinear/trilinear/anisotropic filters, low-resolution textures
# can be blurred, so automatically upscale them with nearest-neighbor # can be blurred, so automatically upscale them with nearest-neighbor
# interpolation to preserve crisp pixels. This sets the minimum texture size # interpolation to preserve crisp pixels. This sets the minimum texture size
# for the upscaled textures; higher values look sharper, but require more # for the upscaled textures; higher values look sharper, but require more
# memory. Powers of 2 are recommended. Setting this higher than 1 may not # memory. Powers of 2 are recommended. This setting is ONLY applies if
# have a visible effect unless bilinear/trilinear/anisotropic filtering is # bilinear/trilinear/anisotropic filtering is enabled.
# enabled.
# This is also used as the base node texture size for world-aligned # This is also used as the base node texture size for world-aligned
# texture autoscaling. # texture autoscaling.
texture_min_size (Minimum texture size) int 64 texture_min_size (Minimum texture size) int 64
@ -674,7 +673,7 @@ lighting_boost_spread (Light curve boost spread) float 0.2 0.0 0.4
# 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.
# A restart is required after changing this. # A restart is required after changing this.
# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise. # Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
# On other platforms, OpenGL is recommended. # On other platforms, OpenGL is recommended.
@ -871,7 +870,7 @@ font_path (Regular font path) filepath fonts/Arimo-Regular.ttf
font_path_bold (Bold font path) filepath fonts/Arimo-Bold.ttf font_path_bold (Bold font path) filepath fonts/Arimo-Bold.ttf
font_path_italic (Italic font path) filepath fonts/Arimo-Italic.ttf font_path_italic (Italic font path) filepath fonts/Arimo-Italic.ttf
font_path_bolditalic (Bold and italic font path) filepath fonts/Arimo-BoldItalic.ttf font_path_bold_italic (Bold and italic font path) filepath fonts/Arimo-BoldItalic.ttf
# Font size of the monospace font in point (pt). # Font size of the monospace font in point (pt).
mono_font_size (Monospace font size) int 15 1 mono_font_size (Monospace font size) int 15 1
@ -884,16 +883,7 @@ mono_font_path (Monospace font path) filepath fonts/Cousine-Regular.ttf
mono_font_path_bold (Bold monospace font path) filepath fonts/Cousine-Bold.ttf mono_font_path_bold (Bold monospace font path) filepath fonts/Cousine-Bold.ttf
mono_font_path_italic (Italic monospace font path) filepath fonts/Cousine-Italic.ttf mono_font_path_italic (Italic monospace font path) filepath fonts/Cousine-Italic.ttf
mono_font_path_bolditalic (Bold and italic monospace font path) filepath fonts/Cousine-BoldItalic.ttf mono_font_path_bold_italic (Bold and italic monospace font path) filepath fonts/Cousine-BoldItalic.ttf
# Font size of the fallback font in point (pt).
fallback_font_size (Fallback font size) int 15 1
# Shadow offset (in pixels) of the fallback font. If 0, then shadow will not be drawn.
fallback_font_shadow (Fallback font shadow) int 1
# Opaqueness (alpha) of the shadow behind the fallback font, between 0 and 255.
fallback_font_shadow_alpha (Fallback font shadow alpha) int 128 0 255
# Path of the fallback font. # Path of the fallback font.
# If “freetype” setting is enabled: Must be a TrueType font. # If “freetype” setting is enabled: Must be a TrueType font.
@ -1407,7 +1397,7 @@ 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 ,ar,ca,cs,da,de,dv,el,en,eo,es,et,eu,fil,fr,hu,id,it,ja,ja_KS,jbo,kk,kn,lo,lt,ms,my,nb,nl,nn,pl,pt,pt_BR,ro,ru,sl,sr_Cyrl,sv,sw,th,tr,uk,vi language (Language) enum ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,id,it,ja,jbo,kk,ko,lt,lv,ms,nb,nl,nn,pl,pt,pt_BR,ro,ru,sk,sl,sr_Cyrl,sr_Latn,sv,sw,tr,uk,vi,zh_CN,zh_TW
# Level of logging to be written to debug.txt: # Level of logging to be written to debug.txt:
# - <nothing> (no logging) # - <nothing> (no logging)
@ -1434,9 +1424,8 @@ enable_ipv6 (IPv6) bool true
[*Advanced] [*Advanced]
# Default timeout for cURL, stated in milliseconds. # Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
# Only has an effect if compiled with cURL. curl_timeout (cURL interactive timeout) int 20000
curl_timeout (cURL timeout) int 5000
# Limits number of parallel HTTP requests. Affects: # Limits number of parallel HTTP requests. Affects:
# - Media fetch if server uses remote_media setting. # - Media fetch if server uses remote_media setting.
@ -1445,7 +1434,7 @@ curl_timeout (cURL timeout) int 5000
# Only has an effect if compiled with cURL. # Only has an effect if compiled with cURL.
curl_parallel_limit (cURL parallel limit) int 8 curl_parallel_limit (cURL parallel limit) int 8
# Maximum time in ms a file download (e.g. a mod download) may take. # Maximum time a file download (e.g. a mod download) may take, stated in milliseconds.
curl_file_download_timeout (cURL file download timeout) int 300000 curl_file_download_timeout (cURL file download timeout) int 300000
# Makes DirectX work with LuaJIT. Disable if it causes troubles. # Makes DirectX work with LuaJIT. Disable if it causes troubles.

View File

@ -3,5 +3,9 @@ varying lowp vec4 varColor;
void main(void) void main(void)
{ {
gl_Position = mWorldViewProj * inVertexPosition; gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -7,5 +7,9 @@ void main(void)
{ {
varTexCoord = inTexCoord0.st; varTexCoord = inTexCoord0.st;
gl_Position = mWorldViewProj * inVertexPosition; gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -146,10 +146,14 @@ void main(void)
// the brightness, so now we have to multiply these // the brightness, so now we have to multiply these
// colors with the color of the incoming light. // colors with the color of the incoming light.
// The pre-baked colors are halved to prevent overflow. // The pre-baked colors are halved to prevent overflow.
vec4 color; #ifdef GL_ES
vec4 color = inVertexColor.bgra;
#else
vec4 color = inVertexColor;
#endif
// The alpha gives the ratio of sunlight in the incoming light. // The alpha gives the ratio of sunlight in the incoming light.
float nightRatio = 1.0 - inVertexColor.a; float nightRatio = 1.0 - color.a;
color.rgb = inVertexColor.rgb * (inVertexColor.a * dayLight.rgb + color.rgb = color.rgb * (color.a * dayLight.rgb +
nightRatio * artificialLight.rgb) * 2.0; nightRatio * artificialLight.rgb) * 2.0;
color.a = 1.0; color.a = 1.0;

View File

@ -49,5 +49,9 @@ void main(void)
: directional_ambient(normalize(inVertexNormal)); : directional_ambient(normalize(inVertexNormal));
#endif #endif
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -6,5 +6,9 @@ void main(void)
varTexCoord = inTexCoord0.st; varTexCoord = inTexCoord0.st;
gl_Position = mWorldViewProj * inVertexPosition; gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
varColor = inVertexColor; varColor = inVertexColor;
#endif
} }

View File

@ -1,36 +1,57 @@
mark_as_advanced(IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR IRRLICHT_DLL) mark_as_advanced(IRRLICHT_DLL)
# Find include directory and libraries # Find include directory and libraries
if(TRUE) # find our fork first, then upstream (TODO: remove this?)
foreach(libname IN ITEMS IrrlichtMt Irrlicht)
string(TOLOWER "${libname}" libname2)
find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
DOC "Path to the directory with Irrlicht includes" DOC "Path to the directory with IrrlichtMt includes"
PATHS PATHS
/usr/local/include/irrlicht /usr/local/include/${libname2}
/usr/include/irrlicht /usr/include/${libname2}
/system/develop/headers/irrlicht #Haiku /system/develop/headers/${libname2} #Haiku
PATH_SUFFIXES "include/irrlicht" PATH_SUFFIXES "include/${libname2}"
) )
find_library(IRRLICHT_LIBRARY NAMES libIrrlicht Irrlicht find_library(IRRLICHT_LIBRARY NAMES lib${libname} ${libname}
DOC "Path to the Irrlicht library file" DOC "Path to the IrrlichtMt library file"
PATHS PATHS
/usr/local/lib /usr/local/lib
/usr/lib /usr/lib
/system/develop/lib # Haiku /system/develop/lib # Haiku
) )
endif()
# Users will likely need to edit these if(IRRLICHT_INCLUDE_DIR OR IRRLICHT_LIBRARY)
mark_as_advanced(CLEAR IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR) break()
endif()
endforeach()
# Handholding for users
if(IRRLICHT_INCLUDE_DIR AND (NOT IS_DIRECTORY "${IRRLICHT_INCLUDE_DIR}" OR
NOT EXISTS "${IRRLICHT_INCLUDE_DIR}/irrlicht.h"))
message(WARNING "IRRLICHT_INCLUDE_DIR was set to ${IRRLICHT_INCLUDE_DIR} "
"but irrlicht.h does not exist inside. The path will not be used.")
unset(IRRLICHT_INCLUDE_DIR CACHE)
endif()
if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR APPLE)
# (only on systems where we're sure how a valid library looks like)
if(IRRLICHT_LIBRARY AND (IS_DIRECTORY "${IRRLICHT_LIBRARY}" OR
NOT IRRLICHT_LIBRARY MATCHES "\\.(a|so|dylib|lib)([.0-9]+)?$"))
message(WARNING "IRRLICHT_LIBRARY was set to ${IRRLICHT_LIBRARY} "
"but is not a valid library file. The path will not be used.")
unset(IRRLICHT_LIBRARY CACHE)
endif()
endif()
# On Windows, find the DLL for installation # On Windows, find the DLL for installation
if(WIN32) if(WIN32)
# If VCPKG_APPLOCAL_DEPS is ON, dll's are automatically handled by VCPKG # If VCPKG_APPLOCAL_DEPS is ON, dll's are automatically handled by VCPKG
if(NOT VCPKG_APPLOCAL_DEPS) if(NOT VCPKG_APPLOCAL_DEPS)
find_file(IRRLICHT_DLL NAMES Irrlicht.dll find_file(IRRLICHT_DLL NAMES IrrlichtMt.dll
DOC "Path of the Irrlicht dll (for installation)" DOC "Path of the IrrlichtMt dll (for installation)"
) )
endif() endif()
endif(WIN32) endif(WIN32)

View File

@ -42,7 +42,7 @@ else()
) )
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OPENGLES2 DEFAULT_MSG OPENGLES2_LIBRARY OPENGLES2_INCLUDE_DIR) find_package_handle_standard_args(OpenGLES2 DEFAULT_MSG OPENGLES2_LIBRARY OPENGLES2_INCLUDE_DIR)
find_path(EGL_INCLUDE_DIR EGL/egl.h find_path(EGL_INCLUDE_DIR EGL/egl.h
PATHS /usr/openwin/share/include PATHS /usr/openwin/share/include
@ -59,7 +59,6 @@ else()
/usr/lib /usr/lib
) )
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR) find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR)
endif() endif()

View File

@ -658,6 +658,9 @@ Minetest namespace reference
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data * `minetest.sha1(data, [raw])`: returns the sha1 hash of data
* `data`: string of data to hash * `data`: string of data to hash
* `raw`: return raw bytes instead of hex digits, default: false * `raw`: return raw bytes instead of hex digits, default: false
* `minetest.colorspec_to_colorstring(colorspec)`: Converts a ColorSpec to a
ColorString. If the ColorSpec is invalid, returns `nil`.
* `colorspec`: The ColorSpec to convert
* `minetest.get_csm_restrictions()`: returns a table of `Flags` indicating the * `minetest.get_csm_restrictions()`: returns a table of `Flags` indicating the
restrictions applied to the current mod. restrictions applied to the current mod.
* If a flag in this table is set to true, the feature is RESTRICTED. * If a flag in this table is set to true, the feature is RESTRICTED.
@ -1698,9 +1701,8 @@ The following functions provide escape sequences:
Named colors are also supported and are equivalent to Named colors are also supported and are equivalent to
[CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors). [CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors).
To specify the value of the alpha channel, append `#AA` to the end of the color name To specify the value of the alpha channel, append `#A` or `#AA` to the end of
(e.g. `colorname#08`). For named colors the hexadecimal string representing the alpha the color name (e.g. `colorname#08`).
value must (always) be two hexadecimal digits.
`Color` `Color`
------------- -------------

View File

@ -1048,9 +1048,9 @@ The function of `param2` is determined by `paramtype2` in node definition.
* The height of the 'plantlike' section is stored in `param2`. * The height of the 'plantlike' section is stored in `param2`.
* The height is (`param2` / 16) nodes. * The height is (`param2` / 16) nodes.
* `paramtype2 = "degrotate"` * `paramtype2 = "degrotate"`
* Only valid for "plantlike" drawtype. The rotation of the node is stored in * Valid for `plantlike` and `mesh` drawtypes. The rotation of the node is
`param2`. stored in `param2`.
* Values range 0 - 179. The value stored in `param2` is multiplied by two to * Values range 0239. The value stored in `param2` is multiplied by 1.5 to
get the actual rotation in degrees of the node. get the actual rotation in degrees of the node.
* `paramtype2 = "meshoptions"` * `paramtype2 = "meshoptions"`
* Only valid for "plantlike" drawtype. `param2` encodes the shape and * Only valid for "plantlike" drawtype. `param2` encodes the shape and
@ -1088,6 +1088,11 @@ The function of `param2` is determined by `paramtype2` in node definition.
* `param2` values 0-63 define 64 levels of internal liquid, 0 being empty * `param2` values 0-63 define 64 levels of internal liquid, 0 being empty
and 63 being full. and 63 being full.
* Liquid texture is defined using `special_tiles = {"modname_tilename.png"}` * Liquid texture is defined using `special_tiles = {"modname_tilename.png"}`
* `paramtype2 = "colordegrotate"`
* Same as `degrotate`, but with colors.
* The first (most-significant) three bits of `param2` tells which color
is picked from the palette. The palette should have 8 pixels.
* Remaining 5 bits store rotation in range 023 (i.e. in 15° steps)
* `paramtype2 = "none"` * `paramtype2 = "none"`
* `param2` will not be used by the engine and can be used to store * `param2` will not be used by the engine and can be used to store
an arbitrary value an arbitrary value
@ -1107,8 +1112,20 @@ Look for examples in `games/devtest` or `games/minetest_game`.
* Invisible, uses no texture. * Invisible, uses no texture.
* `liquid` * `liquid`
* The cubic source node for a liquid. * The cubic source node for a liquid.
* Faces bordering to the same node are never rendered.
* Connects to node specified in `liquid_alternative_flowing`.
* Use `backface_culling = false` for the tiles you want to make
visible when inside the node.
* `flowingliquid` * `flowingliquid`
* The flowing version of a liquid, appears with various heights and slopes. * The flowing version of a liquid, appears with various heights and slopes.
* Faces bordering to the same node are never rendered.
* Connects to node specified in `liquid_alternative_source`.
* Node textures are defined with `special_tiles` where the first tile
is for the top and bottom faces and the second tile is for the side
faces.
* `tiles` is used for the item/inventory/wield image rendering.
* Use `backface_culling = false` for the special tiles you want to make
visible when inside the node
* `glasslike` * `glasslike`
* Often used for partially-transparent nodes. * Often used for partially-transparent nodes.
* Only external sides of textures are visible. * Only external sides of textures are visible.
@ -1135,14 +1152,20 @@ Look for examples in `games/devtest` or `games/minetest_game`.
used to compensate for how `glasslike` reduces visual thickness. used to compensate for how `glasslike` reduces visual thickness.
* `torchlike` * `torchlike`
* A single vertical texture. * A single vertical texture.
* If placed on top of a node, uses the first texture specified in `tiles`. * If `paramtype2="[color]wallmounted":
* If placed against the underside of a node, uses the second texture * If placed on top of a node, uses the first texture specified in `tiles`.
specified in `tiles`. * If placed against the underside of a node, uses the second texture
* If placed on the side of a node, uses the third texture specified in specified in `tiles`.
`tiles` and is perpendicular to that node. * If placed on the side of a node, uses the third texture specified in
`tiles` and is perpendicular to that node.
* If `paramtype2="none"`:
* Will be rendered as if placed on top of a node (see
above) and only the first texture is used.
* `signlike` * `signlike`
* A single texture parallel to, and mounted against, the top, underside or * A single texture parallel to, and mounted against, the top, underside or
side of a node. side of a node.
* If `paramtype2="[color]wallmounted", it rotates according to `param2`
* If `paramtype2="none"`, it will always be on the floor.
* `plantlike` * `plantlike`
* Two vertical and diagonal textures at right-angles to each other. * Two vertical and diagonal textures at right-angles to each other.
* See `paramtype2 = "meshoptions"` above for other options. * See `paramtype2 = "meshoptions"` above for other options.
@ -1725,7 +1748,15 @@ to games.
* `3`: the node always gets the digging time 0 seconds (torch) * `3`: the node always gets the digging time 0 seconds (torch)
* `disable_jump`: Player (and possibly other things) cannot jump from node * `disable_jump`: Player (and possibly other things) cannot jump from node
or if their feet are in the node. Note: not supported for `new_move = false` or if their feet are in the node. Note: not supported for `new_move = false`
* `fall_damage_add_percent`: damage speed = `speed * (1 + value/100)` * `fall_damage_add_percent`: modifies the fall damage suffered when hitting
the top of this node. There's also an armor group with the same name.
The final player damage is determined by the following formula:
damage =
collision speed
* ((node_fall_damage_add_percent + 100) / 100) -- node group
* ((player_fall_damage_add_percent + 100) / 100) -- player armor group
- (14) -- constant tolerance
Negative damage values are discarded as no damage.
* `falling_node`: if there is no walkable block under the node it will fall * `falling_node`: if there is no walkable block under the node it will fall
* `float`: the node will not fall through liquids * `float`: the node will not fall through liquids
* `level`: Can be used to give an additional sense of progression in the game. * `level`: Can be used to give an additional sense of progression in the game.
@ -1745,12 +1776,15 @@ to games.
`"toolrepair"` crafting recipe `"toolrepair"` crafting recipe
### `ObjectRef` groups ### `ObjectRef` armor groups
* `immortal`: Skips all damage and breath handling for an object. This group * `immortal`: Skips all damage and breath handling for an object. This group
will also hide the integrated HUD status bars for players. It is will also hide the integrated HUD status bars for players. It is
automatically set to all players when damage is disabled on the server and automatically set to all players when damage is disabled on the server and
cannot be reset (subject to change). cannot be reset (subject to change).
* `fall_damage_add_percent`: Modifies the fall damage suffered by players
when they hit the ground. It is analog to the node group with the same
name. See the node group above for the exact calculation.
* `punch_operable`: For entities; disables the regular damage mechanism for * `punch_operable`: For entities; disables the regular damage mechanism for
players punching it by hand or a non-tool item, so that it can do something players punching it by hand or a non-tool item, so that it can do something
else than take damage. else than take damage.
@ -3078,9 +3112,8 @@ Colors
Named colors are also supported and are equivalent to Named colors are also supported and are equivalent to
[CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors). [CSS Color Module Level 4](http://dev.w3.org/csswg/css-color/#named-colors).
To specify the value of the alpha channel, append `#AA` to the end of the color To specify the value of the alpha channel, append `#A` or `#AA` to the end of
name (e.g. `colorname#08`). For named colors the hexadecimal string the color name (e.g. `colorname#08`).
representing the alpha value must (always) be two hexadecimal digits.
`ColorSpec` `ColorSpec`
----------- -----------
@ -3146,6 +3179,16 @@ For the following functions, `v`, `v1`, `v2` are vectors,
* Returns a vector. * Returns a vector.
* A copy of `a` if `a` is a vector. * A copy of `a` if `a` is a vector.
* `{x = a, y = b, z = c}`, if all of `a`, `b`, `c` are defined numbers. * `{x = a, y = b, z = c}`, if all of `a`, `b`, `c` are defined numbers.
* `vector.from_string(s[, init])`:
* Returns `v, np`, where `v` is a vector read from the given string `s` and
`np` is the next position in the string after the vector.
* Returns `nil` on failure.
* `s`: Has to begin with a substring of the form `"(x, y, z)"`. Additional
spaces, leaving away commas and adding an additional comma to the end
is allowed.
* `init`: If given starts looking for the vector at this string index.
* `vector.to_string(v)`:
* Returns a string of the form `"(x, y, z)"`.
* `vector.direction(p1, p2)`: * `vector.direction(p1, p2)`:
* Returns a vector of length 1 with direction `p1` to `p2`. * Returns a vector of length 1 with direction `p1` to `p2`.
* If `p1` and `p2` are identical, returns `{x = 0, y = 0, z = 0}`. * If `p1` and `p2` are identical, returns `{x = 0, y = 0, z = 0}`.
@ -3160,6 +3203,7 @@ For the following functions, `v`, `v1`, `v2` are vectors,
* Returns a vector, each dimension rounded down. * Returns a vector, each dimension rounded down.
* `vector.round(v)`: * `vector.round(v)`:
* Returns a vector, each dimension rounded to nearest integer. * Returns a vector, each dimension rounded to nearest integer.
* At a multiple of 0.5, rounds away from zero.
* `vector.apply(v, func)`: * `vector.apply(v, func)`:
* Returns a vector where the function `func` has been applied to each * Returns a vector where the function `func` has been applied to each
component. component.
@ -3234,6 +3278,8 @@ Helper functions
* If the absolute value of `x` is within the `tolerance` or `x` is NaN, * If the absolute value of `x` is within the `tolerance` or `x` is NaN,
`0` is returned. `0` is returned.
* `math.factorial(x)`: returns the factorial of `x` * `math.factorial(x)`: returns the factorial of `x`
* `math.round(x)`: Returns `x` rounded to the nearest integer.
* At a multiple of 0.5, rounds away from zero.
* `string.split(str, separator, include_empty, max_splits, sep_is_pattern)` * `string.split(str, separator, include_empty, max_splits, sep_is_pattern)`
* `separator`: string, default: `","` * `separator`: string, default: `","`
* `include_empty`: boolean, default: `false` * `include_empty`: boolean, default: `false`
@ -4394,6 +4440,9 @@ Utilities
direct_velocity_on_players = true, direct_velocity_on_players = true,
-- nodedef's use_texture_alpha accepts new string modes (5.4.0) -- nodedef's use_texture_alpha accepts new string modes (5.4.0)
use_texture_alpha_string_modes = true, use_texture_alpha_string_modes = true,
-- degrotate param2 rotates in units of 1.5° instead of 2°
-- thus changing the range of values from 0-179 to 0-240 (5.5.0)
degrotate_240_steps = true,
} }
* `minetest.has_feature(arg)`: returns `boolean, missing_features` * `minetest.has_feature(arg)`: returns `boolean, missing_features`
@ -4453,6 +4502,9 @@ Utilities
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data * `minetest.sha1(data, [raw])`: returns the sha1 hash of data
* `data`: string of data to hash * `data`: string of data to hash
* `raw`: return raw bytes instead of hex digits, default: false * `raw`: return raw bytes instead of hex digits, default: false
* `minetest.colorspec_to_colorstring(colorspec)`: Converts a ColorSpec to a
ColorString. If the ColorSpec is invalid, returns `nil`.
* `colorspec`: The ColorSpec to convert
Logging Logging
------- -------
@ -4656,6 +4708,7 @@ Call these functions only at load time!
* `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of: * `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of:
* `moved_too_fast` * `moved_too_fast`
* `interacted_too_far` * `interacted_too_far`
* `interacted_with_self`
* `interacted_while_dead` * `interacted_while_dead`
* `finished_unknown_dig` * `finished_unknown_dig`
* `dug_unbreakable` * `dug_unbreakable`
@ -4896,7 +4949,7 @@ Environment access
* Punch node with the same effects that a player would cause * Punch node with the same effects that a player would cause
* `minetest.spawn_falling_node(pos)` * `minetest.spawn_falling_node(pos)`
* Change node into falling node * Change node into falling node
* Returns `true` if successful, `false` on failure * Returns `true` and the ObjectRef of the spawned entity if successful, `false` on failure
* `minetest.find_nodes_with_meta(pos1, pos2)` * `minetest.find_nodes_with_meta(pos1, pos2)`
* Get a table of positions of nodes that have metadata within a region * Get a table of positions of nodes that have metadata within a region
@ -7414,7 +7467,16 @@ Used by `minetest.register_node`.
-- If true, liquids flow into and replace this node. -- If true, liquids flow into and replace this node.
-- Warning: making a liquid node 'floodable' will cause problems. -- Warning: making a liquid node 'floodable' will cause problems.
liquidtype = "none", -- "none" / "source" / "flowing" liquidtype = "none", -- specifies liquid physics
-- * "none": no liquid physics
-- * "source": spawns flowing liquid nodes at all 4 sides and below;
-- recommended drawtype: "liquid".
-- * "flowing": spawned from source, spawns more flowing liquid nodes
-- around it until `liquid_range` is reached;
-- will drain out without a source;
-- recommended drawtype: "flowingliquid".
-- If it's "source" or "flowing" and `liquid_range > 0`, then
-- both `liquid_alternative_*` fields must be specified
liquid_alternative_flowing = "", -- Flowing version of source liquid liquid_alternative_flowing = "", -- Flowing version of source liquid
@ -7437,7 +7499,10 @@ Used by `minetest.register_node`.
-- `minetest.set_node_level` and `minetest.add_node_level`. -- `minetest.set_node_level` and `minetest.add_node_level`.
-- Values above 124 might causes collision detection issues. -- Values above 124 might causes collision detection issues.
liquid_range = 8, -- Number of flowing nodes around source (max. 8) liquid_range = 8,
-- Maximum distance that flowing liquid nodes can spread around
-- source on flat land;
-- maximum = 8; set to 0 to disable liquid flow
drowning = 0, drowning = 0,
-- Player will take this amount of damage if no bubbles are left -- Player will take this amount of damage if no bubbles are left
@ -8384,7 +8449,7 @@ Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`.
url = "http://example.org", url = "http://example.org",
timeout = 10, timeout = 10,
-- Timeout for connection in seconds. Default is 3 seconds. -- Timeout for request to be completed in seconds. Default depends on engine settings.
method = "GET", "POST", "PUT" or "DELETE" method = "GET", "POST", "PUT" or "DELETE"
-- The http method to use. Defaults to "GET". -- The http method to use. Defaults to "GET".

View File

@ -204,7 +204,8 @@ core.get_screen_info()
display_width = <width of display>, display_width = <width of display>,
display_height = <height of display>, display_height = <height of display>,
window_width = <current window width>, window_width = <current window width>,
window_height = <current window height> window_height = <current window height>,
render_info = <active render information>
} }

View File

@ -131,10 +131,11 @@ local function place_nodes(param)
p2_max = 63 p2_max = 63
elseif def.paramtype2 == "leveled" then elseif def.paramtype2 == "leveled" then
p2_max = 127 p2_max = 127
elseif def.paramtype2 == "degrotate" and def.drawtype == "plantlike" then elseif def.paramtype2 == "degrotate" and (def.drawtype == "plantlike" or def.drawtype == "mesh") then
p2_max = 179 p2_max = 239
elseif def.paramtype2 == "colorfacedir" or elseif def.paramtype2 == "colorfacedir" or
def.paramtype2 == "colorwallmounted" or def.paramtype2 == "colorwallmounted" or
def.paramtype2 == "colordegrotate" or
def.paramtype2 == "color" then def.paramtype2 == "color" then
p2_max = 255 p2_max = 255
end end
@ -143,7 +144,8 @@ local function place_nodes(param)
-- Skip undefined param2 values -- Skip undefined param2 values
if not ((def.paramtype2 == "meshoptions" and p2 % 8 > 4) or if not ((def.paramtype2 == "meshoptions" and p2 % 8 > 4) or
(def.paramtype2 == "colorwallmounted" and p2 % 8 > 5) or (def.paramtype2 == "colorwallmounted" and p2 % 8 > 5) or
(def.paramtype2 == "colorfacedir" and p2 % 32 > 23)) then ((def.paramtype2 == "colorfacedir" or def.paramtype2 == "colordegrotate")
and p2 % 32 > 23)) then
minetest.set_node(pos, { name = itemstring, param2 = p2 }) minetest.set_node(pos, { name = itemstring, param2 = p2 })
nodes_placed = nodes_placed + 1 nodes_placed = nodes_placed + 1

View File

@ -15,22 +15,6 @@ testing this node easier and more convenient.
local S = minetest.get_translator("testnodes") local S = minetest.get_translator("testnodes")
-- If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
-- This is due to <https://github.com/minetest/minetest/issues/9209>.
-- This is only added to make the items more visible to avoid confusion, but you will no longer see
-- the default inventory images for these items. When you want to test the default inventory image of drawtypes,
-- this should be turned off.
-- TODO: Remove support for fallback inventory image as soon #9209 is fixed.
local SHOW_FALLBACK_IMAGE = minetest.settings:get_bool("testnodes_show_fallback_image", false)
local fallback_image = function(img)
if SHOW_FALLBACK_IMAGE then
return img
else
return nil
end
end
-- A regular cube -- A regular cube
minetest.register_node("testnodes:normal", { minetest.register_node("testnodes:normal", {
description = S("Normal Drawtype Test Node"), description = S("Normal Drawtype Test Node"),
@ -145,20 +129,15 @@ minetest.register_node("testnodes:fencelike", {
}) })
minetest.register_node("testnodes:torchlike", { minetest.register_node("testnodes:torchlike", {
description = S("Torchlike Drawtype Test Node"), description = S("Floor Torchlike Drawtype Test Node"),
drawtype = "torchlike", drawtype = "torchlike",
paramtype = "light", paramtype = "light",
tiles = { tiles = { "testnodes_torchlike_floor.png^[colorize:#FF0000:64" },
"testnodes_torchlike_floor.png",
"testnodes_torchlike_ceiling.png",
"testnodes_torchlike_wall.png",
},
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
inventory_image = fallback_image("testnodes_torchlike_floor.png"),
}) })
minetest.register_node("testnodes:torchlike_wallmounted", { minetest.register_node("testnodes:torchlike_wallmounted", {
@ -176,12 +155,22 @@ minetest.register_node("testnodes:torchlike_wallmounted", {
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
inventory_image = fallback_image("testnodes_torchlike_floor.png"), })
minetest.register_node("testnodes:signlike", {
description = S("Floor Signlike Drawtype Test Node"),
drawtype = "signlike",
paramtype = "light",
tiles = { "testnodes_signlike.png^[colorize:#FF0000:64" },
walkable = false,
groups = { dig_immediate = 3 },
sunlight_propagates = true,
}) })
minetest.register_node("testnodes:signlike_wallmounted", {
minetest.register_node("testnodes:signlike", {
description = S("Wallmounted Signlike Drawtype Test Node"), description = S("Wallmounted Signlike Drawtype Test Node"),
drawtype = "signlike", drawtype = "signlike",
paramtype = "light", paramtype = "light",
@ -192,7 +181,6 @@ minetest.register_node("testnodes:signlike", {
walkable = false, walkable = false,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
sunlight_propagates = true, sunlight_propagates = true,
inventory_image = fallback_image("testnodes_signlike.png"),
}) })
minetest.register_node("testnodes:plantlike", { minetest.register_node("testnodes:plantlike", {
@ -223,6 +211,30 @@ minetest.register_node("testnodes:plantlike_waving", {
-- param2 will rotate -- param2 will rotate
local function rotate_on_rightclick(pos, node, clicker)
local def = minetest.registered_nodes[node.name]
local aux1 = clicker:get_player_control().aux1
local deg, deg_max
local color, color_mult = 0, 0
if def.paramtype2 == "degrotate" then
deg = node.param2
deg_max = 240
elseif def.paramtype2 == "colordegrotate" then
-- MSB [3x color, 5x rotation] LSB
deg = node.param2 % 2^5
deg_max = 24
color_mult = 2^5
color = math.floor(node.param2 / color_mult)
end
deg = (deg + (aux1 and 10 or 1)) % deg_max
node.param2 = color * color_mult + deg
minetest.swap_node(pos, node)
minetest.chat_send_player(clicker:get_player_name(),
"Rotation is now " .. deg .. " / " .. deg_max)
end
minetest.register_node("testnodes:plantlike_degrotate", { minetest.register_node("testnodes:plantlike_degrotate", {
description = S("Degrotate Plantlike Drawtype Test Node"), description = S("Degrotate Plantlike Drawtype Test Node"),
drawtype = "plantlike", drawtype = "plantlike",
@ -230,12 +242,43 @@ minetest.register_node("testnodes:plantlike_degrotate", {
paramtype2 = "degrotate", paramtype2 = "degrotate",
tiles = { "testnodes_plantlike_degrotate.png" }, tiles = { "testnodes_plantlike_degrotate.png" },
on_rightclick = rotate_on_rightclick,
place_param2 = 7,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
}) })
minetest.register_node("testnodes:mesh_degrotate", {
description = S("Degrotate Mesh Drawtype Test Node"),
drawtype = "mesh",
paramtype = "light",
paramtype2 = "degrotate",
mesh = "testnodes_ocorner.obj",
tiles = { "testnodes_mesh_stripes2.png" },
on_rightclick = rotate_on_rightclick,
place_param2 = 10, -- 15°
sunlight_propagates = true,
groups = { dig_immediate = 3 },
})
minetest.register_node("testnodes:mesh_colordegrotate", {
description = S("Color Degrotate Mesh Drawtype Test Node"),
drawtype = "mesh",
paramtype = "light",
paramtype2 = "colordegrotate",
palette = "testnodes_palette_facedir.png",
mesh = "testnodes_ocorner.obj",
tiles = { "testnodes_mesh_stripes3.png" },
on_rightclick = rotate_on_rightclick,
-- color index 1, 1 step (=15°) rotated
place_param2 = 1 * 2^5 + 1,
sunlight_propagates = true,
groups = { dig_immediate = 3 },
})
-- param2 will change height -- param2 will change height
minetest.register_node("testnodes:plantlike_leveled", { minetest.register_node("testnodes:plantlike_leveled", {
description = S("Leveled Plantlike Drawtype Test Node"), description = S("Leveled Plantlike Drawtype Test Node"),
@ -456,7 +499,6 @@ minetest.register_node("testnodes:airlike", {
walkable = false, walkable = false,
groups = { dig_immediate = 3 }, groups = { dig_immediate = 3 },
sunlight_propagates = true, sunlight_propagates = true,
inventory_image = fallback_image("testnodes_airlike.png"),
}) })
-- param2 changes liquid height -- param2 changes liquid height
@ -549,7 +591,7 @@ scale("plantlike",
scale("torchlike_wallmounted", scale("torchlike_wallmounted",
S("Double-sized Wallmounted Torchlike Drawtype Test Node"), S("Double-sized Wallmounted Torchlike Drawtype Test Node"),
S("Half-sized Wallmounted Torchlike Drawtype Test Node")) S("Half-sized Wallmounted Torchlike Drawtype Test Node"))
scale("signlike", scale("signlike_wallmounted",
S("Double-sized Wallmounted Signlike Drawtype Test Node"), S("Double-sized Wallmounted Signlike Drawtype Test Node"),
S("Half-sized Wallmounted Signlike Drawtype Test Node")) S("Half-sized Wallmounted Signlike Drawtype Test Node"))
scale("firelike", scale("firelike",

View File

@ -1,4 +0,0 @@
# If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
# This is due to <https://github.com/minetest/minetest/issues/9209>.
# This is only added to make the items more visible to avoid confusion, but you will no longer see the default inventory images for these items. When you want to test the default inventory image of drawtypes, this should be turned off.
testnodes_show_fallback_image (Use fallback inventory images) bool false

View File

@ -30,8 +30,3 @@ devtest_dungeon_mossycobble (Generate mossy cobblestone) bool false
# If enabled, some very basic biomes will be registered. # If enabled, some very basic biomes will be registered.
devtest_register_biomes (Register biomes) bool true devtest_register_biomes (Register biomes) bool true
# If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
# This is due to <https://github.com/minetest/minetest/issues/9209>.
# This is only added to make the items more visible to avoid confusion, but you will no longer see the default inventory images for these items. When you want to test the default inventory image of drawtypes, this should be turned off.
testnodes_show_fallback_image (Use fallback inventory images) bool false

View File

@ -761,7 +761,7 @@
# type: path # type: path
# texture_path = # texture_path =
# The rendering back-end for Irrlicht. # The rendering back-end.
# A restart is required after changing this. # A restart is required after changing this.
# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise. # Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
# On other platforms, OpenGL is recommended. # On other platforms, OpenGL is recommended.

View File

@ -1085,18 +1085,6 @@ msgstr ""
msgid "Invalid gamespec." msgid "Invalid gamespec."
msgstr "" msgstr ""
#. ~ DO NOT TRANSLATE THIS LITERALLY!
#. This is a special string. Put either "no" or "yes"
#. into the translation field (literally).
#. Choose "yes" if the language requires use of the fallback
#. font, "no" otherwise.
#. The fallback font is (normally) required for languages with
#. non-Latin script, like Chinese.
#. When in doubt, test your translation.
#: src/client/fontengine.cpp
msgid "needs_fallback_font"
msgstr ""
#: src/client/game.cpp #: src/client/game.cpp
msgid "Shutting down..." msgid "Shutting down..."
msgstr "" msgstr ""

View File

@ -55,7 +55,7 @@ if(NOT USE_CURL)
endif() endif()
option(ENABLE_GETTEXT "Use GetText for internationalization" TRUE) option(ENABLE_GETTEXT "Use GetText for internationalization" ${BUILD_CLIENT})
set(USE_GETTEXT FALSE) set(USE_GETTEXT FALSE)
if(ENABLE_GETTEXT) if(ENABLE_GETTEXT)
@ -102,11 +102,11 @@ endif()
option(ENABLE_GLES "Use OpenGL ES instead of OpenGL" FALSE) option(ENABLE_GLES "Use OpenGL ES instead of OpenGL" FALSE)
mark_as_advanced(ENABLE_GLES) mark_as_advanced(ENABLE_GLES)
if(BUILD_CLIENT) if(BUILD_CLIENT)
if(ENABLE_GLES) # transitive dependency from Irrlicht (see longer explanation below)
find_package(OpenGLES2 REQUIRED) if(NOT WIN32)
else() if(ENABLE_GLES)
# transitive dependency from Irrlicht (see longer explanation below) find_package(OpenGLES2 REQUIRED)
if(NOT WIN32) else()
set(OPENGL_GL_PREFERENCE "LEGACY" CACHE STRING set(OPENGL_GL_PREFERENCE "LEGACY" CACHE STRING
"See CMake Policy CMP0072 for reference. GLVND is broken on some nvidia setups") "See CMake Policy CMP0072 for reference. GLVND is broken on some nvidia setups")
set(OpenGL_GL_PREFERENCE ${OPENGL_GL_PREFERENCE}) set(OpenGL_GL_PREFERENCE ${OPENGL_GL_PREFERENCE})
@ -120,13 +120,13 @@ endif()
option(ENABLE_FREETYPE "Enable FreeType2 (TrueType fonts and basic unicode support)" TRUE) option(ENABLE_FREETYPE "Enable FreeType2 (TrueType fonts and basic unicode support)" TRUE)
set(USE_FREETYPE FALSE) set(USE_FREETYPE FALSE)
if(ENABLE_FREETYPE) if(BUILD_CLIENT AND ENABLE_FREETYPE)
find_package(Freetype) find_package(Freetype)
if(FREETYPE_FOUND) if(FREETYPE_FOUND)
message(STATUS "Freetype enabled.") message(STATUS "Freetype enabled.")
set(USE_FREETYPE TRUE) set(USE_FREETYPE TRUE)
endif() endif()
endif(ENABLE_FREETYPE) endif()
option(ENABLE_CURSES "Enable ncurses console" TRUE) option(ENABLE_CURSES "Enable ncurses console" TRUE)
set(USE_CURSES FALSE) set(USE_CURSES FALSE)
@ -146,7 +146,17 @@ option(ENABLE_POSTGRESQL "Enable PostgreSQL backend" TRUE)
set(USE_POSTGRESQL FALSE) set(USE_POSTGRESQL FALSE)
if(ENABLE_POSTGRESQL) if(ENABLE_POSTGRESQL)
find_package("PostgreSQL") if(CMAKE_VERSION VERSION_LESS "3.20")
find_package(PostgreSQL QUIET)
# Before CMake 3.20 FindPostgreSQL.cmake always looked for server includes
# but we don't need them, so continue anyway if only those are missing.
if(PostgreSQL_INCLUDE_DIR AND PostgreSQL_LIBRARY)
set(PostgreSQL_FOUND TRUE)
set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR})
endif()
else()
find_package(PostgreSQL)
endif()
if(PostgreSQL_FOUND) if(PostgreSQL_FOUND)
set(USE_POSTGRESQL TRUE) set(USE_POSTGRESQL TRUE)
@ -526,8 +536,11 @@ if(USE_CURL)
endif() endif()
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin") # When cross-compiling assume the user doesn't want to run the executable anyway,
# otherwise place it in <source dir>/bin/ since Minetest can only run from there.
if(NOT CMAKE_CROSSCOMPILING)
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin")
endif()
if(BUILD_CLIENT) if(BUILD_CLIENT)
add_executable(${PROJECT_NAME} ${client_SRCS} ${extra_windows_SRCS}) add_executable(${PROJECT_NAME} ${client_SRCS} ${extra_windows_SRCS})
@ -668,7 +681,10 @@ endif(BUILD_SERVER)
# see issue #4638 # see issue #4638
set(GETTEXT_BLACKLISTED_LOCALES set(GETTEXT_BLACKLISTED_LOCALES
ar ar
dv
he he
hi
kn
ky ky
ms_Arab ms_Arab
th th

View File

@ -44,11 +44,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define WIELDMESH_AMPLITUDE_X 7.0f #define WIELDMESH_AMPLITUDE_X 7.0f
#define WIELDMESH_AMPLITUDE_Y 10.0f #define WIELDMESH_AMPLITUDE_Y 10.0f
Camera::Camera(MapDrawControl &draw_control, Client *client): Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine):
m_draw_control(draw_control), m_draw_control(draw_control),
m_client(client) m_client(client)
{ {
scene::ISceneManager *smgr = RenderingEngine::get_scene_manager(); auto smgr = rendering_engine->get_scene_manager();
// note: making the camera node a child of the player node // note: making the camera node a child of the player node
// would lead to unexpected behaviour, so we don't do that. // would lead to unexpected behaviour, so we don't do that.
m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode()); m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
@ -542,7 +542,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
m_curr_fov_degrees = rangelim(m_curr_fov_degrees, 1.0f, 160.0f); m_curr_fov_degrees = rangelim(m_curr_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::getWindowSize();
m_aspect = (f32) window_size.X / (f32) window_size.Y; m_aspect = (f32) window_size.X / (f32) window_size.Y;
m_fov_y = m_curr_fov_degrees * M_PI / 180.0; m_fov_y = m_curr_fov_degrees * M_PI / 180.0;
// Increase vertical FOV on lower aspect ratios (<16:10) // Increase vertical FOV on lower aspect ratios (<16:10)

View File

@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class LocalPlayer; class LocalPlayer;
struct MapDrawControl; struct MapDrawControl;
class Client; class Client;
class RenderingEngine;
class WieldMeshSceneNode; class WieldMeshSceneNode;
struct Nametag struct Nametag
@ -104,7 +105,7 @@ enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
class Camera class Camera
{ {
public: public:
Camera(MapDrawControl &draw_control, Client *client); Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine);
~Camera(); ~Camera();
// Get camera scene node. // Get camera scene node.

View File

@ -98,6 +98,7 @@ Client::Client(
NodeDefManager *nodedef, NodeDefManager *nodedef,
ISoundManager *sound, ISoundManager *sound,
MtEventManager *event, MtEventManager *event,
RenderingEngine *rendering_engine,
bool ipv6, bool ipv6,
GameUI *game_ui GameUI *game_ui
): ):
@ -108,8 +109,9 @@ Client::Client(
m_nodedef(nodedef), m_nodedef(nodedef),
m_sound(sound), m_sound(sound),
m_event(event), m_event(event),
m_rendering_engine(rendering_engine),
m_env( m_env(
new ClientMap(this, control, 666), new ClientMap(this, rendering_engine, control, 666),
tsrc, this tsrc, this
), ),
m_particle_manager(&m_env), m_particle_manager(&m_env),
@ -301,12 +303,7 @@ Client::~Client()
} }
// cleanup 3d model meshes on client shutdown // cleanup 3d model meshes on client shutdown
while (RenderingEngine::get_mesh_cache()->getMeshCount() != 0) { m_rendering_engine->cleanupMeshCache();
scene::IAnimatedMesh *mesh = RenderingEngine::get_mesh_cache()->getMeshByIndex(0);
if (mesh)
RenderingEngine::get_mesh_cache()->removeMesh(mesh);
}
delete m_minimap; delete m_minimap;
m_minimap = nullptr; m_minimap = nullptr;
@ -663,18 +660,11 @@ bool Client::loadMedia(const std::string &data, const std::string &filename,
TRACESTREAM(<< "Client: Attempting to load image " TRACESTREAM(<< "Client: Attempting to load image "
<< "file \"" << filename << "\"" << std::endl); << "file \"" << filename << "\"" << std::endl);
io::IFileSystem *irrfs = RenderingEngine::get_filesystem(); io::IFileSystem *irrfs = m_rendering_engine->get_filesystem();
video::IVideoDriver *vdrv = RenderingEngine::get_video_driver(); video::IVideoDriver *vdrv = m_rendering_engine->get_video_driver();
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
io::IReadFile *rfile = irrfs->createMemoryReadFile( io::IReadFile *rfile = irrfs->createMemoryReadFile(
data.c_str(), data.size(), "_tempreadfile"); data.c_str(), data.size(), "_tempreadfile");
#else
// Silly irrlicht's const-incorrectness
Buffer<char> data_rw(data.c_str(), data.size());
io::IReadFile *rfile = irrfs->createMemoryReadFile(
*data_rw, data_rw.getSize(), "_tempreadfile");
#endif
FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file."); FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file.");
@ -1430,6 +1420,11 @@ bool Client::updateWieldedItem()
return true; return true;
} }
scene::ISceneManager* Client::getSceneManager()
{
return m_rendering_engine->get_scene_manager();
}
Inventory* Client::getInventory(const InventoryLocation &loc) Inventory* Client::getInventory(const InventoryLocation &loc)
{ {
switch(loc.type){ switch(loc.type){
@ -1692,7 +1687,7 @@ typedef struct TextureUpdateArgs {
ITextureSource *tsrc; ITextureSource *tsrc;
} TextureUpdateArgs; } TextureUpdateArgs;
void texture_update_progress(void *args, u32 progress, u32 max_progress) void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progress)
{ {
TextureUpdateArgs* targs = (TextureUpdateArgs*) args; TextureUpdateArgs* targs = (TextureUpdateArgs*) args;
u16 cur_percent = ceil(progress / (double) max_progress * 100.); u16 cur_percent = ceil(progress / (double) max_progress * 100.);
@ -1711,7 +1706,7 @@ void texture_update_progress(void *args, u32 progress, u32 max_progress)
targs->last_time_ms = time_ms; targs->last_time_ms = time_ms;
std::basic_stringstream<wchar_t> strm; std::basic_stringstream<wchar_t> strm;
strm << targs->text_base << " " << targs->last_percent << "%..."; strm << targs->text_base << " " << targs->last_percent << "%...";
RenderingEngine::draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0, m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
72 + (u16) ((18. / 100.) * (double) targs->last_percent), true); 72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
} }
} }
@ -1732,21 +1727,21 @@ void Client::afterContentReceived()
// Rebuild inherited images and recreate textures // Rebuild inherited images and recreate textures
infostream<<"- Rebuilding images and textures"<<std::endl; infostream<<"- Rebuilding images and textures"<<std::endl;
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 70); m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 70);
m_tsrc->rebuildImagesAndTextures(); m_tsrc->rebuildImagesAndTextures();
delete[] text; delete[] text;
// Rebuild shaders // Rebuild shaders
infostream<<"- Rebuilding shaders"<<std::endl; infostream<<"- Rebuilding shaders"<<std::endl;
text = wgettext("Rebuilding shaders..."); text = wgettext("Rebuilding shaders...");
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 71); m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 71);
m_shsrc->rebuildShaders(); m_shsrc->rebuildShaders();
delete[] text; delete[] text;
// Update node aliases // Update node aliases
infostream<<"- Updating node aliases"<<std::endl; infostream<<"- Updating node aliases"<<std::endl;
text = wgettext("Initializing nodes..."); text = wgettext("Initializing nodes...");
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 72); m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 72);
m_nodedef->updateAliases(m_itemdef); m_nodedef->updateAliases(m_itemdef);
for (const auto &path : getTextureDirs()) { for (const auto &path : getTextureDirs()) {
TextureOverrideSource override_source(path + DIR_DELIM + "override.txt"); TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
@ -1765,7 +1760,7 @@ void Client::afterContentReceived()
tu_args.last_percent = 0; tu_args.last_percent = 0;
tu_args.text_base = wgettext("Initializing nodes"); tu_args.text_base = wgettext("Initializing nodes");
tu_args.tsrc = m_tsrc; tu_args.tsrc = m_tsrc;
m_nodedef->updateTextures(this, texture_update_progress, &tu_args); m_nodedef->updateTextures(this, &tu_args);
delete[] tu_args.text_base; delete[] tu_args.text_base;
// Start mesh update thread after setting up content definitions // Start mesh update thread after setting up content definitions
@ -1779,7 +1774,7 @@ void Client::afterContentReceived()
m_script->on_client_ready(m_env.getLocalPlayer()); m_script->on_client_ready(m_env.getLocalPlayer());
text = wgettext("Done!"); text = wgettext("Done!");
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100); m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 100);
infostream<<"Client::afterContentReceived() done"<<std::endl; infostream<<"Client::afterContentReceived() done"<<std::endl;
delete[] text; delete[] text;
} }
@ -1797,7 +1792,7 @@ float Client::getCurRate()
void Client::makeScreenshot() void Client::makeScreenshot()
{ {
irr::video::IVideoDriver *driver = RenderingEngine::get_video_driver(); irr::video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
irr::video::IImage* const raw_image = driver->createScreenShot(); irr::video::IImage* const raw_image = driver->createScreenShot();
if (!raw_image) if (!raw_image)
@ -1947,23 +1942,17 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache)
// Create the mesh, remove it from cache and return it // Create the mesh, remove it from cache and return it
// This allows unique vertex colors and other properties for each instance // This allows unique vertex colors and other properties for each instance
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8 io::IReadFile *rfile = m_rendering_engine->get_filesystem()->createMemoryReadFile(
io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile(
data.c_str(), data.size(), filename.c_str()); data.c_str(), data.size(), filename.c_str());
#else
Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile(
*data_rw, data_rw.getSize(), filename.c_str());
#endif
FATAL_ERROR_IF(!rfile, "Could not create/open RAM file"); FATAL_ERROR_IF(!rfile, "Could not create/open RAM file");
scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile); scene::IAnimatedMesh *mesh = m_rendering_engine->get_scene_manager()->getMesh(rfile);
rfile->drop(); rfile->drop();
if (!mesh) if (!mesh)
return nullptr; return nullptr;
mesh->grab(); mesh->grab();
if (!cache) if (!cache)
RenderingEngine::get_mesh_cache()->removeMesh(mesh); m_rendering_engine->removeMesh(mesh);
return mesh; return mesh;
} }

View File

@ -45,6 +45,7 @@ struct ClientEvent;
struct MeshMakeData; struct MeshMakeData;
struct ChatMessage; struct ChatMessage;
class MapBlockMesh; class MapBlockMesh;
class RenderingEngine;
class IWritableTextureSource; class IWritableTextureSource;
class IWritableShaderSource; class IWritableShaderSource;
class ISoundManager; class ISoundManager;
@ -122,6 +123,7 @@ public:
NodeDefManager *nodedef, NodeDefManager *nodedef,
ISoundManager *sound, ISoundManager *sound,
MtEventManager *event, MtEventManager *event,
RenderingEngine *rendering_engine,
bool ipv6, bool ipv6,
GameUI *game_ui GameUI *game_ui
); );
@ -346,6 +348,7 @@ public:
float mediaReceiveProgress(); float mediaReceiveProgress();
void afterContentReceived(); void afterContentReceived();
void showUpdateProgressTexture(void *args, u32 progress, u32 max_progress);
float getRTT(); float getRTT();
float getCurRate(); float getCurRate();
@ -354,6 +357,7 @@ public:
void setCamera(Camera* camera) { m_camera = camera; } void setCamera(Camera* camera) { m_camera = camera; }
Camera* getCamera () { return m_camera; } Camera* getCamera () { return m_camera; }
scene::ISceneManager *getSceneManager();
bool shouldShowMinimap() const; bool shouldShowMinimap() const;
@ -381,6 +385,7 @@ public:
// Insert a media file appropriately into the appropriate manager // Insert a media file appropriately into the appropriate manager
bool loadMedia(const std::string &data, const std::string &filename, bool loadMedia(const std::string &data, const std::string &filename,
bool from_media_push = false); bool from_media_push = false);
// Send a request for conventional media transfer // Send a request for conventional media transfer
void request_media(const std::vector<std::string> &file_requests); void request_media(const std::vector<std::string> &file_requests);
@ -476,6 +481,7 @@ private:
NodeDefManager *m_nodedef; NodeDefManager *m_nodedef;
ISoundManager *m_sound; ISoundManager *m_sound;
MtEventManager *m_event; MtEventManager *m_event;
RenderingEngine *m_rendering_engine;
ClientEnvironment m_env; ClientEnvironment m_env;

View File

@ -235,7 +235,16 @@ void ClientEnvironment::step(float dtime)
&player_collisions); &player_collisions);
} }
bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal(); bool player_immortal = false;
f32 player_fall_factor = 1.0f;
GenericCAO *playercao = lplayer->getCAO();
if (playercao) {
player_immortal = playercao->isImmortal();
int addp_p = itemgroup_get(playercao->getGroups(),
"fall_damage_add_percent");
// convert armor group into an usable fall damage factor
player_fall_factor = 1.0f + (float)addp_p / 100.0f;
}
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;;
@ -248,17 +257,20 @@ void ClientEnvironment::step(float dtime)
speed_diff.Z = 0; speed_diff.Z = 0;
f32 pre_factor = 1; // 1 hp per node/s f32 pre_factor = 1; // 1 hp per node/s
f32 tolerance = BS*14; // 5 without damage f32 tolerance = BS*14; // 5 without damage
f32 post_factor = 1; // 1 hp per node/s
if (info.type == COLLISION_NODE) { if (info.type == COLLISION_NODE) {
const ContentFeatures &f = m_client->ndef()-> const ContentFeatures &f = m_client->ndef()->
get(m_map->getNode(info.node_p)); get(m_map->getNode(info.node_p));
// Determine fall damage multiplier // Determine fall damage modifier
int addp = itemgroup_get(f.groups, "fall_damage_add_percent"); int addp_n = itemgroup_get(f.groups, "fall_damage_add_percent");
pre_factor = 1.0f + (float)addp / 100.0f; // convert node group to an usable fall damage factor
f32 node_fall_factor = 1.0f + (float)addp_n / 100.0f;
// combine both player fall damage modifiers
pre_factor = node_fall_factor * player_fall_factor;
} }
float speed = pre_factor * speed_diff.getLength(); float speed = pre_factor * speed_diff.getLength();
if (speed > tolerance && !player_immortal) {
f32 damage_f = (speed - tolerance) / BS * post_factor; if (speed > tolerance && !player_immortal && pre_factor > 0.0f) {
f32 damage_f = (speed - tolerance) / BS;
u16 damage = (u16)MYMIN(damage_f + 0.5, U16_MAX); u16 damage = (u16)MYMIN(damage_f + 0.5, U16_MAX);
if (damage != 0) { if (damage != 0) {
damageLocalPlayer(damage, true); damageLocalPlayer(damage, true);
@ -340,7 +352,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
if (!m_ao_manager.registerObject(object)) if (!m_ao_manager.registerObject(object))
return 0; return 0;
object->addToScene(m_texturesource); object->addToScene(m_texturesource, m_client->getSceneManager());
// Update lighting immediately // Update lighting immediately
object->updateLight(getDayNightRatio()); object->updateLight(getDayNightRatio());

View File

@ -80,7 +80,7 @@ ClientLauncher::~ClientLauncher()
delete g_fontengine; delete g_fontengine;
delete g_gamecallback; delete g_gamecallback;
delete RenderingEngine::get_instance(); delete m_rendering_engine;
#if USE_SOUND #if USE_SOUND
g_sound_manager_singleton.reset(); g_sound_manager_singleton.reset();
@ -101,7 +101,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// List video modes if requested // List video modes if requested
if (list_video_modes) if (list_video_modes)
return RenderingEngine::print_video_modes(); return m_rendering_engine->print_video_modes();
#if USE_SOUND #if USE_SOUND
if (g_settings->getBool("enable_sound")) if (g_settings->getBool("enable_sound"))
@ -120,12 +120,12 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
return true; return true;
} }
if (RenderingEngine::get_video_driver() == NULL) { if (m_rendering_engine->get_video_driver() == NULL) {
errorstream << "Could not initialize video driver." << std::endl; errorstream << "Could not initialize video driver." << std::endl;
return false; return false;
} }
RenderingEngine::get_instance()->setupTopLevelWindow(PROJECT_NAME_C); m_rendering_engine->setupTopLevelWindow(PROJECT_NAME_C);
/* /*
This changes the minimum allowed number of vertices in a VBO. This changes the minimum allowed number of vertices in a VBO.
@ -136,15 +136,15 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// Create game callback for menus // Create game callback for menus
g_gamecallback = new MainGameCallback(); g_gamecallback = new MainGameCallback();
RenderingEngine::get_instance()->setResizable(true); m_rendering_engine->setResizable(true);
init_input(); init_input();
RenderingEngine::get_scene_manager()->getParameters()-> m_rendering_engine->get_scene_manager()->getParameters()->
setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
guienv = RenderingEngine::get_gui_env(); guienv = m_rendering_engine->get_gui_env();
skin = RenderingEngine::get_gui_env()->getSkin(); skin = guienv->getSkin();
skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255)); skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255));
skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0)); skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0));
skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30)); skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30));
@ -166,7 +166,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
sprite_path.append("checkbox_16.png"); sprite_path.append("checkbox_16.png");
// Texture dimensions should be a power of 2 // Texture dimensions should be a power of 2
gui::IGUISpriteBank *sprites = skin->getSpriteBank(); gui::IGUISpriteBank *sprites = skin->getSpriteBank();
video::IVideoDriver *driver = RenderingEngine::get_video_driver(); video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str()); video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str());
if (sprite_texture) { if (sprite_texture) {
s32 sprite_id = sprites->addTextureAsSprite(sprite_texture); s32 sprite_id = sprites->addTextureAsSprite(sprite_texture);
@ -178,15 +178,13 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
g_fontengine = new FontEngine(guienv); g_fontengine = new FontEngine(guienv);
FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed."); FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed.");
#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
// Irrlicht 1.8 input colours // Irrlicht 1.8 input colours
skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128)); skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128));
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49)); skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49));
#endif
// Create the menu clouds // Create the menu clouds
if (!g_menucloudsmgr) if (!g_menucloudsmgr)
g_menucloudsmgr = RenderingEngine::get_scene_manager()->createNewSceneManager(); g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager();
if (!g_menuclouds) if (!g_menuclouds)
g_menuclouds = new Clouds(g_menucloudsmgr, -1, rand()); g_menuclouds = new Clouds(g_menucloudsmgr, -1, rand());
g_menuclouds->setHeight(100.0f); g_menuclouds->setHeight(100.0f);
@ -214,11 +212,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
bool retval = true; bool retval = true;
bool *kill = porting::signal_handler_killstatus(); bool *kill = porting::signal_handler_killstatus();
while (RenderingEngine::run() && !*kill && while (m_rendering_engine->run() && !*kill &&
!g_gamecallback->shutdown_requested) { !g_gamecallback->shutdown_requested) {
// Set the window caption // Set the window caption
const wchar_t *text = wgettext("Main Menu"); const wchar_t *text = wgettext("Main Menu");
RenderingEngine::get_raw_device()-> m_rendering_engine->get_raw_device()->
setWindowCaption((utf8_to_wide(PROJECT_NAME_C) + setWindowCaption((utf8_to_wide(PROJECT_NAME_C) +
L" " + utf8_to_wide(g_version_hash) + L" " + utf8_to_wide(g_version_hash) +
L" [" + text + L"]").c_str()); L" [" + text + L"]").c_str());
@ -226,14 +224,14 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
try { // This is used for catching disconnects try { // This is used for catching disconnects
RenderingEngine::get_gui_env()->clear(); m_rendering_engine->get_gui_env()->clear();
/* /*
We need some kind of a root node to be able to add We need some kind of a root node to be able to add
custom gui elements directly on the screen. custom gui elements directly on the screen.
Otherwise they won't be automatically drawn. Otherwise they won't be automatically drawn.
*/ */
guiroot = RenderingEngine::get_gui_env()->addStaticText(L"", guiroot = m_rendering_engine->get_gui_env()->addStaticText(L"",
core::rect<s32>(0, 0, 10000, 10000)); core::rect<s32>(0, 0, 10000, 10000));
bool game_has_run = launch_game(error_message, reconnect_requested, bool game_has_run = launch_game(error_message, reconnect_requested,
@ -256,29 +254,30 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
} }
// Break out of menu-game loop to shut down cleanly // Break out of menu-game loop to shut down cleanly
if (!RenderingEngine::get_raw_device()->run() || *kill) { if (!m_rendering_engine->run() || *kill) {
if (!g_settings_path.empty()) if (!g_settings_path.empty())
g_settings->updateConfigFile(g_settings_path.c_str()); g_settings->updateConfigFile(g_settings_path.c_str());
break; break;
} }
RenderingEngine::get_video_driver()->setTextureCreationFlag( m_rendering_engine->get_video_driver()->setTextureCreationFlag(
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map")); video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
#ifdef HAVE_TOUCHSCREENGUI #ifdef HAVE_TOUCHSCREENGUI
receiver->m_touchscreengui = new TouchScreenGUI(RenderingEngine::get_raw_device(), receiver); receiver->m_touchscreengui = new TouchScreenGUI(m_rendering_engine->get_raw_device(), receiver);
g_touchscreengui = receiver->m_touchscreengui; g_touchscreengui = receiver->m_touchscreengui;
#endif #endif
the_game( the_game(
kill, kill,
input, input,
m_rendering_engine,
start_data, start_data,
error_message, error_message,
chat_backend, chat_backend,
&reconnect_requested &reconnect_requested
); );
RenderingEngine::get_scene_manager()->clear(); m_rendering_engine->get_scene_manager()->clear();
#ifdef HAVE_TOUCHSCREENGUI #ifdef HAVE_TOUCHSCREENGUI
delete g_touchscreengui; delete g_touchscreengui;
@ -346,8 +345,8 @@ void ClientLauncher::init_args(GameStartData &start_data, const Settings &cmd_ar
bool ClientLauncher::init_engine() bool ClientLauncher::init_engine()
{ {
receiver = new MyEventReceiver(); receiver = new MyEventReceiver();
new RenderingEngine(receiver); m_rendering_engine = new RenderingEngine(receiver);
return RenderingEngine::get_raw_device() != nullptr; return m_rendering_engine->get_raw_device() != nullptr;
} }
void ClientLauncher::init_input() void ClientLauncher::init_input()
@ -364,7 +363,7 @@ void ClientLauncher::init_input()
// Make sure this is called maximum once per // Make sure this is called maximum once per
// irrlicht device, otherwise it will give you // irrlicht device, otherwise it will give you
// multiple events for the same joystick. // multiple events for the same joystick.
if (RenderingEngine::get_raw_device()->activateJoysticks(infos)) { if (m_rendering_engine->get_raw_device()->activateJoysticks(infos)) {
infostream << "Joystick support enabled" << std::endl; infostream << "Joystick support enabled" << std::endl;
joystick_infos.reserve(infos.size()); joystick_infos.reserve(infos.size());
for (u32 i = 0; i < infos.size(); i++) { for (u32 i = 0; i < infos.size(); i++) {
@ -471,7 +470,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
start_data.address.empty() && !start_data.name.empty(); start_data.address.empty() && !start_data.name.empty();
} }
if (!RenderingEngine::run()) if (!m_rendering_engine->run())
return false; return false;
if (!start_data.isSinglePlayer() && start_data.name.empty()) { if (!start_data.isSinglePlayer() && start_data.name.empty()) {
@ -543,14 +542,14 @@ bool ClientLauncher::launch_game(std::string &error_message,
void ClientLauncher::main_menu(MainMenuData *menudata) void ClientLauncher::main_menu(MainMenuData *menudata)
{ {
bool *kill = porting::signal_handler_killstatus(); bool *kill = porting::signal_handler_killstatus();
video::IVideoDriver *driver = RenderingEngine::get_video_driver(); video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
infostream << "Waiting for other menus" << std::endl; infostream << "Waiting for other menus" << std::endl;
while (RenderingEngine::get_raw_device()->run() && !*kill) { while (m_rendering_engine->run() && !*kill) {
if (!isMenuActive()) if (!isMenuActive())
break; break;
driver->beginScene(true, true, video::SColor(255, 128, 128, 128)); driver->beginScene(true, true, video::SColor(255, 128, 128, 128));
RenderingEngine::get_gui_env()->drawAll(); m_rendering_engine->get_gui_env()->drawAll();
driver->endScene(); driver->endScene();
// On some computers framerate doesn't seem to be automatically limited // On some computers framerate doesn't seem to be automatically limited
sleep_ms(25); sleep_ms(25);
@ -559,14 +558,14 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
// Cursor can be non-visible when coming from the game // Cursor can be non-visible when coming from the game
#ifndef ANDROID #ifndef ANDROID
RenderingEngine::get_raw_device()->getCursorControl()->setVisible(true); m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true);
#endif #endif
/* show main menu */ /* show main menu */
GUIEngine mymenu(&input->joystick, guiroot, &g_menumgr, menudata, *kill); GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill);
/* leave scene manager in a clean state */ /* leave scene manager in a clean state */
RenderingEngine::get_scene_manager()->clear(); m_rendering_engine->get_scene_manager()->clear();
} }
void ClientLauncher::speed_tests() void ClientLauncher::speed_tests()

View File

@ -49,6 +49,7 @@ private:
bool list_video_modes = false; bool list_video_modes = false;
bool skip_main_menu = false; bool skip_main_menu = false;
bool random_input = false; bool random_input = false;
RenderingEngine *m_rendering_engine = nullptr;
InputHandler *input = nullptr; InputHandler *input = nullptr;
MyEventReceiver *receiver = nullptr; MyEventReceiver *receiver = nullptr;
gui::IGUISkin *skin = nullptr; gui::IGUISkin *skin = nullptr;

View File

@ -64,12 +64,13 @@ void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
ClientMap::ClientMap( ClientMap::ClientMap(
Client *client, Client *client,
RenderingEngine *rendering_engine,
MapDrawControl &control, MapDrawControl &control,
s32 id s32 id
): ):
Map(client), Map(client),
scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
RenderingEngine::get_scene_manager(), id), rendering_engine->get_scene_manager(), id),
m_client(client), m_client(client),
m_control(control) m_control(control)
{ {
@ -317,7 +318,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS); v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS);
float d = camera_position.getDistanceFrom(block_pos_r); float d = camera_position.getDistanceFrom(block_pos_r);
d = MYMAX(0,d - BLOCK_MAX_RADIUS); d = MYMAX(0,d - BLOCK_MAX_RADIUS);
// Mesh animation // Mesh animation
if (pass == scene::ESNRP_SOLID) { if (pass == scene::ESNRP_SOLID) {
//MutexAutoLock lock(block->mesh_mutex); //MutexAutoLock lock(block->mesh_mutex);
@ -499,12 +500,12 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
static v3f z_directions[50] = { static v3f z_directions[50] = {
v3f(-100, 0, 0) v3f(-100, 0, 0)
}; };
static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = { static f32 z_offsets[50] = {
-1000, -1000,
}; };
if(z_directions[0].X < -99){ if (z_directions[0].X < -99) {
for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){ for (u32 i = 0; i < ARRLEN(z_directions); i++) {
// Assumes FOV of 72 and 16/9 aspect ratio // Assumes FOV of 72 and 16/9 aspect ratio
z_directions[i] = v3f( z_directions[i] = v3f(
0.02 * myrand_range(-100, 100), 0.02 * myrand_range(-100, 100),
@ -520,7 +521,8 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
if(sunlight_min_d > 35*BS) if(sunlight_min_d > 35*BS)
sunlight_min_d = 35*BS; sunlight_min_d = 35*BS;
std::vector<int> values; std::vector<int> values;
for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){ values.reserve(ARRLEN(z_directions));
for (u32 i = 0; i < ARRLEN(z_directions); i++) {
v3f z_dir = z_directions[i]; v3f z_dir = z_directions[i];
core::CMatrix4<f32> a; core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0,1,0), z_dir); a.buildRotateFromTo(v3f(0,1,0), z_dir);

View File

@ -68,6 +68,7 @@ class ClientMap : public Map, public scene::ISceneNode
public: public:
ClientMap( ClientMap(
Client *client, Client *client,
RenderingEngine *rendering_engine,
MapDrawControl &control, MapDrawControl &control,
s32 id s32 id
); );

View File

@ -216,7 +216,6 @@ void ClientMediaDownloader::initialStep(Client *client)
// This is the first time we use httpfetch, so alloc a caller ID // This is the first time we use httpfetch, so alloc a caller ID
m_httpfetch_caller = httpfetch_caller_alloc(); m_httpfetch_caller = httpfetch_caller_alloc();
m_httpfetch_timeout = g_settings->getS32("curl_timeout");
// Set the active fetch limit to curl_parallel_limit or 84, // Set the active fetch limit to curl_parallel_limit or 84,
// whichever is greater. This gives us some leeway so that // whichever is greater. This gives us some leeway so that
@ -258,8 +257,6 @@ void ClientMediaDownloader::initialStep(Client *client)
remote->baseurl + MTHASHSET_FILE_NAME; remote->baseurl + MTHASHSET_FILE_NAME;
fetch_request.caller = m_httpfetch_caller; fetch_request.caller = m_httpfetch_caller;
fetch_request.request_id = m_httpfetch_next_id; // == i fetch_request.request_id = m_httpfetch_next_id; // == i
fetch_request.timeout = m_httpfetch_timeout;
fetch_request.connect_timeout = m_httpfetch_timeout;
fetch_request.method = HTTP_POST; fetch_request.method = HTTP_POST;
fetch_request.raw_data = required_hash_set; fetch_request.raw_data = required_hash_set;
fetch_request.extra_headers.emplace_back( fetch_request.extra_headers.emplace_back(
@ -432,9 +429,8 @@ void ClientMediaDownloader::startRemoteMediaTransfers()
fetch_request.url = url; fetch_request.url = url;
fetch_request.caller = m_httpfetch_caller; fetch_request.caller = m_httpfetch_caller;
fetch_request.request_id = m_httpfetch_next_id; fetch_request.request_id = m_httpfetch_next_id;
fetch_request.timeout = 0; // no data timeout! fetch_request.timeout =
fetch_request.connect_timeout = g_settings->getS32("curl_file_download_timeout");
m_httpfetch_timeout;
httpfetch_async(fetch_request); httpfetch_async(fetch_request);
m_remote_file_transfers.insert(std::make_pair( m_remote_file_transfers.insert(std::make_pair(

View File

@ -137,7 +137,6 @@ private:
// Status of remote transfers // Status of remote transfers
unsigned long m_httpfetch_caller; unsigned long m_httpfetch_caller;
unsigned long m_httpfetch_next_id = 0; unsigned long m_httpfetch_next_id = 0;
long m_httpfetch_timeout = 0;
s32 m_httpfetch_active = 0; s32 m_httpfetch_active = 0;
s32 m_httpfetch_active_limit = 0; s32 m_httpfetch_active_limit = 0;
s32 m_outstanding_hash_sets = 0; s32 m_outstanding_hash_sets = 0;

View File

@ -44,7 +44,7 @@ public:
ClientActiveObject(u16 id, Client *client, ClientEnvironment *env); ClientActiveObject(u16 id, Client *client, ClientEnvironment *env);
virtual ~ClientActiveObject(); virtual ~ClientActiveObject();
virtual void addToScene(ITextureSource *tsrc) {} virtual void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) = 0;
virtual void removeFromScene(bool permanent) {} virtual void removeFromScene(bool permanent) {}
virtual void updateLight(u32 day_night_ratio) {} virtual void updateLight(u32 day_night_ratio) {}

View File

@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Menu clouds are created later // Menu clouds are created later
class Clouds; class Clouds;
Clouds *g_menuclouds = NULL; Clouds *g_menuclouds = NULL;
irr::scene::ISceneManager *g_menucloudsmgr = NULL; scene::ISceneManager *g_menucloudsmgr = NULL;
// Constant for now // Constant for now
static constexpr const float cloud_size = BS * 64.0f; static constexpr const float cloud_size = BS * 64.0f;
@ -170,7 +170,7 @@ void Clouds::render()
// Read noise // Read noise
std::vector<char> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2); // vector<bool> is broken std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
std::vector<video::S3DVertex> vertices; std::vector<video::S3DVertex> vertices;
vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i); vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);

View File

@ -29,8 +29,7 @@ class Clouds;
extern Clouds *g_menuclouds; extern Clouds *g_menuclouds;
// Scene manager used for menu clouds // Scene manager used for menu clouds
namespace irr{namespace scene{class ISceneManager;}} extern scene::ISceneManager *g_menucloudsmgr;
extern irr::scene::ISceneManager *g_menucloudsmgr;
class Clouds : public scene::ISceneNode class Clouds : public scene::ISceneNode
{ {

View File

@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IMeshManipulator.h> #include <IMeshManipulator.h>
#include <IAnimatedMeshSceneNode.h> #include <IAnimatedMeshSceneNode.h>
#include "client/client.h" #include "client/client.h"
#include "client/renderingengine.h"
#include "client/sound.h" #include "client/sound.h"
#include "client/tile.h" #include "client/tile.h"
#include "util/basic_macros.h" #include "util/basic_macros.h"
@ -190,7 +189,7 @@ public:
static ClientActiveObject* create(Client *client, ClientEnvironment *env); static ClientActiveObject* create(Client *client, ClientEnvironment *env);
void addToScene(ITextureSource *tsrc); void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr);
void removeFromScene(bool permanent); void removeFromScene(bool permanent);
void updateLight(u32 day_night_ratio); void updateLight(u32 day_night_ratio);
void updateNodePos(); void updateNodePos();
@ -221,7 +220,7 @@ ClientActiveObject* TestCAO::create(Client *client, ClientEnvironment *env)
return new TestCAO(client, env); return new TestCAO(client, env);
} }
void TestCAO::addToScene(ITextureSource *tsrc) void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
{ {
if(m_node != NULL) if(m_node != NULL)
return; return;
@ -250,7 +249,7 @@ void TestCAO::addToScene(ITextureSource *tsrc)
// Add to mesh // Add to mesh
mesh->addMeshBuffer(buf); mesh->addMeshBuffer(buf);
buf->drop(); buf->drop();
m_node = RenderingEngine::get_scene_manager()->addMeshSceneNode(mesh, NULL); m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop(); mesh->drop();
updateNodePos(); updateNodePos();
} }
@ -595,9 +594,9 @@ void GenericCAO::removeFromScene(bool permanent)
m_client->getMinimap()->removeMarker(&m_marker); m_client->getMinimap()->removeMarker(&m_marker);
} }
void GenericCAO::addToScene(ITextureSource *tsrc) void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
{ {
m_smgr = RenderingEngine::get_scene_manager(); m_smgr = smgr;
if (getSceneNode() != NULL) { if (getSceneNode() != NULL) {
return; return;
@ -629,8 +628,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
} }
auto grabMatrixNode = [this] { auto grabMatrixNode = [this] {
m_matrixnode = RenderingEngine::get_scene_manager()-> m_matrixnode = m_smgr->addDummyTransformationSceneNode();
addDummyTransformationSceneNode();
m_matrixnode->grab(); m_matrixnode->grab();
}; };
@ -648,7 +646,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
if (m_prop.visual == "sprite") { if (m_prop.visual == "sprite") {
grabMatrixNode(); grabMatrixNode();
m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode( m_spritenode = m_smgr->addBillboardSceneNode(
m_matrixnode, v2f(1, 1), v3f(0,0,0), -1); m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
m_spritenode->grab(); m_spritenode->grab();
m_spritenode->setMaterialTexture(0, m_spritenode->setMaterialTexture(0,
@ -733,8 +731,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
mesh->addMeshBuffer(buf); mesh->addMeshBuffer(buf);
buf->drop(); buf->drop();
} }
m_meshnode = RenderingEngine::get_scene_manager()-> m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab(); m_meshnode->grab();
mesh->drop(); mesh->drop();
// Set it to use the materials of the meshbuffers directly. // Set it to use the materials of the meshbuffers directly.
@ -743,8 +740,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
} else if (m_prop.visual == "cube") { } else if (m_prop.visual == "cube") {
grabMatrixNode(); grabMatrixNode();
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
m_meshnode = RenderingEngine::get_scene_manager()-> m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab(); m_meshnode->grab();
mesh->drop(); mesh->drop();
@ -757,8 +753,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
grabMatrixNode(); grabMatrixNode();
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true); scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
if (mesh) { if (mesh) {
m_animated_meshnode = RenderingEngine::get_scene_manager()-> m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode);
addAnimatedMeshSceneNode(mesh, m_matrixnode);
m_animated_meshnode->grab(); m_animated_meshnode->grab();
mesh->drop(); // The scene node took hold of it mesh->drop(); // The scene node took hold of it
@ -799,8 +794,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
infostream << "serialized form: " << m_prop.wield_item << std::endl; infostream << "serialized form: " << m_prop.wield_item << std::endl;
item.deSerialize(m_prop.wield_item, m_client->idef()); item.deSerialize(m_prop.wield_item, m_client->idef());
} }
m_wield_meshnode = new WieldMeshSceneNode( m_wield_meshnode = new WieldMeshSceneNode(m_smgr, -1);
RenderingEngine::get_scene_manager(), -1);
m_wield_meshnode->setItem(item, m_client, m_wield_meshnode->setItem(item, m_client,
(m_prop.visual == "wielditem")); (m_prop.visual == "wielditem"));
@ -1089,7 +1083,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
} }
removeFromScene(false); removeFromScene(false);
addToScene(m_client->tsrc()); addToScene(m_client->tsrc(), m_smgr);
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back // Attachments, part 2: Now that the parent has been refreshed, put its attachments back
for (u16 cao_id : m_attachment_child_ids) { for (u16 cao_id : m_attachment_child_ids) {
@ -1488,11 +1482,8 @@ void GenericCAO::updateAnimation()
if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed) if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed)
m_animated_meshnode->setAnimationSpeed(m_animation_speed); m_animated_meshnode->setAnimationSpeed(m_animation_speed);
m_animated_meshnode->setTransitionTime(m_animation_blend); m_animated_meshnode->setTransitionTime(m_animation_blend);
// Requires Irrlicht 1.8 or greater
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR > 1
if (m_animated_meshnode->getLoopMode() != m_animation_loop) if (m_animated_meshnode->getLoopMode() != m_animation_loop)
m_animated_meshnode->setLoopMode(m_animation_loop); m_animated_meshnode->setLoopMode(m_animation_loop);
#endif
} }
void GenericCAO::updateAnimationSpeed() void GenericCAO::updateAnimationSpeed()
@ -1508,10 +1499,10 @@ void GenericCAO::updateBonePosition()
if (m_bone_position.empty() || !m_animated_meshnode) if (m_bone_position.empty() || !m_animated_meshnode)
return; return;
m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render m_animated_meshnode->setJointMode(scene::EJUOR_CONTROL); // To write positions to the mesh on render
for (auto &it : m_bone_position) { for (auto &it : m_bone_position) {
std::string bone_name = it.first; std::string bone_name = it.first;
irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str()); scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
if (bone) { if (bone) {
bone->setPosition(it.second.X); bone->setPosition(it.second.X);
bone->setRotation(it.second.Y); bone->setRotation(it.second.Y);
@ -1520,7 +1511,7 @@ void GenericCAO::updateBonePosition()
// search through bones to find mistakenly rotated bones due to bug in Irrlicht // search through bones to find mistakenly rotated bones due to bug in Irrlicht
for (u32 i = 0; i < m_animated_meshnode->getJointCount(); ++i) { for (u32 i = 0; i < m_animated_meshnode->getJointCount(); ++i) {
irr::scene::IBoneSceneNode *bone = m_animated_meshnode->getJointNode(i); scene::IBoneSceneNode *bone = m_animated_meshnode->getJointNode(i);
if (!bone) if (!bone)
continue; continue;
@ -1965,7 +1956,7 @@ void GenericCAO::updateMeshCulling()
return; return;
} }
irr::scene::ISceneNode *node = getSceneNode(); scene::ISceneNode *node = getSceneNode();
if (!node) if (!node)
return; return;

View File

@ -189,6 +189,8 @@ public:
const bool isImmortal(); const bool isImmortal();
inline const ObjectProperties &getProperties() const { return m_prop; }
scene::ISceneNode *getSceneNode() const; scene::ISceneNode *getSceneNode() const;
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const; scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const;
@ -260,7 +262,7 @@ public:
void removeFromScene(bool permanent); void removeFromScene(bool permanent);
void addToScene(ITextureSource *tsrc); void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr);
inline void expireVisuals() inline void expireVisuals()
{ {

View File

@ -60,18 +60,16 @@ static constexpr u16 quad_indices[] = {0, 1, 2, 2, 3, 0};
const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike"; const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike";
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output) MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
scene::IMeshManipulator *mm):
data(input),
collector(output),
nodedef(data->m_client->ndef()),
meshmanip(mm),
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE)
{ {
data = input;
collector = output;
nodedef = data->m_client->ndef();
meshmanip = RenderingEngine::get_scene_manager()->getMeshManipulator();
enable_mesh_cache = g_settings->getBool("enable_mesh_cache") && enable_mesh_cache = g_settings->getBool("enable_mesh_cache") &&
!data->m_smooth_lighting; // Mesh cache is not supported with smooth lighting !data->m_smooth_lighting; // Mesh cache is not supported with smooth lighting
blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
} }
void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special) void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special)
@ -968,7 +966,7 @@ void MapblockMeshGenerator::drawPlantlike()
draw_style = PLANT_STYLE_CROSS; draw_style = PLANT_STYLE_CROSS;
scale = BS / 2 * f->visual_scale; scale = BS / 2 * f->visual_scale;
offset = v3f(0, 0, 0); offset = v3f(0, 0, 0);
rotate_degree = 0; rotate_degree = 0.0f;
random_offset_Y = false; random_offset_Y = false;
face_num = 0; face_num = 0;
plant_height = 1.0; plant_height = 1.0;
@ -988,7 +986,8 @@ void MapblockMeshGenerator::drawPlantlike()
break; break;
case CPT2_DEGROTATE: case CPT2_DEGROTATE:
rotate_degree = n.param2 * 2; case CPT2_COLORED_DEGROTATE:
rotate_degree = 1.5f * n.getDegRotate(nodedef);
break; break;
case CPT2_LEVELED: case CPT2_LEVELED:
@ -1343,6 +1342,7 @@ void MapblockMeshGenerator::drawMeshNode()
u8 facedir = 0; u8 facedir = 0;
scene::IMesh* mesh; scene::IMesh* mesh;
bool private_mesh; // as a grab/drop pair is not thread-safe bool private_mesh; // as a grab/drop pair is not thread-safe
int degrotate = 0;
if (f->param_type_2 == CPT2_FACEDIR || if (f->param_type_2 == CPT2_FACEDIR ||
f->param_type_2 == CPT2_COLORED_FACEDIR) { f->param_type_2 == CPT2_COLORED_FACEDIR) {
@ -1354,9 +1354,12 @@ void MapblockMeshGenerator::drawMeshNode()
facedir = n.getWallMounted(nodedef); facedir = n.getWallMounted(nodedef);
if (!enable_mesh_cache) if (!enable_mesh_cache)
facedir = wallmounted_to_facedir[facedir]; facedir = wallmounted_to_facedir[facedir];
} else if (f->param_type_2 == CPT2_DEGROTATE ||
f->param_type_2 == CPT2_COLORED_DEGROTATE) {
degrotate = n.getDegRotate(nodedef);
} }
if (!data->m_smooth_lighting && f->mesh_ptr[facedir]) { if (!data->m_smooth_lighting && f->mesh_ptr[facedir] && !degrotate) {
// use cached meshes // use cached meshes
private_mesh = false; private_mesh = false;
mesh = f->mesh_ptr[facedir]; mesh = f->mesh_ptr[facedir];
@ -1364,7 +1367,10 @@ void MapblockMeshGenerator::drawMeshNode()
// no cache, clone and rotate mesh // no cache, clone and rotate mesh
private_mesh = true; private_mesh = true;
mesh = cloneMesh(f->mesh_ptr[0]); mesh = cloneMesh(f->mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh, facedir); if (facedir)
rotateMeshBy6dFacedir(mesh, facedir);
else if (degrotate)
rotateMeshXZby(mesh, 1.5f * degrotate);
recalculateBoundingBox(mesh); recalculateBoundingBox(mesh);
meshmanip->recalculateNormals(mesh, true, false); meshmanip->recalculateNormals(mesh, true, false);
} else } else

View File

@ -139,7 +139,7 @@ public:
// plantlike-specific // plantlike-specific
PlantlikeStyle draw_style; PlantlikeStyle draw_style;
v3f offset; v3f offset;
int rotate_degree; float rotate_degree;
bool random_offset_Y; bool random_offset_Y;
int face_num; int face_num;
float plant_height; float plant_height;
@ -172,7 +172,8 @@ public:
void drawNode(); void drawNode();
public: public:
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output); MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
scene::IMeshManipulator *mm);
void generate(); void generate();
void renderSingle(content_t node, u8 param2 = 0x00); void renderSingle(content_t node, u8 param2 = 0x00);
}; };

View File

@ -56,7 +56,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) :
readSettings(); readSettings();
if (m_currentMode == FM_Standard) { if (m_currentMode != FM_Simple) {
g_settings->registerChangedCallback("font_size", font_setting_changed, NULL); g_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_bold", font_setting_changed, NULL); g_settings->registerChangedCallback("font_bold", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_italic", font_setting_changed, NULL); g_settings->registerChangedCallback("font_italic", font_setting_changed, NULL);
@ -66,12 +66,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) :
g_settings->registerChangedCallback("font_path_bolditalic", font_setting_changed, NULL); g_settings->registerChangedCallback("font_path_bolditalic", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL); g_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL); g_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL);
}
else if (m_currentMode == FM_Fallback) {
g_settings->registerChangedCallback("fallback_font_size", font_setting_changed, NULL);
g_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL); g_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL);
g_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed, NULL);
g_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed, NULL);
} }
g_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL); g_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
@ -101,6 +96,11 @@ void FontEngine::cleanCache()
/******************************************************************************/ /******************************************************************************/
irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec) irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
{
return getFont(spec, false);
}
irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec, bool may_fail)
{ {
if (spec.mode == FM_Unspecified) { if (spec.mode == FM_Unspecified) {
spec.mode = m_currentMode; spec.mode = m_currentMode;
@ -112,6 +112,10 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
// Support for those could be added, but who cares? // Support for those could be added, but who cares?
spec.bold = false; spec.bold = false;
spec.italic = false; spec.italic = false;
} else if (spec.mode == _FM_Fallback) {
// Fallback font doesn't support these either
spec.bold = false;
spec.italic = false;
} }
// Fallback to default size // Fallback to default size
@ -130,6 +134,13 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
else else
font = initFont(spec); font = initFont(spec);
if (!font && !may_fail) {
errorstream << "Minetest cannot continue without a valid font. "
"Please correct the 'font_path' setting or install the font "
"file in the proper location." << std::endl;
abort();
}
m_font_cache[spec.getHash()][spec.size] = font; m_font_cache[spec.getHash()][spec.size] = font;
return font; return font;
@ -204,20 +215,9 @@ unsigned int FontEngine::getFontSize(FontMode mode)
void FontEngine::readSettings() void FontEngine::readSettings()
{ {
if (USE_FREETYPE && g_settings->getBool("freetype")) { if (USE_FREETYPE && g_settings->getBool("freetype")) {
m_default_size[FM_Standard] = g_settings->getU16("font_size"); m_default_size[FM_Standard] = g_settings->getU16("font_size");
m_default_size[FM_Fallback] = g_settings->getU16("fallback_font_size"); m_default_size[_FM_Fallback] = g_settings->getU16("font_size");
m_default_size[FM_Mono] = g_settings->getU16("mono_font_size"); m_default_size[FM_Mono] = g_settings->getU16("mono_font_size");
/*~ DO NOT TRANSLATE THIS LITERALLY!
This is a special string. Put either "no" or "yes"
into the translation field (literally).
Choose "yes" if the language requires use of the fallback
font, "no" otherwise.
The fallback font is (normally) required for languages with
non-Latin script, like Chinese.
When in doubt, test your translation. */
m_currentMode = is_yes(gettext("needs_fallback_font")) ?
FM_Fallback : FM_Standard;
m_default_bold = g_settings->getBool("font_bold"); m_default_bold = g_settings->getBool("font_bold");
m_default_italic = g_settings->getBool("font_italic"); m_default_italic = g_settings->getBool("font_italic");
@ -271,18 +271,8 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
assert(spec.size != FONT_SIZE_UNSPECIFIED); assert(spec.size != FONT_SIZE_UNSPECIFIED);
std::string setting_prefix = ""; std::string setting_prefix = "";
if (spec.mode == FM_Mono)
switch (spec.mode) { setting_prefix = "mono_";
case FM_Fallback:
setting_prefix = "fallback_";
break;
case FM_Mono:
case FM_SimpleMono:
setting_prefix = "mono_";
break;
default:
break;
}
std::string setting_suffix = ""; std::string setting_suffix = "";
if (spec.bold) if (spec.bold)
@ -305,38 +295,41 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha", g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha",
font_shadow_alpha); font_shadow_alpha);
std::string wanted_font_path; std::string path_setting;
wanted_font_path = g_settings->get(setting_prefix + "font_path" + setting_suffix); if (spec.mode == _FM_Fallback)
path_setting = "fallback_font_path";
else
path_setting = setting_prefix + "font_path" + setting_suffix;
std::string fallback_settings[] = { std::string fallback_settings[] = {
wanted_font_path, g_settings->get(path_setting),
g_settings->get("fallback_font_path"), Settings::getLayer(SL_DEFAULTS)->get(path_setting)
Settings::getLayer(SL_DEFAULTS)->get(setting_prefix + "font_path")
}; };
#if USE_FREETYPE #if USE_FREETYPE
for (const std::string &font_path : fallback_settings) { for (const std::string &font_path : fallback_settings) {
irr::gui::IGUIFont *font = gui::CGUITTFont::createTTFont(m_env, gui::CGUITTFont *font = gui::CGUITTFont::createTTFont(m_env,
font_path.c_str(), size, true, true, font_shadow, font_path.c_str(), size, true, true, font_shadow,
font_shadow_alpha); font_shadow_alpha);
if (font) if (!font) {
return font; errorstream << "FontEngine: Cannot load '" << font_path <<
errorstream << "FontEngine: Cannot load '" << font_path <<
"'. Trying to fall back to another path." << std::endl; "'. Trying to fall back to another path." << std::endl;
continue;
}
if (spec.mode != _FM_Fallback) {
FontSpec spec2(spec);
spec2.mode = _FM_Fallback;
font->setFallback(getFont(spec2, true));
}
return font;
} }
// give up
errorstream << "minetest can not continue without a valid font. "
"Please correct the 'font_path' setting or install the font "
"file in the proper location" << std::endl;
#else #else
errorstream << "FontEngine: Tried to load freetype fonts but Minetest was" errorstream << "FontEngine: Tried to load TTF font but Minetest was"
" not compiled with that library." << std::endl; " compiled without Freetype." << std::endl;
#endif #endif
abort(); return nullptr;
} }
/** initialize a font without freetype */ /** initialize a font without freetype */

View File

@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
enum FontMode : u8 { enum FontMode : u8 {
FM_Standard = 0, FM_Standard = 0,
FM_Mono, FM_Mono,
FM_Fallback, _FM_Fallback, // do not use directly
FM_Simple, FM_Simple,
FM_SimpleMono, FM_SimpleMono,
FM_MaxMode, FM_MaxMode,
@ -47,7 +47,7 @@ struct FontSpec {
bold(bold), bold(bold),
italic(italic) {} italic(italic) {}
u16 getHash() u16 getHash() const
{ {
return (mode << 2) | (static_cast<u8>(bold) << 1) | static_cast<u8>(italic); return (mode << 2) | (static_cast<u8>(bold) << 1) | static_cast<u8>(italic);
} }
@ -132,10 +132,12 @@ public:
void readSettings(); void readSettings();
private: private:
irr::gui::IGUIFont *getFont(FontSpec spec, bool may_fail);
/** update content of font cache in case of a setting change made it invalid */ /** update content of font cache in case of a setting change made it invalid */
void updateFontCache(); void updateFontCache();
/** initialize a new font */ /** initialize a new TTF font */
gui::IGUIFont *initFont(const FontSpec &spec); gui::IGUIFont *initFont(const FontSpec &spec);
/** initialize a font without freetype */ /** initialize a font without freetype */

View File

@ -153,7 +153,7 @@ Game::~Game()
delete itemdef_manager; delete itemdef_manager;
delete draw_control; delete draw_control;
extendedResourceCleanup(); clearTextureNameCache();
g_settings->deregisterChangedCallback("doubletap_jump", g_settings->deregisterChangedCallback("doubletap_jump",
&settingChangedCallback, this); &settingChangedCallback, this);
@ -191,6 +191,7 @@ Game::~Game()
bool Game::startup(bool *kill, bool Game::startup(bool *kill,
InputHandler *input, InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &start_data, const GameStartData &start_data,
std::string &error_message, std::string &error_message,
bool *reconnect, bool *reconnect,
@ -198,21 +199,21 @@ bool Game::startup(bool *kill,
{ {
// "cache" // "cache"
this->device = RenderingEngine::get_raw_device(); m_rendering_engine = rendering_engine;
device = m_rendering_engine->get_raw_device();
this->kill = kill; this->kill = kill;
this->error_message = &error_message; this->error_message = &error_message;
this->reconnect_requested = reconnect; reconnect_requested = reconnect;
this->input = input; this->input = input;
this->chat_backend = chat_backend; this->chat_backend = chat_backend;
this->simple_singleplayer_mode = start_data.isSinglePlayer(); simple_singleplayer_mode = start_data.isSinglePlayer();
input->keycache.populate(); input->keycache.populate();
driver = device->getVideoDriver(); driver = device->getVideoDriver();
smgr = RenderingEngine::get_scene_manager(); smgr = m_rendering_engine->get_scene_manager();
RenderingEngine::get_scene_manager()->getParameters()-> smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
// Reinit runData // Reinit runData
runData = GameRunData(); runData = GameRunData();
@ -233,7 +234,7 @@ bool Game::startup(bool *kill,
if (!createClient(start_data)) if (!createClient(start_data))
return false; return false;
RenderingEngine::initialize(client, hud); m_rendering_engine->initialize(client, hud);
return true; return true;
} }
@ -250,7 +251,7 @@ void Game::run()
Profiler::GraphValues dummyvalues; Profiler::GraphValues dummyvalues;
g_profiler->graphGet(dummyvalues); g_profiler->graphGet(dummyvalues);
draw_times.last_time = RenderingEngine::get_timer_time(); draw_times.last_time = m_rendering_engine->get_timer_time();
set_light_table(g_settings->getFloat("display_gamma")); set_light_table(g_settings->getFloat("display_gamma"));
@ -262,12 +263,12 @@ void Game::run()
irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screen_w"), irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screen_w"),
g_settings->getU16("screen_h")); g_settings->getU16("screen_h"));
while (RenderingEngine::run() while (m_rendering_engine->run()
&& !(*kill || g_gamecallback->shutdown_requested && !(*kill || g_gamecallback->shutdown_requested
|| (server && server->isShutdownRequested()))) { || (server && server->isShutdownRequested()))) {
const irr::core::dimension2d<u32> &current_screen_size = const irr::core::dimension2d<u32> &current_screen_size =
RenderingEngine::get_video_driver()->getScreenSize(); m_rendering_engine->get_video_driver()->getScreenSize();
// Verify if window size has changed and save it if it's the case // Verify if window size has changed and save it if it's the case
// Ensure evaluating settings->getBool after verifying screensize // Ensure evaluating settings->getBool after verifying screensize
// First condition is cheaper // First condition is cheaper
@ -280,7 +281,7 @@ void Game::run()
} }
// Calculate dtime = // Calculate dtime =
// RenderingEngine::run() from this iteration // m_rendering_engine->run() from this iteration
// + Sleep time until the wanted FPS are reached // + Sleep time until the wanted FPS are reached
limitFps(&draw_times, &dtime); limitFps(&draw_times, &dtime);
@ -329,7 +330,7 @@ void Game::run()
void Game::shutdown() void Game::shutdown()
{ {
RenderingEngine::finalize(); m_rendering_engine->finalize();
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8
if (g_settings->get("3d_mode") == "pageflip") { if (g_settings->get("3d_mode") == "pageflip") {
driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS); driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
@ -488,7 +489,7 @@ bool Game::createClient(const GameStartData &start_data)
{ {
showOverlayMessage(N_("Creating client..."), 0, 10); showOverlayMessage(N_("Creating client..."), 0, 10);
draw_control = new MapDrawControl; draw_control = new MapDrawControl();
if (!draw_control) if (!draw_control)
return false; return false;
@ -529,7 +530,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Camera /* Camera
*/ */
camera = new Camera(*draw_control, client); camera = new Camera(*draw_control, client, m_rendering_engine);
if (!camera->successfullyCreated(*error_message)) if (!camera->successfullyCreated(*error_message))
return false; return false;
client->setCamera(camera); client->setCamera(camera);
@ -541,7 +542,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Skybox /* Skybox
*/ */
sky = new Sky(-1, texture_src, shader_src); sky = new Sky(-1, m_rendering_engine, texture_src, shader_src);
scsf->setSky(sky); scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop skybox = NULL; // This is used/set later on in the main run loop
@ -563,16 +564,28 @@ bool Game::createClient(const GameStartData &start_data)
std::wstring str = utf8_to_wide(PROJECT_NAME_C); std::wstring str = utf8_to_wide(PROJECT_NAME_C);
str += L" "; str += L" ";
str += utf8_to_wide(g_version_hash); str += utf8_to_wide(g_version_hash);
{
const wchar_t *text = nullptr;
if (simple_singleplayer_mode)
text = wgettext("Singleplayer");
else
text = wgettext("Multiplayer");
str += L" [";
str += text;
str += L"]";
delete text;
}
str += L" ["; str += L" [";
str += L"Minetest Hackclient"; str += L"Minetest Hackclient";
str += L"]"; str += L"]";
device->setWindowCaption(str.c_str()); device->setWindowCaption(str.c_str());
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
player->hurt_tilt_timer = 0; player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0; player->hurt_tilt_strength = 0;
hud = new Hud(guienv, client, player, &player->inventory); hud = new Hud(client, player, &player->inventory);
mapper = client->getMinimap(); mapper = client->getMinimap();
@ -663,7 +676,7 @@ bool Game::connectToServer(const GameStartData &start_data,
start_data.password, start_data.address, start_data.password, start_data.address,
*draw_control, texture_src, shader_src, *draw_control, texture_src, shader_src,
itemdef_manager, nodedef_manager, sound, eventmgr, itemdef_manager, nodedef_manager, sound, eventmgr,
connect_address.isIPv6(), m_game_ui.get()); m_rendering_engine, connect_address.isIPv6(), m_game_ui.get());
client->m_simple_singleplayer_mode = simple_singleplayer_mode; client->m_simple_singleplayer_mode = simple_singleplayer_mode;
@ -685,9 +698,9 @@ bool Game::connectToServer(const GameStartData &start_data,
f32 dtime; f32 dtime;
f32 wait_time = 0; // in seconds f32 wait_time = 0; // in seconds
fps_control.last_time = RenderingEngine::get_timer_time(); fps_control.last_time = m_rendering_engine->get_timer_time();
while (RenderingEngine::run()) { while (m_rendering_engine->run()) {
limitFps(&fps_control, &dtime); limitFps(&fps_control, &dtime);
@ -724,7 +737,7 @@ bool Game::connectToServer(const GameStartData &start_data,
if (client->m_is_registration_confirmation_state) { if (client->m_is_registration_confirmation_state) {
if (registration_confirmation_shown) { if (registration_confirmation_shown) {
// Keep drawing the GUI // Keep drawing the GUI
RenderingEngine::draw_menu_scene(guienv, dtime, true); m_rendering_engine->draw_menu_scene(guienv, dtime, true);
} else { } else {
registration_confirmation_shown = true; registration_confirmation_shown = true;
(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1, (new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
@ -734,7 +747,7 @@ bool Game::connectToServer(const GameStartData &start_data,
} else { } else {
wait_time += dtime; wait_time += dtime;
// Only time out if we aren't waiting for the server we started // Only time out if we aren't waiting for the server we started
if (!start_data.local_server && !start_data.isSinglePlayer() && wait_time > 10) { if (!start_data.address.empty() && wait_time > 10) {
*error_message = "Connection timed out."; *error_message = "Connection timed out.";
errorstream << *error_message << std::endl; errorstream << *error_message << std::endl;
break; break;
@ -760,9 +773,9 @@ bool Game::getServerContent(bool *aborted)
FpsControl fps_control = { 0 }; FpsControl fps_control = { 0 };
f32 dtime; // in seconds f32 dtime; // in seconds
fps_control.last_time = RenderingEngine::get_timer_time(); fps_control.last_time = m_rendering_engine->get_timer_time();
while (RenderingEngine::run()) { while (m_rendering_engine->run()) {
limitFps(&fps_control, &dtime); limitFps(&fps_control, &dtime);
@ -800,13 +813,13 @@ bool Game::getServerContent(bool *aborted)
if (!client->itemdefReceived()) { if (!client->itemdefReceived()) {
const wchar_t *text = wgettext("Item definitions..."); const wchar_t *text = wgettext("Item definitions...");
progress = 25; progress = 25;
RenderingEngine::draw_load_screen(text, guienv, texture_src, m_rendering_engine->draw_load_screen(text, guienv, texture_src,
dtime, progress); dtime, progress);
delete[] text; delete[] text;
} else if (!client->nodedefReceived()) { } else if (!client->nodedefReceived()) {
const wchar_t *text = wgettext("Node definitions..."); const wchar_t *text = wgettext("Node definitions...");
progress = 30; progress = 30;
RenderingEngine::draw_load_screen(text, guienv, texture_src, m_rendering_engine->draw_load_screen(text, guienv, texture_src,
dtime, progress); dtime, progress);
delete[] text; delete[] text;
} else { } else {
@ -833,7 +846,7 @@ bool Game::getServerContent(bool *aborted)
} }
progress = 30 + client->mediaReceiveProgress() * 35 + 0.5; progress = 30 + client->mediaReceiveProgress() * 35 + 0.5;
RenderingEngine::draw_load_screen(utf8_to_wide(message.str()), guienv, m_rendering_engine->draw_load_screen(utf8_to_wide(message.str()), guienv,
texture_src, dtime, progress); texture_src, dtime, progress);
} }
} }
@ -1150,6 +1163,8 @@ void Game::processKeyInput()
toggleCinematic(); toggleCinematic();
} else if (wasKeyDown(KeyType::SCREENSHOT)) { } else if (wasKeyDown(KeyType::SCREENSHOT)) {
client->makeScreenshot(); client->makeScreenshot();
} else if (wasKeyDown(KeyType::TOGGLE_BLOCK_BOUNDS)) {
hud->toggleBlockBounds();
} else if (wasKeyDown(KeyType::TOGGLE_HUD)) { } else if (wasKeyDown(KeyType::TOGGLE_HUD)) {
m_game_ui->toggleHud(); m_game_ui->toggleHud();
} else if (wasKeyDown(KeyType::MINIMAP)) { } else if (wasKeyDown(KeyType::MINIMAP)) {
@ -1264,8 +1279,8 @@ void Game::openInventory()
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) { || !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
TextDest *txt_dst = new TextDestPlayerInventory(client); TextDest *txt_dst = new TextDestPlayerInventory(client);
auto *&formspec = m_game_ui->updateFormspec(""); auto *&formspec = m_game_ui->updateFormspec("");
GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src, GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
txt_dst, client->getFormspecPrepend(), sound); &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFormSpec(fs_src->getForm(), inventoryloc); formspec->setFormSpec(fs_src->getForm(), inventoryloc);
} }
@ -1838,14 +1853,18 @@ void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation
// Damage flash and hurt tilt are not used at death // Damage flash and hurt tilt are not used at death
if (client->getHP() > 0) { if (client->getHP() > 0) {
runData.damage_flash += 95.0f + 3.2f * event->player_damage.amount;
runData.damage_flash = MYMIN(runData.damage_flash, 127.0f);
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
f32 hp_max = player->getCAO() ?
player->getCAO()->getProperties()->hp_max : PLAYER_MAX_HP_DEFAULT;
f32 damage_ratio = event->player_damage.amount / hp_max;
runData.damage_flash += 95.0f + 64.f * damage_ratio;
runData.damage_flash = MYMIN(runData.damage_flash, 127.0f);
player->hurt_tilt_timer = 1.5f; player->hurt_tilt_timer = 1.5f;
player->hurt_tilt_strength = player->hurt_tilt_strength =
rangelim(event->player_damage.amount / 4.0f, 1.0f, 4.0f); rangelim(damage_ratio * 5.0f, 1.0f, 4.0f);
} }
// Play damage sound // Play damage sound
@ -1889,8 +1908,8 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
new TextDestPlayerInventory(client, *(event->show_formspec.formname)); new TextDestPlayerInventory(client, *(event->show_formspec.formname));
auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname)); auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname));
GUIFormSpecMenu::create(formspec, client, &input->joystick, GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
fs_src, txt_dst, client->getFormspecPrepend(), sound); &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
} }
delete event->show_formspec.formspec; delete event->show_formspec.formspec;
@ -1909,7 +1928,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec); FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
LocalFormspecHandler *txt_dst = LocalFormspecHandler *txt_dst =
new LocalFormspecHandler(*event->show_formspec.formname, client); new LocalFormspecHandler(*event->show_formspec.formname, client);
GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick, GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend(), sound); fs_src, txt_dst, client->getFormspecPrepend(), sound);
} }
@ -2075,6 +2094,7 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam)
"custom" "custom"
); );
} }
delete event->set_sky; delete event->set_sky;
} }
@ -2607,8 +2627,8 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client); TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
auto *&formspec = m_game_ui->updateFormspec(""); auto *&formspec = m_game_ui->updateFormspec("");
GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src, GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
txt_dst, client->getFormspecPrepend(), sound); &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFormSpec(meta->getString("formspec"), inventoryloc); formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
return false; return false;
@ -3170,7 +3190,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
} catch (SettingNotFoundException) { } catch (SettingNotFoundException) {
} }
#endif #endif
RenderingEngine::draw_scene(skycolor, m_game_ui->m_flags.show_hud, m_rendering_engine->draw_scene(skycolor, m_game_ui->m_flags.show_hud,
m_game_ui->m_flags.show_minimap, draw_wield_tool, draw_crosshair); m_game_ui->m_flags.show_minimap, draw_wield_tool, draw_crosshair);
/* /*
@ -3309,7 +3329,7 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds) void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds)
{ {
const wchar_t *wmsg = wgettext(msg); const wchar_t *wmsg = wgettext(msg);
RenderingEngine::draw_load_screen(wmsg, guienv, texture_src, dtime, percent, m_rendering_engine->draw_load_screen(wmsg, guienv, texture_src, dtime, percent,
draw_clouds); draw_clouds);
delete[] wmsg; delete[] wmsg;
} }
@ -3392,27 +3412,6 @@ bool Game::wasKeyReleased(GameKeyType k)
****************************************************************************/ ****************************************************************************/
/****************************************************************************/ /****************************************************************************/
void Game::extendedResourceCleanup()
{
// Extended resource accounting
infostream << "Irrlicht resources after cleanup:" << std::endl;
infostream << "\tRemaining meshes : "
<< RenderingEngine::get_mesh_cache()->getMeshCount() << std::endl;
infostream << "\tRemaining textures : "
<< driver->getTextureCount() << std::endl;
for (unsigned int i = 0; i < driver->getTextureCount(); i++) {
irr::video::ITexture *texture = driver->getTextureByIndex(i);
infostream << "\t\t" << i << ":" << texture->getName().getPath().c_str()
<< std::endl;
}
clearTextureNameCache();
infostream << "\tRemaining materials: "
<< driver-> getMaterialRendererCount()
<< " (note: irrlicht doesn't support removing renderers)" << std::endl;
}
void Game::showDeathFormspec() void Game::showDeathFormspec()
{ {
static std::string formspec_str = static std::string formspec_str =
@ -3430,8 +3429,8 @@ void Game::showDeathFormspec()
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client); LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
auto *&formspec = m_game_ui->getFormspecGUI(); auto *&formspec = m_game_ui->getFormspecGUI();
GUIFormSpecMenu::create(formspec, client, &input->joystick, GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
fs_src, txt_dst, client->getFormspecPrepend(), sound); &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_respawn"); formspec->setFocus("btn_respawn");
} }
@ -3572,8 +3571,8 @@ void Game::showPauseMenu()
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU"); LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
auto *&formspec = m_game_ui->getFormspecGUI(); auto *&formspec = m_game_ui->getFormspecGUI();
GUIFormSpecMenu::create(formspec, client, &input->joystick, GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
fs_src, txt_dst, client->getFormspecPrepend(), sound); &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_continue"); formspec->setFocus("btn_continue");
formspec->doPause = true; formspec->doPause = true;
@ -3591,6 +3590,7 @@ Game *g_game;
void the_game(bool *kill, void the_game(bool *kill,
InputHandler *input, InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &start_data, const GameStartData &start_data,
std::string &error_message, std::string &error_message,
ChatBackend &chat_backend, ChatBackend &chat_backend,
@ -3607,8 +3607,8 @@ void the_game(bool *kill,
try { try {
if (game.startup(kill, input, start_data, error_message, if (game.startup(kill, input, rendering_engine, start_data,
reconnect_requested, &chat_backend)) { error_message, reconnect_requested, &chat_backend)) {
game.run(); game.run();
} }

View File

@ -76,7 +76,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string> #include <string>
class InputHandler; class InputHandler;
class ChatBackend; /* to avoid having to include chat.h */ class ChatBackend;
class RenderingEngine;
struct SubgameSpec; struct SubgameSpec;
struct GameStartData; struct GameStartData;
@ -417,12 +418,7 @@ public:
}; };
// before 1.8 there isn't a "integer interface", only float
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
typedef f32 SamplerLayer_t;
#else
typedef s32 SamplerLayer_t; typedef s32 SamplerLayer_t;
#endif
class GameGlobalShaderConstantSetter : public IShaderConstantSetter class GameGlobalShaderConstantSetter : public IShaderConstantSetter
@ -530,38 +526,20 @@ public:
float eye_position_array[3]; float eye_position_array[3];
v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition(); v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
eye_position_array[0] = epos.X;
eye_position_array[1] = epos.Y;
eye_position_array[2] = epos.Z;
#else
epos.getAs3Values(eye_position_array); epos.getAs3Values(eye_position_array);
#endif
m_eye_position_pixel.set(eye_position_array, services); m_eye_position_pixel.set(eye_position_array, services);
m_eye_position_vertex.set(eye_position_array, services); m_eye_position_vertex.set(eye_position_array, services);
if (m_client->getMinimap()) { if (m_client->getMinimap()) {
float minimap_yaw_array[3]; float minimap_yaw_array[3];
v3f minimap_yaw = m_client->getMinimap()->getYawVec(); v3f minimap_yaw = m_client->getMinimap()->getYawVec();
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
minimap_yaw_array[0] = minimap_yaw.X;
minimap_yaw_array[1] = minimap_yaw.Y;
minimap_yaw_array[2] = minimap_yaw.Z;
#else
minimap_yaw.getAs3Values(minimap_yaw_array); minimap_yaw.getAs3Values(minimap_yaw_array);
#endif
m_minimap_yaw.set(minimap_yaw_array, services); m_minimap_yaw.set(minimap_yaw_array, services);
} }
float camera_offset_array[3]; float camera_offset_array[3];
v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS); v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
camera_offset_array[0] = offset.X;
camera_offset_array[1] = offset.Y;
camera_offset_array[2] = offset.Z;
#else
offset.getAs3Values(camera_offset_array); offset.getAs3Values(camera_offset_array);
#endif
m_camera_offset_pixel.set(camera_offset_array, services); m_camera_offset_pixel.set(camera_offset_array, services);
m_camera_offset_vertex.set(camera_offset_array, services); m_camera_offset_vertex.set(camera_offset_array, services);
@ -673,6 +651,7 @@ public:
bool startup(bool *kill, bool startup(bool *kill,
InputHandler *input, InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &game_params, const GameStartData &game_params,
std::string &error_message, std::string &error_message,
bool *reconnect, bool *reconnect,
@ -682,8 +661,6 @@ public:
void run(); void run();
void shutdown(); void shutdown();
void extendedResourceCleanup();
// Basic initialisation // Basic initialisation
bool init(const std::string &map_dir, const std::string &address, bool init(const std::string &map_dir, const std::string &address,
u16 port, const SubgameSpec &gamespec); u16 port, const SubgameSpec &gamespec);
@ -881,6 +858,7 @@ public:
these items (e.g. device) these items (e.g. device)
*/ */
IrrlichtDevice *device; IrrlichtDevice *device;
RenderingEngine *m_rendering_engine;
video::IVideoDriver *driver; video::IVideoDriver *driver;
scene::ISceneManager *smgr; scene::ISceneManager *smgr;
bool *kill; bool *kill;
@ -936,6 +914,7 @@ extern Game *g_game;
void the_game(bool *kill, void the_game(bool *kill,
InputHandler *input, InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &start_data, const GameStartData &start_data,
std::string &error_message, std::string &error_message,
ChatBackend &chat_backend, ChatBackend &chat_backend,

View File

@ -55,7 +55,7 @@ void GameUI::init()
{ {
m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false, m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
false, guiroot); false, guiroot);
// First line of debug text // First line of debug text
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(), m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
core::rect<s32>(0, 0, 0, 0), false, false, guiroot); core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@ -102,7 +102,8 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
{ {
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
v3f player_position = player->getPosition(); v3f player_position = player->getPosition();
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
v2u32 screensize = RenderingEngine::getWindowSize();
bool show_coords = g_settings->getBool("coords"); bool show_coords = g_settings->getBool("coords");
@ -115,7 +116,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str()); setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str());
m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y)); m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y));
} }
m_guitext_coords->setVisible(show_coords); m_guitext_coords->setVisible(show_coords);
if (m_flags.show_debug) { if (m_flags.show_debug) {
@ -238,9 +239,9 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
{ {
// Update gui element size and position // Update gui element size and position
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); const v2u32 &window_size = RenderingEngine::getWindowSize();
s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight(); s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight();
if (m_flags.show_debug) if (m_flags.show_debug)
@ -276,7 +277,7 @@ void GameUI::updateProfiler()
core::position2di upper_left(6, 50); core::position2di upper_left(6, 50);
core::position2di lower_right = upper_left; core::position2di lower_right = upper_left;
lower_right.X += size.Width + 10; lower_right.X += size.Width + 10;
lower_right.Y += size.Height; lower_right.Y += size.Height;
m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right)); m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right));
} }

View File

@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h" #include "util/numeric.h"
#include <cstdio> #include <cstdio>
#include "client/renderingengine.h" #include "client/renderingengine.h"
#include "client/tile.h" // hasNPotSupport()
/* Maintain a static cache to store the images that correspond to textures /* Maintain a static cache to store the images that correspond to textures
* in a format that's manipulable by code. Some platforms exhibit issues * in a format that's manipulable by code. Some platforms exhibit issues
@ -102,7 +101,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
if (!g_settings->getBool("gui_scaling_filter_txr2img")) if (!g_settings->getBool("gui_scaling_filter_txr2img"))
return src; return src;
srcimg = driver->createImageFromData(src->getColorFormat(), srcimg = driver->createImageFromData(src->getColorFormat(),
src->getSize(), src->lock(), false); src->getSize(), src->lock(video::ETLM_READ_ONLY), false);
src->unlock(); src->unlock();
g_imgCache[origname] = srcimg; g_imgCache[origname] = srcimg;
} }
@ -117,7 +116,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
#if ENABLE_GLES #if ENABLE_GLES
// Some platforms are picky about textures being powers of 2, so expand // Some platforms are picky about textures being powers of 2, so expand
// the image dimensions to the next power of 2, if necessary. // the image dimensions to the next power of 2, if necessary.
if (!hasNPotSupport()) { if (!driver->queryFeature(video::EVDF_TEXTURE_NPOT)) {
video::IImage *po2img = driver->createImage(src->getColorFormat(), video::IImage *po2img = driver->createImage(src->getColorFormat(),
core::dimension2d<u32>(npot2((u32)destrect.getWidth()), core::dimension2d<u32>(npot2((u32)destrect.getWidth()),
npot2((u32)destrect.getHeight()))); npot2((u32)destrect.getHeight())));

View File

@ -45,11 +45,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define OBJECT_CROSSHAIR_LINE_SIZE 8 #define OBJECT_CROSSHAIR_LINE_SIZE 8
#define CROSSHAIR_LINE_SIZE 10 #define CROSSHAIR_LINE_SIZE 10
Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, Hud::Hud(Client *client, LocalPlayer *player,
Inventory *inventory) Inventory *inventory)
{ {
driver = RenderingEngine::get_video_driver(); driver = RenderingEngine::get_video_driver();
this->guienv = guienv;
this->client = client; this->client = client;
this->player = player; this->player = player;
this->inventory = inventory; this->inventory = inventory;
@ -315,7 +314,7 @@ bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *p
{ {
v3f w_pos = e->world_pos * BS; v3f w_pos = e->world_pos * BS;
scene::ICameraSceneNode* camera = scene::ICameraSceneNode* camera =
RenderingEngine::get_scene_manager()->getActiveCamera(); client->getSceneManager()->getActiveCamera();
w_pos -= intToFloat(camera_offset, BS); w_pos -= intToFloat(camera_offset, BS);
core::matrix4 trans = camera->getProjectionMatrix(); core::matrix4 trans = camera->getProjectionMatrix();
trans *= camera->getViewMatrix(); trans *= camera->getViewMatrix();
@ -336,22 +335,22 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
irr::gui::IGUIFont* font = g_fontengine->getFont(); irr::gui::IGUIFont* font = g_fontengine->getFont();
// Reorder elements by z_index // Reorder elements by z_index
std::vector<size_t> ids; std::vector<HudElement*> elems;
elems.reserve(player->maxHudId());
for (size_t i = 0; i != player->maxHudId(); i++) { for (size_t i = 0; i != player->maxHudId(); i++) {
HudElement *e = player->getHud(i); HudElement *e = player->getHud(i);
if (!e) if (!e)
continue; continue;
auto it = ids.begin(); auto it = elems.begin();
while (it != ids.end() && player->getHud(*it)->z_index <= e->z_index) while (it != elems.end() && (*it)->z_index <= e->z_index)
++it; ++it;
ids.insert(it, i); elems.insert(it, e);
} }
for (size_t i : ids) { for (HudElement *e : elems) {
HudElement *e = player->getHud(i);
v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5), v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
floor(e->pos.Y * (float) m_screensize.Y + 0.5)); floor(e->pos.Y * (float) m_screensize.Y + 0.5));
@ -475,7 +474,7 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
// Angle according to camera view // Angle according to camera view
v3f fore(0.f, 0.f, 1.f); v3f fore(0.f, 0.f, 1.f);
scene::ICameraSceneNode *cam = RenderingEngine::get_scene_manager()->getActiveCamera(); scene::ICameraSceneNode *cam = client->getSceneManager()->getActiveCamera();
cam->getAbsoluteTransformation().rotateVect(fore); cam->getAbsoluteTransformation().rotateVect(fore);
int angle = - fore.getHorizontalAngle().Y; int angle = - fore.getHorizontalAngle().Y;
@ -522,8 +521,8 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
client->getMinimap()->drawMinimap(rect); client->getMinimap()->drawMinimap(rect);
break; } break; }
default: default:
infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << infostream << "Hud::drawLuaElements: ignoring drawform " << e->type
" of hud element ID " << i << " due to unrecognized type" << std::endl; << " due to unrecognized type" << std::endl;
} }
} }
} }
@ -747,7 +746,7 @@ void Hud::drawHotbar(u16 playeritem) {
s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2); s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3); v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); const v2u32 &window_size = RenderingEngine::getWindowSize();
if ((float) width / (float) window_size.X <= if ((float) width / (float) window_size.X <=
g_settings->getFloat("hud_hotbar_max_width")) { g_settings->getFloat("hud_hotbar_max_width")) {
if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
@ -862,6 +861,54 @@ void Hud::drawSelectionMesh()
} }
} }
void Hud::toggleBlockBounds()
{
m_block_bounds_mode = static_cast<BlockBoundsMode>(m_block_bounds_mode + 1);
if (m_block_bounds_mode >= BLOCK_BOUNDS_MAX) {
m_block_bounds_mode = BLOCK_BOUNDS_OFF;
}
}
void Hud::drawBlockBounds()
{
if (m_block_bounds_mode == BLOCK_BOUNDS_OFF) {
return;
}
video::SMaterial old_material = driver->getMaterial2D();
driver->setMaterial(m_selection_material);
v3s16 pos = player->getStandingNodePos();
v3s16 blockPos(
floorf((float) pos.X / MAP_BLOCKSIZE),
floorf((float) pos.Y / MAP_BLOCKSIZE),
floorf((float) pos.Z / MAP_BLOCKSIZE)
);
v3f offset = intToFloat(client->getCamera()->getOffset(), BS);
s8 radius = m_block_bounds_mode == BLOCK_BOUNDS_ALL ? 2 : 0;
v3f halfNode = v3f(BS, BS, BS) / 2.0f;
for (s8 x = -radius; x <= radius; x++)
for (s8 y = -radius; y <= radius; y++)
for (s8 z = -radius; z <= radius; z++) {
v3s16 blockOffset(x, y, z);
aabb3f box(
intToFloat((blockPos + blockOffset) * MAP_BLOCKSIZE, BS) - offset - halfNode,
intToFloat(((blockPos + blockOffset) * MAP_BLOCKSIZE) + (MAP_BLOCKSIZE - 1), BS) - offset + halfNode
);
driver->draw3DBox(box, video::SColor(255, 255, 0, 0));
}
driver->setMaterial(old_material);
}
void Hud::updateSelectionMesh(const v3s16 &camera_offset) void Hud::updateSelectionMesh(const v3s16 &camera_offset)
{ {
m_camera_offset = camera_offset; m_camera_offset = camera_offset;
@ -908,7 +955,7 @@ void Hud::updateSelectionMesh(const v3s16 &camera_offset)
} }
void Hud::resizeHotbar() { void Hud::resizeHotbar() {
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); const v2u32 &window_size = RenderingEngine::getWindowSize();
if (m_screensize != window_size) { if (m_screensize != window_size) {
m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
@ -945,10 +992,18 @@ void drawItemStack(
return; return;
} }
const ItemDefinition &def = item.getDefinition(client->idef()); const static thread_local bool enable_animations =
ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client); g_settings->getBool("inventory_items_animations");
if (imesh && imesh->mesh) { const ItemDefinition &def = item.getDefinition(client->idef());
bool draw_overlay = false;
// Render as mesh if animated or no inventory image
if ((enable_animations && rotation_kind < IT_ROT_NONE) || def.inventory_image.empty()) {
ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
if (!imesh || !imesh->mesh)
return;
scene::IMesh *mesh = imesh->mesh; scene::IMesh *mesh = imesh->mesh;
driver->clearBuffers(video::ECBF_DEPTH); driver->clearBuffers(video::ECBF_DEPTH);
s32 delta = 0; s32 delta = 0;
@ -992,9 +1047,6 @@ void drawItemStack(
core::matrix4 matrix; core::matrix4 matrix;
matrix.makeIdentity(); matrix.makeIdentity();
static thread_local bool enable_animations =
g_settings->getBool("inventory_items_animations");
if (enable_animations) { if (enable_animations) {
float timer_f = (float) delta / 5000.f; float timer_f = (float) delta / 5000.f;
matrix.setRotationDegrees(v3f( matrix.setRotationDegrees(v3f(
@ -1040,15 +1092,29 @@ void drawItemStack(
driver->setTransform(video::ETS_PROJECTION, oldProjMat); driver->setTransform(video::ETS_PROJECTION, oldProjMat);
driver->setViewPort(oldViewPort); driver->setViewPort(oldViewPort);
// draw the inventory_overlay draw_overlay = def.type == ITEM_NODE && def.inventory_image.empty();
if (def.type == ITEM_NODE && def.inventory_image.empty() && } else { // Otherwise just draw as 2D
!def.inventory_overlay.empty()) { video::ITexture *texture = client->idef()->getInventoryTexture(def.name, client);
ITextureSource *tsrc = client->getTextureSource(); if (!texture)
video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay); return;
core::dimension2d<u32> dimens = overlay_texture->getOriginalSize(); video::SColor color =
core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height); client->idef()->getItemstackColor(item, client);
draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true); const video::SColor colors[] = { color, color, color, color };
}
draw2DImageFilterScaled(driver, texture, rect,
core::rect<s32>({0, 0}, core::dimension2di(texture->getOriginalSize())),
clip, colors, true);
draw_overlay = true;
}
// draw the inventory_overlay
if (!def.inventory_overlay.empty() && draw_overlay) {
ITextureSource *tsrc = client->getTextureSource();
video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay);
core::dimension2d<u32> dimens = overlay_texture->getOriginalSize();
core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height);
draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true);
} }
if (def.type == ITEM_TOOL && item.wear != 0) { if (def.type == ITEM_TOOL && item.wear != 0) {

View File

@ -35,14 +35,6 @@ struct ItemStack;
class Hud class Hud
{ {
public: public:
video::IVideoDriver *driver;
scene::ISceneManager *smgr;
gui::IGUIEnvironment *guienv;
Client *client;
LocalPlayer *player;
Inventory *inventory;
ITextureSource *tsrc;
video::SColor crosshair_argb; video::SColor crosshair_argb;
video::SColor selectionbox_argb; video::SColor selectionbox_argb;
@ -55,10 +47,13 @@ public:
bool pointing_at_object = false; bool pointing_at_object = false;
Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, Hud(Client *client, LocalPlayer *player,
Inventory *inventory); Inventory *inventory);
~Hud(); ~Hud();
void toggleBlockBounds();
void drawBlockBounds();
void drawHotbar(u16 playeritem); void drawHotbar(u16 playeritem);
void resizeHotbar(); void resizeHotbar();
void drawCrosshair(); void drawCrosshair();
@ -103,6 +98,12 @@ private:
void drawCompassRotate(HudElement *e, video::ITexture *texture, void drawCompassRotate(HudElement *e, video::ITexture *texture,
const core::rect<s32> &rect, int way); const core::rect<s32> &rect, int way);
Client *client = nullptr;
video::IVideoDriver *driver = nullptr;
LocalPlayer *player = nullptr;
Inventory *inventory = nullptr;
ITextureSource *tsrc = nullptr;
float m_hud_scaling; // cached minetest setting float m_hud_scaling; // cached minetest setting
float m_scale_factor; float m_scale_factor;
v3s16 m_camera_offset; v3s16 m_camera_offset;
@ -125,6 +126,14 @@ private:
scene::SMeshBuffer m_rotation_mesh_buffer; scene::SMeshBuffer m_rotation_mesh_buffer;
enum BlockBoundsMode
{
BLOCK_BOUNDS_OFF,
BLOCK_BOUNDS_CURRENT,
BLOCK_BOUNDS_ALL,
BLOCK_BOUNDS_MAX
} m_block_bounds_mode = BLOCK_BOUNDS_OFF;
enum enum
{ {
HIGHLIGHT_BOX, HIGHLIGHT_BOX,

View File

@ -19,63 +19,134 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "imagefilters.h" #include "imagefilters.h"
#include "util/numeric.h" #include "util/numeric.h"
#include <cmath> #include <cmath>
#include <cassert>
#include <vector>
// Simple 2D bitmap class with just the functionality needed here
class Bitmap {
u32 linesize, lines;
std::vector<u8> data;
static inline u32 bytepos(u32 index) { return index >> 3; }
static inline u8 bitpos(u32 index) { return index & 7; }
public:
Bitmap(u32 width, u32 height) : linesize(width), lines(height),
data(bytepos(width * height) + 1) {}
inline bool get(u32 x, u32 y) const {
u32 index = y * linesize + x;
return data[bytepos(index)] & (1 << bitpos(index));
}
inline void set(u32 x, u32 y) {
u32 index = y * linesize + x;
data[bytepos(index)] |= 1 << bitpos(index);
}
inline bool all() const {
for (u32 i = 0; i < data.size() - 1; i++) {
if (data[i] != 0xff)
return false;
}
// last byte not entirely filled
for (u8 i = 0; i < bitpos(linesize * lines); i++) {
bool value_of_bit = data.back() & (1 << i);
if (!value_of_bit)
return false;
}
return true;
}
inline void copy(Bitmap &to) const {
assert(to.linesize == linesize && to.lines == lines);
to.data = data;
}
};
/* Fill in RGB values for transparent pixels, to correct for odd colors /* Fill in RGB values for transparent pixels, to correct for odd colors
* appearing at borders when blending. This is because many PNG optimizers * appearing at borders when blending. This is because many PNG optimizers
* like to discard RGB values of transparent pixels, but when blending then * like to discard RGB values of transparent pixels, but when blending then
* with non-transparent neighbors, their RGB values will shpw up nonetheless. * with non-transparent neighbors, their RGB values will show up nonetheless.
* *
* This function modifies the original image in-place. * This function modifies the original image in-place.
* *
* Parameter "threshold" is the alpha level below which pixels are considered * Parameter "threshold" is the alpha level below which pixels are considered
* transparent. Should be 127 for 3d where alpha is threshold, but 0 for * transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF,
* 2d where alpha is blended. * 0 when alpha blending is used.
*/ */
void imageCleanTransparent(video::IImage *src, u32 threshold) void imageCleanTransparent(video::IImage *src, u32 threshold)
{ {
core::dimension2d<u32> dim = src->getDimension(); core::dimension2d<u32> dim = src->getDimension();
// Walk each pixel looking for fully transparent ones. Bitmap bitmap(dim.Width, dim.Height);
// First pass: Mark all opaque pixels
// Note: loop y around x for better cache locality. // Note: loop y around x for better cache locality.
for (u32 ctry = 0; ctry < dim.Height; ctry++) for (u32 ctry = 0; ctry < dim.Height; ctry++)
for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) { for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) {
if (src->getPixel(ctrx, ctry).getAlpha() > threshold)
bitmap.set(ctrx, ctry);
}
// Ignore opaque pixels. // Exit early if all pixels opaque
irr::video::SColor c = src->getPixel(ctrx, ctry); if (bitmap.all())
if (c.getAlpha() > threshold) return;
Bitmap newmap = bitmap;
// Then repeatedly look for transparent pixels, filling them in until
// we're finished (capped at 50 iterations).
for (u32 iter = 0; iter < 50; iter++) {
for (u32 ctry = 0; ctry < dim.Height; ctry++)
for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) {
// Skip pixels we have already processed
if (bitmap.get(ctrx, ctry))
continue; continue;
// Sample size and total weighted r, g, b values. video::SColor c = src->getPixel(ctrx, ctry);
// Sample size and total weighted r, g, b values
u32 ss = 0, sr = 0, sg = 0, sb = 0; u32 ss = 0, sr = 0, sg = 0, sb = 0;
// Walk each neighbor pixel (clipped to image bounds). // Walk each neighbor pixel (clipped to image bounds)
for (u32 sy = (ctry < 1) ? 0 : (ctry - 1); for (u32 sy = (ctry < 1) ? 0 : (ctry - 1);
sy <= (ctry + 1) && sy < dim.Height; sy++) sy <= (ctry + 1) && sy < dim.Height; sy++)
for (u32 sx = (ctrx < 1) ? 0 : (ctrx - 1); for (u32 sx = (ctrx < 1) ? 0 : (ctrx - 1);
sx <= (ctrx + 1) && sx < dim.Width; sx++) { sx <= (ctrx + 1) && sx < dim.Width; sx++) {
// Ignore pixels we haven't processed
// Ignore transparent pixels. if (!bitmap.get(sx, sy))
irr::video::SColor d = src->getPixel(sx, sy);
if (d.getAlpha() <= threshold)
continue; continue;
// Add RGB values weighted by alpha. // Add RGB values weighted by alpha IF the pixel is opaque, otherwise
u32 a = d.getAlpha(); // use full weight since we want to propagate colors.
video::SColor d = src->getPixel(sx, sy);
u32 a = d.getAlpha() <= threshold ? 255 : d.getAlpha();
ss += a; ss += a;
sr += a * d.getRed(); sr += a * d.getRed();
sg += a * d.getGreen(); sg += a * d.getGreen();
sb += a * d.getBlue(); sb += a * d.getBlue();
} }
// If we found any neighbor RGB data, set pixel to average // Set pixel to average weighted by alpha
// weighted by alpha.
if (ss > 0) { if (ss > 0) {
c.setRed(sr / ss); c.setRed(sr / ss);
c.setGreen(sg / ss); c.setGreen(sg / ss);
c.setBlue(sb / ss); c.setBlue(sb / ss);
src->setPixel(ctrx, ctry, c); src->setPixel(ctrx, ctry, c);
newmap.set(ctrx, ctry);
} }
} }
if (newmap.all())
return;
// Apply changes to bitmap for next run. This is done so we don't introduce
// a bias in color propagation in the direction pixels are processed.
newmap.copy(bitmap);
}
} }
/* Scale a region of an image into another image, using nearest-neighbor with /* Scale a region of an image into another image, using nearest-neighbor with

View File

@ -23,13 +23,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/* Fill in RGB values for transparent pixels, to correct for odd colors /* Fill in RGB values for transparent pixels, to correct for odd colors
* appearing at borders when blending. This is because many PNG optimizers * appearing at borders when blending. This is because many PNG optimizers
* like to discard RGB values of transparent pixels, but when blending then * like to discard RGB values of transparent pixels, but when blending then
* with non-transparent neighbors, their RGB values will shpw up nonetheless. * with non-transparent neighbors, their RGB values will show up nonetheless.
* *
* This function modifies the original image in-place. * This function modifies the original image in-place.
* *
* Parameter "threshold" is the alpha level below which pixels are considered * Parameter "threshold" is the alpha level below which pixels are considered
* transparent. Should be 127 for 3d where alpha is threshold, but 0 for * transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF,
* 2d where alpha is blended. * 0 when alpha blending is used.
*/ */
void imageCleanTransparent(video::IImage *src, u32 threshold); void imageCleanTransparent(video::IImage *src, u32 threshold);

View File

@ -61,6 +61,7 @@ void KeyCache::populate()
key[KeyType::DEC_VOLUME] = getKeySetting("keymap_decrease_volume"); key[KeyType::DEC_VOLUME] = getKeySetting("keymap_decrease_volume");
key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic"); key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic");
key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot"); key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot");
key[KeyType::TOGGLE_BLOCK_BOUNDS] = getKeySetting("keymap_toggle_block_bounds");
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud"); key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat"); key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog"); key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog");

View File

@ -197,7 +197,6 @@ static const struct table_key table[] = {
DEFINEKEY1(KEY_MODECHANGE, N_("IME Mode Change")) DEFINEKEY1(KEY_MODECHANGE, N_("IME Mode Change"))
DEFINEKEY1(KEY_APPS, N_("Apps")) DEFINEKEY1(KEY_APPS, N_("Apps"))
DEFINEKEY1(KEY_SLEEP, N_("Sleep")) DEFINEKEY1(KEY_SLEEP, N_("Sleep"))
#if !(IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 7 && IRRLICHT_VERSION_REVISION < 3)
DEFINEKEY1(KEY_OEM_1, "OEM 1") // KEY_OEM_[0-9] and KEY_OEM_102 are assigned to multiple DEFINEKEY1(KEY_OEM_1, "OEM 1") // KEY_OEM_[0-9] and KEY_OEM_102 are assigned to multiple
DEFINEKEY1(KEY_OEM_2, "OEM 2") // different chars (on different platforms too) and thus w/o char DEFINEKEY1(KEY_OEM_2, "OEM 2") // different chars (on different platforms too) and thus w/o char
DEFINEKEY1(KEY_OEM_3, "OEM 3") DEFINEKEY1(KEY_OEM_3, "OEM 3")
@ -208,7 +207,6 @@ static const struct table_key table[] = {
DEFINEKEY1(KEY_OEM_8, "OEM 8") DEFINEKEY1(KEY_OEM_8, "OEM 8")
DEFINEKEY1(KEY_OEM_AX, "OEM AX") DEFINEKEY1(KEY_OEM_AX, "OEM AX")
DEFINEKEY1(KEY_OEM_102, "OEM 102") DEFINEKEY1(KEY_OEM_102, "OEM 102")
#endif
DEFINEKEY1(KEY_ATTN, "Attn") DEFINEKEY1(KEY_ATTN, "Attn")
DEFINEKEY1(KEY_CRSEL, "CrSel") DEFINEKEY1(KEY_CRSEL, "CrSel")
DEFINEKEY1(KEY_EXSEL, "ExSel") DEFINEKEY1(KEY_EXSEL, "ExSel")

View File

@ -60,6 +60,7 @@ public:
DEC_VOLUME, DEC_VOLUME,
CINEMATIC, CINEMATIC,
SCREENSHOT, SCREENSHOT,
TOGGLE_BLOCK_BOUNDS,
TOGGLE_HUD, TOGGLE_HUD,
TOGGLE_CHAT, TOGGLE_CHAT,
TOGGLE_FOG, TOGGLE_FOG,

View File

@ -1140,8 +1140,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
*/ */
{ {
MapblockMeshGenerator generator(data, &collector); MapblockMeshGenerator(data, &collector,
generator.generate(); data->m_client->getSceneManager()->getMeshManipulator()).generate();
} }
/* /*

View File

@ -27,14 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <SAnimatedMesh.h> #include <SAnimatedMesh.h>
#include <IAnimatedMeshSceneNode.h> #include <IAnimatedMeshSceneNode.h>
// In Irrlicht 1.8 the signature of ITexture::lock was changed from
// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
#define MY_ETLM_READ_ONLY true
#else
#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
#endif
inline static void applyShadeFactor(video::SColor& color, float factor) inline static void applyShadeFactor(video::SColor& color, float factor)
{ {
color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255)); color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));

View File

@ -491,7 +491,8 @@ video::ITexture *Minimap::getMinimapTexture()
// Want to use texture source, to : 1 find texture, 2 cache it // Want to use texture source, to : 1 find texture, 2 cache it
video::ITexture* texture = m_tsrc->getTexture(data->mode.texture); video::ITexture* texture = m_tsrc->getTexture(data->mode.texture);
video::IImage* image = driver->createImageFromData( video::IImage* image = driver->createImageFromData(
texture->getColorFormat(), texture->getSize(), texture->lock(), true, false); texture->getColorFormat(), texture->getSize(),
texture->lock(video::ETLM_READ_ONLY), true, false);
texture->unlock(); texture->unlock();
auto dim = image->getDimension(); auto dim = image->getDimension();
@ -576,7 +577,7 @@ scene::SMeshBuffer *Minimap::getMinimapMeshBuffer()
void Minimap::drawMinimap() void Minimap::drawMinimap()
{ {
// Non hud managed minimap drawing (legacy minimap) // Non hud managed minimap drawing (legacy minimap)
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); v2u32 screensize = RenderingEngine::getWindowSize();
const u32 size = 0.25 * screensize.Y; const u32 size = 0.25 * screensize.Y;
drawMinimap(core::rect<s32>( drawMinimap(core::rect<s32>(

View File

@ -64,8 +64,8 @@ Particle::Particle(
v2f texsize, v2f texsize,
video::SColor color video::SColor color
): ):
scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), scene::ISceneNode(((Client *)gamedef)->getSceneManager()->getRootSceneNode(),
RenderingEngine::get_scene_manager()) ((Client *)gamedef)->getSceneManager())
{ {
// Misc // Misc
m_gamedef = gamedef; m_gamedef = gamedef;

View File

@ -163,6 +163,7 @@ void RenderingCore::draw3D()
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
if (!show_hud) if (!show_hud)
return; return;
hud->drawBlockBounds();
hud->drawSelectionMesh(); hud->drawSelectionMesh();
if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers) if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers)
drawTracersAndESP(); drawTracersAndESP();

View File

@ -159,7 +159,7 @@ RenderingEngine::~RenderingEngine()
s_singleton = nullptr; s_singleton = nullptr;
} }
v2u32 RenderingEngine::getWindowSize() const v2u32 RenderingEngine::_getWindowSize() const
{ {
if (core) if (core)
return core->getVirtualSize(); return core->getVirtualSize();
@ -225,6 +225,20 @@ bool RenderingEngine::print_video_modes()
return videomode_list != NULL; return videomode_list != NULL;
} }
void RenderingEngine::removeMesh(const scene::IMesh* mesh)
{
m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
}
void RenderingEngine::cleanupMeshCache()
{
auto mesh_cache = m_device->getSceneManager()->getMeshCache();
while (mesh_cache->getMeshCount() != 0) {
if (scene::IAnimatedMesh *mesh = mesh_cache->getMeshByIndex(0))
mesh_cache->removeMesh(mesh);
}
}
bool RenderingEngine::setupTopLevelWindow(const std::string &name) bool RenderingEngine::setupTopLevelWindow(const std::string &name)
{ {
// FIXME: It would make more sense for there to be a switch of some // FIXME: It would make more sense for there to be a switch of some
@ -335,6 +349,10 @@ static bool getWindowHandle(irr::video::IVideoDriver *driver, HWND &hWnd)
case video::EDT_DIRECT3D9: case video::EDT_DIRECT3D9:
hWnd = reinterpret_cast<HWND>(exposedData.D3D9.HWnd); hWnd = reinterpret_cast<HWND>(exposedData.D3D9.HWnd);
break; break;
#if ENABLE_GLES
case video::EDT_OGLES1:
case video::EDT_OGLES2:
#endif
case video::EDT_OPENGL: case video::EDT_OPENGL:
hWnd = reinterpret_cast<HWND>(exposedData.OpenGLWin32.HWnd); hWnd = reinterpret_cast<HWND>(exposedData.OpenGLWin32.HWnd);
break; break;
@ -474,11 +492,11 @@ bool RenderingEngine::setXorgWindowIconFromPath(const std::string &icon_file)
Text will be removed when the screen is drawn the next time. Text will be removed when the screen is drawn the next time.
Additionally, a progressbar can be drawn when percent is set between 0 and 100. Additionally, a progressbar can be drawn when percent is set between 0 and 100.
*/ */
void RenderingEngine::_draw_load_screen(const std::wstring &text, void RenderingEngine::draw_load_screen(const std::wstring &text,
gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime, gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime,
int percent, bool clouds) int percent, bool clouds)
{ {
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); v2u32 screensize = getWindowSize();
v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight()); v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight());
v2s32 center(screensize.X / 2, screensize.Y / 2); v2s32 center(screensize.X / 2, screensize.Y / 2);
@ -546,7 +564,7 @@ void RenderingEngine::_draw_load_screen(const std::wstring &text,
/* /*
Draws the menu scene including (optional) cloud background. Draws the menu scene including (optional) cloud background.
*/ */
void RenderingEngine::_draw_menu_scene(gui::IGUIEnvironment *guienv, void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv,
float dtime, bool clouds) float dtime, bool clouds)
{ {
bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds"); bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
@ -594,19 +612,19 @@ std::vector<irr::video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers
return drivers; return drivers;
} }
void RenderingEngine::_initialize(Client *client, Hud *hud) void RenderingEngine::initialize(Client *client, Hud *hud)
{ {
const std::string &draw_mode = g_settings->get("3d_mode"); const std::string &draw_mode = g_settings->get("3d_mode");
core.reset(createRenderingCore(draw_mode, m_device, client, hud)); core.reset(createRenderingCore(draw_mode, m_device, client, hud));
core->initialize(); core->initialize();
} }
void RenderingEngine::_finalize() void RenderingEngine::finalize()
{ {
core.reset(); core.reset();
} }
void RenderingEngine::_draw_scene(video::SColor skycolor, bool show_hud, void RenderingEngine::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)
{ {
core->draw(skycolor, show_hud, show_minimap, draw_wield_tool, draw_crosshair); core->draw(skycolor, show_hud, show_minimap, draw_wield_tool, draw_crosshair);

View File

@ -41,7 +41,6 @@ public:
RenderingEngine(IEventReceiver *eventReceiver); RenderingEngine(IEventReceiver *eventReceiver);
~RenderingEngine(); ~RenderingEngine();
v2u32 getWindowSize() const;
void setResizable(bool resize); void setResizable(bool resize);
video::IVideoDriver *getVideoDriver() { return driver; } video::IVideoDriver *getVideoDriver() { return driver; }
@ -56,13 +55,19 @@ public:
bool setWindowIcon(); bool setWindowIcon();
bool setXorgWindowIconFromPath(const std::string &icon_file); bool setXorgWindowIconFromPath(const std::string &icon_file);
static bool print_video_modes(); static bool print_video_modes();
void cleanupMeshCache();
static RenderingEngine *get_instance() { return s_singleton; } void removeMesh(const scene::IMesh* mesh);
static io::IFileSystem *get_filesystem() static v2u32 getWindowSize()
{ {
sanity_check(s_singleton && s_singleton->m_device); sanity_check(s_singleton);
return s_singleton->m_device->getFileSystem(); return s_singleton->_getWindowSize();
}
io::IFileSystem *get_filesystem()
{
return m_device->getFileSystem();
} }
static video::IVideoDriver *get_video_driver() static video::IVideoDriver *get_video_driver()
@ -71,16 +76,9 @@ public:
return s_singleton->m_device->getVideoDriver(); return s_singleton->m_device->getVideoDriver();
} }
static scene::IMeshCache *get_mesh_cache() scene::ISceneManager *get_scene_manager()
{ {
sanity_check(s_singleton && s_singleton->m_device); return m_device->getSceneManager();
return s_singleton->m_device->getSceneManager()->getMeshCache();
}
static scene::ISceneManager *get_scene_manager()
{
sanity_check(s_singleton && s_singleton->m_device);
return s_singleton->m_device->getSceneManager();
} }
static irr::IrrlichtDevice *get_raw_device() static irr::IrrlichtDevice *get_raw_device()
@ -89,70 +87,37 @@ public:
return s_singleton->m_device; return s_singleton->m_device;
} }
static u32 get_timer_time() u32 get_timer_time()
{ {
sanity_check(s_singleton && s_singleton->m_device && return m_device->getTimer()->getTime();
s_singleton->m_device->getTimer());
return s_singleton->m_device->getTimer()->getTime();
} }
static gui::IGUIEnvironment *get_gui_env() gui::IGUIEnvironment *get_gui_env()
{ {
sanity_check(s_singleton && s_singleton->m_device); return m_device->getGUIEnvironment();
return s_singleton->m_device->getGUIEnvironment();
} }
inline static void draw_load_screen(const std::wstring &text, void draw_load_screen(const std::wstring &text,
gui::IGUIEnvironment *guienv, ITextureSource *tsrc, gui::IGUIEnvironment *guienv, ITextureSource *tsrc,
float dtime = 0, int percent = 0, bool clouds = true) float dtime = 0, int percent = 0, bool clouds = true);
{
s_singleton->_draw_load_screen(
text, guienv, tsrc, dtime, percent, clouds);
}
inline static void draw_menu_scene( void draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime, bool clouds);
gui::IGUIEnvironment *guienv, float dtime, bool clouds) void draw_scene(video::SColor skycolor, bool show_hud,
{ bool show_minimap, bool draw_wield_tool, bool draw_crosshair);
s_singleton->_draw_menu_scene(guienv, dtime, clouds);
}
inline static void draw_scene(video::SColor skycolor, bool show_hud, void initialize(Client *client, Hud *hud);
bool show_minimap, bool draw_wield_tool, bool draw_crosshair) void finalize();
{
s_singleton->_draw_scene(skycolor, show_hud, show_minimap,
draw_wield_tool, draw_crosshair);
}
inline static void initialize(Client *client, Hud *hud) bool run()
{ {
s_singleton->_initialize(client, hud); return m_device->run();
}
inline static void finalize() { s_singleton->_finalize(); }
static bool run()
{
sanity_check(s_singleton && s_singleton->m_device);
return s_singleton->m_device->run();
} }
static std::vector<core::vector3d<u32>> getSupportedVideoModes(); static std::vector<core::vector3d<u32>> getSupportedVideoModes();
static std::vector<irr::video::E_DRIVER_TYPE> getSupportedVideoDrivers(); static std::vector<irr::video::E_DRIVER_TYPE> getSupportedVideoDrivers();
private: private:
void _draw_load_screen(const std::wstring &text, gui::IGUIEnvironment *guienv, v2u32 _getWindowSize() const;
ITextureSource *tsrc, float dtime = 0, int percent = 0,
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,
bool draw_wield_tool, bool draw_crosshair);
void _initialize(Client *client, Hud *hud);
void _finalize();
std::unique_ptr<RenderingCore> core; std::unique_ptr<RenderingCore> core;
irr::IrrlichtDevice *m_device = nullptr; irr::IrrlichtDevice *m_device = nullptr;

View File

@ -579,8 +579,10 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
if (use_gles) { if (use_gles) {
shaders_header << R"( shaders_header << R"(
#version 100 #version 100
)"; )";
vertex_header = R"( vertex_header = R"(
precision mediump float;
uniform highp mat4 mWorldView; uniform highp mat4 mWorldView;
uniform highp mat4 mWorldViewProj; uniform highp mat4 mWorldViewProj;
uniform mediump mat4 mTexture; uniform mediump mat4 mTexture;
@ -592,17 +594,17 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
attribute mediump vec3 inVertexNormal; attribute mediump vec3 inVertexNormal;
attribute mediump vec4 inVertexTangent; attribute mediump vec4 inVertexTangent;
attribute mediump vec4 inVertexBinormal; attribute mediump vec4 inVertexBinormal;
)"; )";
fragment_header = R"( fragment_header = R"(
precision mediump float; precision mediump float;
)"; )";
} else { } else {
shaders_header << R"( shaders_header << R"(
#version 120 #version 120
#define lowp #define lowp
#define mediump #define mediump
#define highp #define highp
)"; )";
vertex_header = R"( vertex_header = R"(
#define mWorldView gl_ModelViewMatrix #define mWorldView gl_ModelViewMatrix
#define mWorldViewProj gl_ModelViewProjectionMatrix #define mWorldViewProj gl_ModelViewProjectionMatrix
@ -615,7 +617,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
#define inVertexNormal gl_Normal #define inVertexNormal gl_Normal
#define inVertexTangent gl_MultiTexCoord1 #define inVertexTangent gl_MultiTexCoord1
#define inVertexBinormal gl_MultiTexCoord2 #define inVertexBinormal gl_MultiTexCoord2
)"; )";
} }
bool use_discard = use_gles; bool use_discard = use_gles;

View File

@ -53,10 +53,12 @@ static video::SMaterial baseMaterial()
return mat; return mat;
}; };
Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) : Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc) :
scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
RenderingEngine::get_scene_manager(), id) rendering_engine->get_scene_manager(), id)
{ {
m_seed = (u64)myrand() << 32 | myrand();
setAutomaticCulling(scene::EAC_OFF); setAutomaticCulling(scene::EAC_OFF);
m_box.MaxEdge.set(0, 0, 0); m_box.MaxEdge.set(0, 0, 0);
m_box.MinEdge.set(0, 0, 0); m_box.MinEdge.set(0, 0, 0);
@ -82,13 +84,13 @@ Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) :
// Ensures that sun and moon textures and tonemaps are correct. // Ensures that sun and moon textures and tonemaps are correct.
setSkyDefaults(); setSkyDefaults();
m_sun_texture = tsrc->isKnownSourceImage(m_sun_params.texture) ? m_sun_texture = tsrc->isKnownSourceImage(m_sun_params.texture) ?
tsrc->getTextureForMesh(m_sun_params.texture) : NULL; tsrc->getTextureForMesh(m_sun_params.texture) : nullptr;
m_moon_texture = tsrc->isKnownSourceImage(m_moon_params.texture) ? m_moon_texture = tsrc->isKnownSourceImage(m_moon_params.texture) ?
tsrc->getTextureForMesh(m_moon_params.texture) : NULL; tsrc->getTextureForMesh(m_moon_params.texture) : nullptr;
m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ? m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ?
tsrc->getTexture(m_sun_params.tonemap) : NULL; tsrc->getTexture(m_sun_params.tonemap) : nullptr;
m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ? m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ?
tsrc->getTexture(m_moon_params.tonemap) : NULL; tsrc->getTexture(m_moon_params.tonemap) : nullptr;
if (m_sun_texture) { if (m_sun_texture) {
m_materials[3] = baseMaterial(); m_materials[3] = baseMaterial();
@ -744,14 +746,14 @@ void Sky::place_sky_body(
} }
} }
void Sky::setSunTexture(std::string sun_texture, void Sky::setSunTexture(const std::string &sun_texture,
std::string sun_tonemap, ITextureSource *tsrc) const std::string &sun_tonemap, ITextureSource *tsrc)
{ {
// Ignore matching textures (with modifiers) entirely, // Ignore matching textures (with modifiers) entirely,
// but lets at least update the tonemap before hand. // but lets at least update the tonemap before hand.
m_sun_params.tonemap = sun_tonemap; m_sun_params.tonemap = sun_tonemap;
m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ? m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ?
tsrc->getTexture(m_sun_params.tonemap) : NULL; tsrc->getTexture(m_sun_params.tonemap) : nullptr;
m_materials[3].Lighting = !!m_sun_tonemap; m_materials[3].Lighting = !!m_sun_tonemap;
if (m_sun_params.texture == sun_texture) if (m_sun_params.texture == sun_texture)
@ -780,7 +782,7 @@ void Sky::setSunTexture(std::string sun_texture,
} }
} }
void Sky::setSunriseTexture(std::string sunglow_texture, void Sky::setSunriseTexture(const std::string &sunglow_texture,
ITextureSource* tsrc) ITextureSource* tsrc)
{ {
// Ignore matching textures (with modifiers) entirely. // Ignore matching textures (with modifiers) entirely.
@ -792,14 +794,14 @@ void Sky::setSunriseTexture(std::string sunglow_texture,
); );
} }
void Sky::setMoonTexture(std::string moon_texture, void Sky::setMoonTexture(const std::string &moon_texture,
std::string moon_tonemap, ITextureSource *tsrc) const std::string &moon_tonemap, ITextureSource *tsrc)
{ {
// Ignore matching textures (with modifiers) entirely, // Ignore matching textures (with modifiers) entirely,
// but lets at least update the tonemap before hand. // but lets at least update the tonemap before hand.
m_moon_params.tonemap = moon_tonemap; m_moon_params.tonemap = moon_tonemap;
m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ? m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ?
tsrc->getTexture(m_moon_params.tonemap) : NULL; tsrc->getTexture(m_moon_params.tonemap) : nullptr;
m_materials[4].Lighting = !!m_moon_tonemap; m_materials[4].Lighting = !!m_moon_tonemap;
if (m_moon_params.texture == moon_texture) if (m_moon_params.texture == moon_texture)
@ -833,7 +835,6 @@ void Sky::setStarCount(u16 star_count, bool force_update)
// Allow force updating star count at game init. // Allow force updating star count at game init.
if (m_star_params.count != star_count || force_update) { if (m_star_params.count != star_count || force_update) {
m_star_params.count = star_count; m_star_params.count = star_count;
m_seed = (u64)myrand() << 32 | myrand();
updateStars(); updateStars();
} }
} }
@ -893,7 +894,7 @@ void Sky::setSkyColors(const SkyColor &sky_color)
} }
void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint, void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
std::string use_sun_tint) const std::string &use_sun_tint)
{ {
// Change sun and moon tinting: // Change sun and moon tinting:
m_sky_params.fog_sun_tint = sun_tint; m_sky_params.fog_sun_tint = sun_tint;
@ -907,7 +908,7 @@ void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
m_default_tint = true; m_default_tint = true;
} }
void Sky::addTextureToSkybox(std::string texture, int material_id, void Sky::addTextureToSkybox(const std::string &texture, int material_id,
ITextureSource *tsrc) ITextureSource *tsrc)
{ {
// Sanity check for more than six textures. // Sanity check for more than six textures.

View File

@ -36,7 +36,7 @@ class Sky : public scene::ISceneNode
{ {
public: public:
//! constructor //! constructor
Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc); Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc);
virtual void OnRegisterSceneNode(); virtual void OnRegisterSceneNode();
@ -65,15 +65,15 @@ public:
} }
void setSunVisible(bool sun_visible) { m_sun_params.visible = sun_visible; } void setSunVisible(bool sun_visible) { m_sun_params.visible = sun_visible; }
void setSunTexture(std::string sun_texture, void setSunTexture(const std::string &sun_texture,
std::string sun_tonemap, ITextureSource *tsrc); const std::string &sun_tonemap, ITextureSource *tsrc);
void setSunScale(f32 sun_scale) { m_sun_params.scale = sun_scale; } void setSunScale(f32 sun_scale) { m_sun_params.scale = sun_scale; }
void setSunriseVisible(bool glow_visible) { m_sun_params.sunrise_visible = glow_visible; } void setSunriseVisible(bool glow_visible) { m_sun_params.sunrise_visible = glow_visible; }
void setSunriseTexture(std::string sunglow_texture, ITextureSource* tsrc); void setSunriseTexture(const std::string &sunglow_texture, ITextureSource* tsrc);
void setMoonVisible(bool moon_visible) { m_moon_params.visible = moon_visible; } void setMoonVisible(bool moon_visible) { m_moon_params.visible = moon_visible; }
void setMoonTexture(std::string moon_texture, void setMoonTexture(const std::string &moon_texture,
std::string moon_tonemap, ITextureSource *tsrc); const std::string &moon_tonemap, ITextureSource *tsrc);
void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; } void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; }
void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; } void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; }
@ -87,21 +87,21 @@ public:
void setVisible(bool visible) { m_visible = visible; } void setVisible(bool visible) { m_visible = visible; }
// Set only from set_sky API // Set only from set_sky API
void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; } void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; }
void setFallbackBgColor(const video::SColor &fallback_bg_color) void setFallbackBgColor(video::SColor fallback_bg_color)
{ {
m_fallback_bg_color = fallback_bg_color; m_fallback_bg_color = fallback_bg_color;
} }
void overrideColors(const video::SColor &bgcolor, const video::SColor &skycolor) void overrideColors(video::SColor bgcolor, video::SColor skycolor)
{ {
m_bgcolor = bgcolor; m_bgcolor = bgcolor;
m_skycolor = skycolor; m_skycolor = skycolor;
} }
void setSkyColors(const SkyColor &sky_color); void setSkyColors(const SkyColor &sky_color);
void setHorizonTint(video::SColor sun_tint, video::SColor moon_tint, void setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
std::string use_sun_tint); const std::string &use_sun_tint);
void setInClouds(bool clouds) { m_in_clouds = clouds; } void setInClouds(bool clouds) { m_in_clouds = clouds; }
void clearSkyboxTextures() { m_sky_params.textures.clear(); } void clearSkyboxTextures() { m_sky_params.textures.clear(); }
void addTextureToSkybox(std::string texture, int material_id, void addTextureToSkybox(const std::string &texture, int material_id,
ITextureSource *tsrc); ITextureSource *tsrc);
const video::SColorf &getCurrentStarColor() const { return m_star_color; } const video::SColorf &getCurrentStarColor() const { return m_star_color; }
@ -126,7 +126,7 @@ private:
} }
// Mix two colors by a given amount // Mix two colors by a given amount
video::SColor m_mix_scolor(video::SColor col1, video::SColor col2, f32 factor) static video::SColor m_mix_scolor(video::SColor col1, video::SColor col2, f32 factor)
{ {
video::SColor result = video::SColor( video::SColor result = video::SColor(
col1.getAlpha() * (1 - factor) + col2.getAlpha() * factor, col1.getAlpha() * (1 - factor) + col2.getAlpha() * factor,
@ -135,7 +135,7 @@ private:
col1.getBlue() * (1 - factor) + col2.getBlue() * factor); col1.getBlue() * (1 - factor) + col2.getBlue() * factor);
return result; return result;
} }
video::SColorf m_mix_scolorf(video::SColorf col1, video::SColorf col2, f32 factor) static video::SColorf m_mix_scolorf(video::SColorf col1, video::SColorf col2, f32 factor)
{ {
video::SColorf result = video::SColorf result =
video::SColorf(col1.r * (1 - factor) + col2.r * factor, video::SColorf(col1.r * (1 - factor) + col2.r * factor,

View File

@ -34,15 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiscalingfilter.h" #include "guiscalingfilter.h"
#include "renderingengine.h" #include "renderingengine.h"
#if ENABLE_GLES
#ifdef _IRR_COMPILE_WITH_OGLES1_
#include <GLES/gl.h>
#else
#include <GLES2/gl2.h>
#endif
#endif
/* /*
A cache from texture name to texture path A cache from texture name to texture path
*/ */
@ -427,6 +418,7 @@ private:
std::unordered_map<std::string, Palette> m_palettes; std::unordered_map<std::string, Palette> m_palettes;
// Cached settings needed for making textures from meshes // Cached settings needed for making textures from meshes
bool m_setting_mipmap;
bool m_setting_trilinear_filter; bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter; bool m_setting_bilinear_filter;
}; };
@ -447,6 +439,7 @@ TextureSource::TextureSource()
// Cache some settings // Cache some settings
// Note: Since this is only done once, the game must be restarted // Note: Since this is only done once, the game must be restarted
// for these settings to take effect // for these settings to take effect
m_setting_mipmap = g_settings->getBool("mip_map");
m_setting_trilinear_filter = g_settings->getBool("trilinear_filter"); m_setting_trilinear_filter = g_settings->getBool("trilinear_filter");
m_setting_bilinear_filter = g_settings->getBool("bilinear_filter"); m_setting_bilinear_filter = g_settings->getBool("bilinear_filter");
} }
@ -667,7 +660,7 @@ video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id)
video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id) video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id)
{ {
static thread_local bool filter_needed = static thread_local bool filter_needed =
g_settings->getBool("texture_clean_transparent") || g_settings->getBool("texture_clean_transparent") || m_setting_mipmap ||
((m_setting_trilinear_filter || m_setting_bilinear_filter) && ((m_setting_trilinear_filter || m_setting_bilinear_filter) &&
g_settings->getS32("texture_min_size") > 1); g_settings->getS32("texture_min_size") > 1);
// Avoid duplicating texture if it won't actually change // Avoid duplicating texture if it won't actually change
@ -1011,42 +1004,19 @@ video::IImage* TextureSource::generateImage(const std::string &name)
#if ENABLE_GLES #if ENABLE_GLES
static inline u16 get_GL_major_version()
{
const GLubyte *gl_version = glGetString(GL_VERSION);
return (u16) (gl_version[0] - '0');
}
/**
* Check if hardware requires npot2 aligned textures
* @return true if alignment NOT(!) requires, false otherwise
*/
bool hasNPotSupport()
{
// Only GLES2 is trusted to correctly report npot support
// Note: we cache the boolean result, the GL context will never change.
static const bool supported = get_GL_major_version() > 1 &&
glGetString(GL_EXTENSIONS) &&
strstr((char *)glGetString(GL_EXTENSIONS), "GL_OES_texture_npot");
return supported;
}
/** /**
* Check and align image to npot2 if required by hardware * Check and align image to npot2 if required by hardware
* @param image image to check for npot2 alignment * @param image image to check for npot2 alignment
* @param driver driver to use for image operations * @param driver driver to use for image operations
* @return image or copy of image aligned to npot2 * @return image or copy of image aligned to npot2
*/ */
video::IImage *Align2Npot2(video::IImage *image,
video::IImage * Align2Npot2(video::IImage * image, video::IVideoDriver *driver)
video::IVideoDriver* driver)
{ {
if (image == NULL) if (image == NULL)
return image; return image;
if (hasNPotSupport()) if (driver->queryFeature(video::EVDF_TEXTURE_NPOT))
return image; return image;
core::dimension2d<u32> dim = image->getDimension(); core::dimension2d<u32> dim = image->getDimension();
@ -1636,8 +1606,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
return false; return false;
} }
// Apply the "clean transparent" filter, if configured. // Apply the "clean transparent" filter, if needed
if (g_settings->getBool("texture_clean_transparent")) if (m_setting_mipmap || g_settings->getBool("texture_clean_transparent"))
imageCleanTransparent(baseimg, 127); imageCleanTransparent(baseimg, 127);
/* Upscale textures to user's requested minimum size. This is a trick to make /* Upscale textures to user's requested minimum size. This is a trick to make

View File

@ -134,8 +134,7 @@ public:
IWritableTextureSource *createTextureSource(); IWritableTextureSource *createTextureSource();
#if ENABLE_GLES #if ENABLE_GLES
bool hasNPotSupport(); video::IImage *Align2Npot2(video::IImage *image, video::IVideoDriver *driver);
video::IImage * Align2Npot2(video::IImage * image, irr::video::IVideoDriver* driver);
#endif #endif
enum MaterialType{ enum MaterialType{

View File

@ -294,9 +294,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
} }
material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter); material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter);
// mipmaps cause "thin black line" artifacts // mipmaps cause "thin black line" artifacts
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
material.setFlag(video::EMF_USE_MIP_MAPS, false); material.setFlag(video::EMF_USE_MIP_MAPS, false);
#endif
if (m_enable_shaders) { if (m_enable_shaders) {
material.setTexture(2, tsrc->getShaderFlagsTexture(false)); material.setTexture(2, tsrc->getShaderFlagsTexture(false));
} }
@ -309,18 +307,21 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
MeshMakeData mesh_make_data(client, false); MeshMakeData mesh_make_data(client, false);
MeshCollector collector; MeshCollector collector;
mesh_make_data.setSmoothLighting(false); mesh_make_data.setSmoothLighting(false);
MapblockMeshGenerator gen(&mesh_make_data, &collector); MapblockMeshGenerator gen(&mesh_make_data, &collector,
client->getSceneManager()->getMeshManipulator());
if (n.getParam2()) { if (n.getParam2()) {
// keep it // keep it
} else if (f.param_type_2 == CPT2_WALLMOUNTED || } else if (f.param_type_2 == CPT2_WALLMOUNTED ||
f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
if (f.drawtype == NDT_TORCHLIKE) if (f.drawtype == NDT_TORCHLIKE ||
n.setParam2(1); f.drawtype == NDT_SIGNLIKE ||
else if (f.drawtype == NDT_SIGNLIKE ||
f.drawtype == NDT_NODEBOX || f.drawtype == NDT_NODEBOX ||
f.drawtype == NDT_MESH) f.drawtype == NDT_MESH) {
n.setParam2(4); n.setParam2(4);
}
} else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) {
n.setParam2(1);
} }
gen.renderSingle(n.getContent(), n.getParam2()); gen.renderSingle(n.getContent(), n.getParam2());
@ -395,7 +396,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
case NDT_TORCHLIKE: case NDT_TORCHLIKE:
case NDT_RAILLIKE: case NDT_RAILLIKE:
case NDT_PLANTLIKE: case NDT_PLANTLIKE:
case NDT_PLANTLIKE_ROOTED:
case NDT_FLOWINGLIQUID: { case NDT_FLOWINGLIQUID: {
v3f wscale = def.wield_scale; v3f wscale = def.wield_scale;
if (f.drawtype == NDT_FLOWINGLIQUID) if (f.drawtype == NDT_FLOWINGLIQUID)
@ -411,6 +411,15 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
m_colors.emplace_back(l1.has_color, l1.color); m_colors.emplace_back(l1.has_color, l1.color);
break; break;
} }
case NDT_PLANTLIKE_ROOTED: {
setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id),
"", def.wield_scale, tsrc,
f.special_tiles[0].layers[0].animation_frame_count);
// Add color
const TileLayer &l0 = f.special_tiles[0].layers[0];
m_colors.emplace_back(l0.has_color, l0.color);
break;
}
case NDT_NORMAL: case NDT_NORMAL:
case NDT_ALLFACES: case NDT_ALLFACES:
case NDT_LIQUID: case NDT_LIQUID:
@ -530,7 +539,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
content_t id = ndef->getId(def.name); content_t id = ndef->getId(def.name);
FATAL_ERROR_IF(!g_extrusion_mesh_cache, "Extrusion mesh cache is not yet initialized"); FATAL_ERROR_IF(!g_extrusion_mesh_cache, "Extrusion mesh cache is not yet initialized");
scene::SMesh *mesh = nullptr; scene::SMesh *mesh = nullptr;
// Shading is on by default // Shading is on by default

View File

@ -671,7 +671,6 @@ void ClientInterface::UpdatePlayerList()
std::vector<session_t> clients = getClientIDs(); std::vector<session_t> clients = getClientIDs();
m_clients_names.clear(); m_clients_names.clear();
if (!clients.empty()) if (!clients.empty())
infostream<<"Players:"<<std::endl; infostream<<"Players:"<<std::endl;

View File

@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <list> #include <list>
#include <vector> #include <vector>
#include <set> #include <set>
#include <memory>
#include <mutex> #include <mutex>
class MapBlock; class MapBlock;

View File

@ -17,56 +17,11 @@ 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.
*/ */
#include <vector>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <memory>
#include "convert_json.h" #include "convert_json.h"
#include "content/mods.h"
#include "config.h"
#include "log.h"
#include "settings.h"
#include "httpfetch.h"
#include "porting.h"
Json::Value fetchJsonValue(const std::string &url,
std::vector<std::string> *extra_headers)
{
HTTPFetchRequest fetch_request;
HTTPFetchResult fetch_result;
fetch_request.url = url;
fetch_request.caller = HTTPFETCH_SYNC;
if (extra_headers != NULL)
fetch_request.extra_headers = *extra_headers;
httpfetch_sync(fetch_request, fetch_result);
if (!fetch_result.succeeded) {
return Json::Value();
}
Json::Value root;
std::istringstream stream(fetch_result.data);
Json::CharReaderBuilder builder;
builder.settings_["collectComments"] = false;
std::string errs;
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
errorstream << "URL: " << url << std::endl;
errorstream << "Failed to parse json data " << errs << std::endl;
if (fetch_result.data.size() > 100) {
errorstream << "Data (" << fetch_result.data.size()
<< " bytes) printed to warningstream." << std::endl;
warningstream << "data: \"" << fetch_result.data << "\"" << std::endl;
} else {
errorstream << "data: \"" << fetch_result.data << "\"" << std::endl;
}
return Json::Value();
}
return root;
}
void fastWriteJson(const Json::Value &value, std::ostream &to) void fastWriteJson(const Json::Value &value, std::ostream &to)
{ {

View File

@ -22,9 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <json/json.h> #include <json/json.h>
#include <ostream> #include <ostream>
Json::Value fetchJsonValue(const std::string &url,
std::vector<std::string> *extra_headers);
void fastWriteJson(const Json::Value &value, std::ostream &to); void fastWriteJson(const Json::Value &value, std::ostream &to);
std::string fastWriteJson(const Json::Value &value); std::string fastWriteJson(const Json::Value &value);

View File

@ -56,7 +56,7 @@ void set_default_settings()
settings->setDefault("client_unload_unused_data_timeout", "600"); settings->setDefault("client_unload_unused_data_timeout", "600");
settings->setDefault("client_mapblock_limit", "7500"); settings->setDefault("client_mapblock_limit", "7500");
settings->setDefault("enable_build_where_you_stand", "true"); settings->setDefault("enable_build_where_you_stand", "true");
settings->setDefault("curl_timeout", "5000"); settings->setDefault("curl_timeout", "20000");
settings->setDefault("curl_parallel_limit", "8"); settings->setDefault("curl_parallel_limit", "8");
settings->setDefault("curl_file_download_timeout", "300000"); settings->setDefault("curl_file_download_timeout", "300000");
settings->setDefault("curl_verify_cert", "true"); settings->setDefault("curl_verify_cert", "true");
@ -156,6 +156,7 @@ void set_default_settings()
settings->setDefault("keymap_increase_volume", ""); settings->setDefault("keymap_increase_volume", "");
settings->setDefault("keymap_decrease_volume", ""); settings->setDefault("keymap_decrease_volume", "");
settings->setDefault("keymap_cinematic", ""); settings->setDefault("keymap_cinematic", "");
settings->setDefault("keymap_toggle_block_bounds", "");
settings->setDefault("keymap_toggle_hud", "KEY_F1"); settings->setDefault("keymap_toggle_hud", "KEY_F1");
settings->setDefault("keymap_toggle_chat", "KEY_F2"); settings->setDefault("keymap_toggle_chat", "KEY_F2");
settings->setDefault("keymap_toggle_fog", "KEY_F3"); settings->setDefault("keymap_toggle_fog", "KEY_F3");
@ -372,12 +373,7 @@ void set_default_settings()
settings->setDefault("mono_font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-BoldItalic.ttf")); settings->setDefault("mono_font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-BoldItalic.ttf"));
settings->setDefault("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf")); settings->setDefault("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf"));
settings->setDefault("fallback_font_shadow", "1");
settings->setDefault("fallback_font_shadow_alpha", "128");
std::string font_size_str = std::to_string(TTF_DEFAULT_FONT_SIZE); std::string font_size_str = std::to_string(TTF_DEFAULT_FONT_SIZE);
settings->setDefault("fallback_font_size", font_size_str);
#else #else
settings->setDefault("freetype", "false"); settings->setDefault("freetype", "false");
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "mono_dejavu_sans")); settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "mono_dejavu_sans"));

View File

@ -727,6 +727,70 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
return true; return true;
} }
bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string &destination)
{
if (!fs->addFileArchive(filename, false, false, io::EFAT_ZIP)) {
return false;
}
sanity_check(fs->getFileArchiveCount() > 0);
/**********************************************************************/
/* WARNING this is not threadsafe!! */
/**********************************************************************/
io::IFileArchive* opened_zip = fs->getFileArchive(fs->getFileArchiveCount() - 1);
const io::IFileList* files_in_zip = opened_zip->getFileList();
unsigned int number_of_files = files_in_zip->getFileCount();
for (unsigned int i=0; i < number_of_files; i++) {
std::string fullpath = destination;
fullpath += DIR_DELIM;
fullpath += files_in_zip->getFullFileName(i).c_str();
std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
if (!files_in_zip->isDirectory(i)) {
if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
fs->removeFileArchive(fs->getFileArchiveCount()-1);
return false;
}
io::IReadFile* toread = opened_zip->createAndOpenFile(i);
FILE *targetfile = fopen(fullpath.c_str(),"wb");
if (targetfile == NULL) {
fs->removeFileArchive(fs->getFileArchiveCount()-1);
return false;
}
char read_buffer[1024];
long total_read = 0;
while (total_read < toread->getSize()) {
unsigned int bytes_read =
toread->read(read_buffer,sizeof(read_buffer));
if ((bytes_read == 0 ) ||
(fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
{
fclose(targetfile);
fs->removeFileArchive(fs->getFileArchiveCount() - 1);
return false;
}
total_read += bytes_read;
}
fclose(targetfile);
}
}
fs->removeFileArchive(fs->getFileArchiveCount() - 1);
return true;
}
bool ReadFile(const std::string &path, std::string &out) bool ReadFile(const std::string &path, std::string &out)
{ {
std::ifstream is(path, std::ios::binary | std::ios::ate); std::ifstream is(path, std::ios::binary | std::ios::ate);

View File

@ -36,6 +36,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PATH_DELIM ":" #define PATH_DELIM ":"
#endif #endif
namespace irr { namespace io {
class IFileSystem;
}}
namespace fs namespace fs
{ {
@ -125,6 +129,8 @@ const char *GetFilenameFromPath(const char *path);
bool safeWriteToFile(const std::string &path, const std::string &content); bool safeWriteToFile(const std::string &path, const std::string &content);
bool extractZipFile(irr::io::IFileSystem *fs, const char *filename, const std::string &destination);
bool ReadFile(const std::string &path, std::string &out); bool ReadFile(const std::string &path, std::string &out);
bool Rename(const std::string &from, const std::string &to); bool Rename(const std::string &from, const std::string &to);

View File

@ -30,7 +30,7 @@ FontMode CheatMenu::fontStringToEnum(std::string str)
else if (str == "FM_Mono") else if (str == "FM_Mono")
return FM_Mono; return FM_Mono;
else if (str == "FM_Fallback") else if (str == "FM_Fallback")
return FM_Fallback; return _FM_Fallback;
else if (str == "FM_Simple") else if (str == "FM_Simple")
return FM_Simple; return FM_Simple;
else if (str == "FM_SimpleMono") else if (str == "FM_SimpleMono")

View File

@ -30,7 +30,7 @@ using namespace gui;
GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment, GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle, gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
ISimpleTextureSource *tsrc, std::string item, Client *client, ISimpleTextureSource *tsrc, const std::string &item, Client *client,
bool noclip) bool noclip)
: GUIButton (environment, parent, id, rectangle, tsrc, noclip) : GUIButton (environment, parent, id, rectangle, tsrc, noclip)
{ {
@ -44,7 +44,7 @@ GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
GUIButtonItemImage *GUIButtonItemImage::addButton(IGUIEnvironment *environment, GUIButtonItemImage *GUIButtonItemImage::addButton(IGUIEnvironment *environment,
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc, const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
IGUIElement *parent, s32 id, const wchar_t *text, std::string item, IGUIElement *parent, s32 id, const wchar_t *text, const std::string &item,
Client *client) Client *client)
{ {
GUIButtonItemImage *button = new GUIButtonItemImage(environment, GUIButtonItemImage *button = new GUIButtonItemImage(environment,

View File

@ -33,13 +33,13 @@ public:
//! constructor //! constructor
GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc, s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
std::string item, Client *client, bool noclip = false); const std::string &item, Client *client, bool noclip = false);
//! Do not drop returned handle //! Do not drop returned handle
static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment, static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment,
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc, const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
IGUIElement *parent, s32 id, const wchar_t *text, std::string item, IGUIElement *parent, s32 id, const wchar_t *text,
Client *client); const std::string &item, Client *client);
private: private:
Client *m_client; Client *m_client;

View File

@ -17,6 +17,7 @@ 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.
*/ */
#include "IrrCompileConfig.h"
#include "guiChatConsole.h" #include "guiChatConsole.h"
#include "chat.h" #include "chat.h"
#include "client/client.h" #include "client/client.h"
@ -326,7 +327,6 @@ void GUIChatConsole::drawText()
tmp->draw( tmp->draw(
fragment.text, fragment.text,
destrect, destrect,
video::SColor(255, 255, 255, 255),
false, false,
false, false,
&AbsoluteClippingRect); &AbsoluteClippingRect);
@ -619,6 +619,13 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
m_chat_backend->scroll(rows); m_chat_backend->scroll(rows);
} }
} }
#if (IRRLICHT_VERSION_MT_REVISION >= 2)
else if(event.EventType == EET_STRING_INPUT_EVENT)
{
prompt.input(std::wstring(event.StringInput.Str->c_str()));
return true;
}
#endif
return Parent ? Parent->OnEvent(event) : false; return Parent ? Parent->OnEvent(event) : false;
} }

View File

@ -72,6 +72,8 @@ public:
virtual void setVisible(bool visible); virtual void setVisible(bool visible);
virtual bool acceptsIME() { return true; }
private: private:
void reformatConsole(); void reformatConsole();
void recalculateConsolePosition(); void recalculateConsolePosition();

View File

@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiEditBox.h" #include "guiEditBox.h"
#include "IrrCompileConfig.h"
#include "IGUISkin.h" #include "IGUISkin.h"
#include "IGUIEnvironment.h" #include "IGUIEnvironment.h"
#include "IGUIFont.h" #include "IGUIFont.h"
@ -216,6 +217,11 @@ bool GUIEditBox::OnEvent(const SEvent &event)
if (processMouse(event)) if (processMouse(event))
return true; return true;
break; break;
#if (IRRLICHT_VERSION_MT_REVISION >= 2)
case EET_STRING_INPUT_EVENT:
inputString(*event.StringInput.Str);
return true;
#endif
default: default:
break; break;
} }
@ -669,40 +675,45 @@ bool GUIEditBox::onKeyDelete(const SEvent &event, s32 &mark_begin, s32 &mark_end
} }
void GUIEditBox::inputChar(wchar_t c) void GUIEditBox::inputChar(wchar_t c)
{
if (c == 0)
return;
core::stringw s(&c, 1);
inputString(s);
}
void GUIEditBox::inputString(const core::stringw &str)
{ {
if (!isEnabled() || !m_writable) if (!isEnabled() || !m_writable)
return; return;
if (c != 0) { u32 len = str.size();
if (Text.size() < m_max || m_max == 0) { if (Text.size()+len <= m_max || m_max == 0) {
core::stringw s; core::stringw s;
if (m_mark_begin != m_mark_end) {
// replace marked text
s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
if (m_mark_begin != m_mark_end) { s = Text.subString(0, real_begin);
// clang-format off s.append(str);
// replace marked text s.append(Text.subString(real_end, Text.size() - real_end));
s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end; Text = s;
s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin; m_cursor_pos = real_begin + len;
} else {
s = Text.subString(0, real_begin); // append string
s.append(c); s = Text.subString(0, m_cursor_pos);
s.append(Text.subString(real_end, Text.size() - real_end)); s.append(str);
Text = s; s.append(Text.subString(m_cursor_pos,
m_cursor_pos = real_begin + 1; Text.size() - m_cursor_pos));
// clang-format on Text = s;
} else { m_cursor_pos += len;
// add new character
s = Text.subString(0, m_cursor_pos);
s.append(c);
s.append(Text.subString(m_cursor_pos,
Text.size() - m_cursor_pos));
Text = s;
++m_cursor_pos;
}
m_blink_start_time = porting::getTimeMs();
setTextMarkers(0, 0);
} }
m_blink_start_time = porting::getTimeMs();
setTextMarkers(0, 0);
} }
breakText(); breakText();
sendGuiEvent(EGET_EDITBOX_CHANGED); sendGuiEvent(EGET_EDITBOX_CHANGED);
calculateScrollPos(); calculateScrollPos();

View File

@ -138,6 +138,8 @@ public:
virtual void deserializeAttributes( virtual void deserializeAttributes(
io::IAttributes *in, io::SAttributeReadWriteOptions *options); io::IAttributes *in, io::SAttributeReadWriteOptions *options);
virtual bool acceptsIME() { return isEnabled() && m_writable; };
protected: protected:
virtual void breakText() = 0; virtual void breakText() = 0;
@ -156,6 +158,7 @@ protected:
virtual s32 getCursorPos(s32 x, s32 y) = 0; virtual s32 getCursorPos(s32 x, s32 y) = 0;
bool processKey(const SEvent &event); bool processKey(const SEvent &event);
virtual void inputString(const core::stringw &str);
virtual void inputChar(wchar_t c); virtual void inputChar(wchar_t c);
//! returns the line number that the cursor is on //! returns the line number that the cursor is on

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