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 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

View File

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

View File

@ -9,7 +9,7 @@ stages:
- deploy
variables:
IRRLICHT_TAG: "1.9.0mt0"
IRRLICHT_TAG: "1.9.0mt1"
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
@ -26,7 +26,7 @@ variables:
- cd ..
- mkdir 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 install
artifacts:
@ -171,10 +171,10 @@ build:fedora-28:
##
.generic_win_template:
image: ubuntu:bionic
image: ubuntu:focal
before_script:
- 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
- tar -xaf mingw.tar.xz -C /usr
@ -184,13 +184,13 @@ build:fedora-28:
artifacts:
expire_in: 1h
paths:
- _build/*
- build/build/*.zip
.package_win_template:
extends: .generic_win_template
stage: package
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/libstdc++*.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"}},
table = {fields = {"copy", "getn", "indexof", "insert_all", "combine"}},
math = {fields = {"hypot"}},
math = {fields = {"hypot", "round"}},
}
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
find_package(Irrlicht)
if(BUILD_CLIENT AND NOT IRRLICHT_FOUND)
message(FATAL_ERROR "Irrlicht is required to build the client, but it was not found.")
elseif(IRRLICHT_INCLUDE_DIR STREQUAL "")
message(FATAL_ERROR "Irrlicht headers are required to build the server, but none found.")
message(FATAL_ERROR "IrrlichtMt is required to build the client, but it was not found.")
elseif(NOT IRRLICHT_INCLUDE_DIR)
message(FATAL_ERROR "Irrlicht or IrrlichtMt headers are required to build the server, but none found.")
endif()
include(CheckSymbolExists)
@ -71,7 +71,7 @@ unset(HAS_FORKED_IRRLICHT CACHE)
check_symbol_exists(IRRLICHT_VERSION_MT "IrrCompileConfig.h" HAS_FORKED_IRRLICHT)
if(NOT HAS_FORKED_IRRLICHT)
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. "
"It can be found here: https://github.com/minetest/irrlicht")
if(BUILD_CLIENT)

View File

@ -1,6 +1,7 @@
FROM alpine:3.11
FROM alpine:3.13
ENV MINETEST_GAME_VERSION master
ENV IRRLICHT_VERSION master
COPY .git /usr/src/minetest/.git
COPY CMakeLists.txt /usr/src/minetest/CMakeLists.txt
@ -18,9 +19,7 @@ COPY textures /usr/src/minetest/textures
WORKDIR /usr/src/minetest
RUN apk add --no-cache git build-base irrlicht-dev cmake bzip2-dev libpng-dev \
jpeg-dev libxxf86vm-dev mesa-dev sqlite-dev libogg-dev \
libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev \
RUN apk add --no-cache git build-base cmake sqlite-dev curl-dev zlib-dev \
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 && \
rm -fr ./games/minetest_game/.git
@ -36,6 +35,9 @@ RUN git clone --recursive https://github.com/jupp0r/prometheus-cpp/ && \
make -j2 && \
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
RUN mkdir build && \
cd build && \
@ -49,7 +51,7 @@ RUN mkdir build && \
make -j2 && \
make install
FROM alpine:3.11
FROM alpine:3.13
RUN apk add --no-cache sqlite-libs curl gmp libstdc++ libgcc libpq luajit jsoncpp && \
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
---------------
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

View File

@ -133,8 +133,8 @@ Compiling
| Dependency | Version | Commentary |
|------------|---------|------------|
| GCC | 4.9+ | Can be replaced with Clang 3.4+ |
| CMake | 2.6+ | |
| Irrlicht | - | Custom version required, see https://github.com/minetest/irrlicht |
| CMake | 3.5+ | |
| IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
| SQLite3 | 3.0+ | |
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
@ -209,7 +209,7 @@ Run it:
- You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`.
- You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`.
- Debug build is slower, but gives much more useful output in a debugger.
- If you build a bare server you don't need to 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`.
### 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_FREETYPE=ON - Build with FreeType2; Allows using TTF fonts
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_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
@ -259,9 +259,9 @@ Library specific options:
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_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_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_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

View File

@ -14,7 +14,7 @@ include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
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 $(CLEAR_VARS)
@ -47,18 +47,6 @@ LOCAL_MODULE := OpenAL
LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a
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)
LOCAL_MODULE := Vorbis
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_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

View File

@ -244,6 +244,15 @@ function math.factorial(x)
return v
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)
if text ~= nil then
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))
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.
local function almost_equal(a, b)
if type(a) == "number" then

View File

@ -12,6 +12,22 @@ function vector.new(a, b, c)
return {x=0, y=0, z=0}
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)
return a.x == b.x and
a.y == b.y and
@ -41,9 +57,9 @@ end
function vector.round(v)
return {
x = math.floor(v.x + 0.5),
y = math.floor(v.y + 0.5),
z = math.floor(v.z + 0.5)
x = math.round(v.x),
y = math.round(v.y),
z = math.round(v.z)
}
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)
if has_privs then
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 delay = (minetest.get_us_time() - t_before) / 1000000
local delay = (core.get_us_time() - t_before) / 1000000
if success == false and result == nil then
core.chat_send_player(name, "-!- "..S("Invalid command usage."))
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
-- Show how much time it took to execute the command
if result then
result = result ..
minetest.colorize("#f3d2ff", " (%.5g s)"):format(delay)
result = result .. core.colorize("#f3d2ff", S(" (@1 s)",
string.format("%.5f", delay)))
else
result = minetest.colorize("#f3d2ff",
"Command execution took %.5f s"):format(delay)
result = core.colorize("#f3d2ff", S(
"Command execution took @1 s",
string.format("%.5f", delay)))
end
end
if result then
@ -166,6 +167,18 @@ core.register_chatcommand("admin", {
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", {
params = S("[<name>]"),
description = S("Show privileges of yourself or another player"),
@ -175,9 +188,7 @@ core.register_chatcommand("privs", {
if not core.player_exists(name) then
return false, S("Player @1 does not exist.", name)
end
return true, S("Privileges of @1: @2", name,
core.privs_to_string(
core.get_player_privs(name), ", "))
return true, privileges_of(name)
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")
for priv, _ in pairs(grantprivs) do
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
if not core.registered_privileges[priv] then
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
core.chat_send_player(grantname,
S("@1 granted you privileges: @2", caller,
core.privs_to_string(grantprivs, ' ')))
core.privs_to_string(grantprivs, ', ')))
end
return true, S("Privileges of @1: @2", grantname,
core.privs_to_string(
core.get_player_privs(grantname), ' '))
return true, privileges_of(grantname)
end
core.register_chatcommand("grant", {
params = S("<name> (<privilege> | all)"),
params = S("<name> (<privilege> [, <privilege2> [<...>]] | all)"),
description = S("Give privileges to player"),
func = function(name, param)
local grantname, grantprivstr = string.match(param, "([^ ]+) (.+)")
@ -265,7 +277,7 @@ core.register_chatcommand("grant", {
})
core.register_chatcommand("grantme", {
params = S("<privilege> | all"),
params = S("<privilege> [, <privilege2> [<...>]] | all"),
description = S("Grant privileges to yourself"),
func = function(name, param)
if param == "" then
@ -285,16 +297,13 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
return false, S("Player @1 does not exist.", revokename)
end
local revokeprivs = core.string_to_privs(revokeprivstr)
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
revokeprivs = privs
privs = {}
@ -304,27 +313,73 @@ local function handle_revoke_command(caller, revokename, revokeprivstr)
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
-- call the on_revoke callbacks
core.run_priv_callbacks(revokename, priv, caller, "revoke")
revokecount = revokecount + 1
end
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.privs_to_string(revokeprivs, ', ')
..') privileges from '..revokename)
if revokename ~= caller then
core.chat_send_player(revokename,
S("@1 revoked privileges from you: @2", caller,
core.privs_to_string(revokeprivs, ' ')))
core.privs_to_string(revokeprivs, ', ')))
end
return true, S("Privileges of @1: @2", revokename,
core.privs_to_string(
core.get_player_privs(revokename), ' '))
return true, privileges_of(revokename, new_privs)
end
core.register_chatcommand("revoke", {
params = S("<name> (<privilege> | all)"),
params = S("<name> (<privilege> [, <privilege2> [<...>]] | all)"),
description = S("Remove privileges from player"),
privs = {},
func = function(name, param)
@ -337,7 +392,7 @@ core.register_chatcommand("revoke", {
})
core.register_chatcommand("revokeme", {
params = S("<privilege> | all"),
params = S("<privilege> [, <privilege2> [<...>]] | all"),
description = S("Revoke privileges from yourself"),
privs = {},
func = function(name, param)

View File

@ -84,9 +84,6 @@ core.register_entity(":__builtin:falling_node", {
local textures
if def.tiles and def.tiles[1] then
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
tile = tile.name
end
@ -147,11 +144,7 @@ core.register_entity(":__builtin:falling_node", {
-- Rotate entity
if def.drawtype == "torchlike" then
if def.paramtype2 == "wallmounted" then
self.object:set_yaw(math.pi*0.25)
else
self.object:set_yaw(-math.pi*0.25)
end
self.object:set_yaw(math.pi*0.25)
elseif ((node.param2 ~= 0 or def.drawtype == "nodebox" or def.drawtype == "mesh")
and (def.wield_image == "" or def.wield_image == nil))
or def.drawtype == "signlike"
@ -165,8 +158,12 @@ core.register_entity(":__builtin:falling_node", {
if euler then
self.object:set_rotation(euler)
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
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
if def.drawtype == "nodebox" or def.drawtype == "mesh" then
if rot == 0 then
@ -208,6 +205,14 @@ core.register_entity(":__builtin:falling_node", {
end
end
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,
@ -407,7 +412,7 @@ local function convert_to_falling_node(pos, node)
obj:get_luaentity():set_node(node, metatable)
core.remove_node(pos)
return true
return true, obj
end
function core.spawn_falling_node(pos)

View File

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

View File

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

View File

@ -2,6 +2,8 @@
Empty command.=Leerer Befehl.
Invalid command: @1=Ungültiger Befehl: @1
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).
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)
@ -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
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.
@1 does not have any privileges.=@1 hat keine Privilegien.
Privileges of @1: @2=Privilegien von @1: @2
[<name>]=[<Name>]
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.
Privileges of @1: @2=Privilegien von @1: @2
<privilege>=<Privileg>
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“).
Unknown privilege!=Unbekanntes Privileg!
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. '@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
@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
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
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
Remove privileges from player=Privilegien von Spieler entfernen
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
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)
Objects cleared.=Objekte gelöscht.
Cleared all objects.=Alle Objekte gelöscht.
<name> <message>=<Name> <Nachricht>
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
[all | privs | <cmd>]=[all | privs | <Befehl>]
Get help for commands or list privileges=Hilfe für Befehle erhalten oder Privilegien auflisten
Available privileges:=Verfügbare Privilegien:
Command=Befehl
Parameters=Parameter
For more information, click on any entry in the list.=Für mehr Informationen klicken Sie auf einen beliebigen Eintrag in der Liste.
@ -194,16 +200,20 @@ Available commands: (see also: /help <cmd>)=Verfügbare Befehle: (siehe auch: /h
Close=Schließen
Privilege=Privileg
Description=Beschreibung
Available privileges:=Verfügbare Privilegien:
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<Filter>] | dump [<Filter>] | save [<Format> [<Filter>]]
Handle the profiler and profiling data=Den Profiler und Profilingdaten verwalten
Statistics written to action log.=Statistiken zum Aktionsprotokoll geschrieben.
Statistics were reset.=Statistiken wurden zurückgesetzt.
Usage: @1=Verwendung: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=Format kann entweder „txt“, „csv“, „lua“, „json“ oder „json_pretty“ sein (die Struktur kann sich in Zukunft ändern).
@1 joined the game.=@1 ist dem Spiel beigetreten.
@1 left the game.=@1 hat das Spiel verlassen.
@1 left the game (timed out).=@1 hat das Spiel verlassen (Netzwerkzeitüberschreitung).
(no description)=(keine Beschreibung)
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 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 teleport self=Kann sich selbst teleportieren
Can teleport other players=Kann andere Spieler teleportieren
@ -223,3 +233,8 @@ Unknown Item=Unbekannter Gegenstand
Air=Luft
Ignore=Ignorieren
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.
Invalid command: @1=Comando non valido: @1
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).
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)
@ -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
The administrator of this server is @1.=L'amministratore di questo server è @1.
There's no administrator named in the config file.=Non c'è nessun amministratore nel file di configurazione.
@1 does not have any privileges.=
Privileges of @1: @2=Privilegi di @1: @2
[<name>]=[<nome>]
Show privileges of yourself or another player=Mostra i privilegi propri o di un altro giocatore
Player @1 does not exist.=Il giocatore @1 non esiste.
Privileges of @1: @2=Privilegi di @1: @2
<privilege>=<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).
Unknown privilege!=Privilegio sconosciuto!
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. '@1' only allows you to grant: @2=
Unknown privilege: @1=Privilegio sconosciuto: @1
@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
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ǝ
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
Remove privileges from player=Rimuove privilegi dal giocatore
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
[all | privs | <cmd>]=[all | privs | <comando>]
Get help for commands or list privileges=Richiama la finestra d'aiuto dei comandi o dei privilegi
Available privileges:=Privilegi disponibili:
Command=Comando
Parameters=Parametri
For more information, click on any entry in the list.=Per più informazioni, clicca su una qualsiasi voce dell'elenco.
@ -193,16 +200,20 @@ Available commands: (see also: /help <cmd>)=Comandi disponibili: (vedi anche /he
Close=Chiudi
Privilege=Privilegio
Description=Descrizione
Available privileges:=Privilegi disponibili:
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=print [<filtro>] | dump [<filtro>] | save [<formato> [<filtro>]] | reset
Handle the profiler and profiling data=Gestisce il profiler e i dati da esso elaborati
Statistics written to action log.=Statistiche scritte nel log delle azioni.
Statistics were reset.=Le statistiche sono state resettate.
Usage: @1=Utilizzo: @1
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=I formati supportati sono txt, csv, lua, json e json_pretty (le strutture potrebbero essere soggetti a cambiamenti).
@1 joined the game.=
@1 left the game.=
@1 left the game (timed out).=
(no description)=(nessuna descrizione)
Can interact with things and modify the world=Si può interagire con le cose e modificare il mondo
Can speak in chat=Si può parlare in chat
Can modify '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 teleport self=Si può teletrasportare se stessз
Can teleport other players=Si possono teletrasportare gli altri giocatori
@ -222,3 +233,15 @@ Unknown Item=Oggetto sconosciuto
Air=Aria
Ignore=Ignora
You can't place 'ignore' nodes!=Non puoi piazzare nodi 'ignore'!
Values below show absolute/relative times spend per server step by the instrumented function.=
A total of @1 sample(s) were taken.=
The output is limited to '@1'.=
Saving of profile failed: @1=
Profile saved to @1=
##### not used anymore #####
<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.=
Invalid command: @1=
Invalid command usage.=
(@1 s)=
Command execution took @1 s=
You don't have permission to run this command (missing privileges: @1).=
Unable to get position of player @1.=
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=
The administrator of this server is @1.=
There's no administrator named in the config file.=
@1 does not have any privileges.=
Privileges of @1: @2=
[<name>]=
Show privileges of yourself or another player=
Player @1 does not exist.=
Privileges of @1: @2=
<privilege>=
Return list of all online players with privilege=
Invalid parameters (see /help haspriv).=
Unknown privilege!=
Players online with the "@1" privilege: @2=
Your privileges are insufficient.=
Your privileges are insufficient. '@1' only allows you to grant: @2=
Unknown privilege: @1=
@1 granted you privileges: @2=
<name> (<privilege> | all)=
<name> (<privilege> [, <privilege2> [<...>]] | all)=
Give privileges to player=
Invalid parameters (see /help grant).=
<privilege> | all=
<privilege> [, <privilege2> [<...>]] | all=
Grant privileges to yourself=
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=
Remove privileges from player=
Invalid parameters (see /help revoke).=
@ -183,7 +191,6 @@ Available commands:=
Command not available: @1=
[all | privs | <cmd>]=
Get help for commands or list privileges=
Available privileges:=
Command=
Parameters=
For more information, click on any entry in the list.=
@ -193,16 +200,20 @@ Available commands: (see also: /help <cmd>)=
Close=
Privilege=
Description=
Available privileges:=
print [<filter>] | dump [<filter>] | save [<format> [<filter>]] | reset=
Handle the profiler and profiling data=
Statistics written to action log.=
Statistics were reset.=
Usage: @1=
Format can be one of txt, csv, lua, json, json_pretty (structures may be subject to change).=
@1 joined the game.=
@1 left the game.=
@1 left the game (timed out).=
(no description)=
Can interact with things and modify the world=
Can speak in chat=
Can modify 'shout' and 'interact' privileges=
Can modify basic privileges (@1)=
Can modify privileges=
Can teleport self=
Can teleport other players=
@ -222,3 +233,8 @@ Unknown Item=
Air=
Ignore=
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.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.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.settings)
tv_main:add(tabs.credits)
tv_main:add(tabs.about)
tv_main:set_global_event_handler(main_event_handler)
tv_main:set_fixed_size(false)

View File

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

View File

@ -107,8 +107,8 @@ local function buildCreditList(source)
end
return {
name = "credits",
caption = fgettext("Credits"),
name = "about",
caption = fgettext("About"),
cbf_formspec = function(tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png"
local version = core.get_version()
@ -131,11 +131,16 @@ return {
buildCreditList(previous_contributors) .. "," ..
";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
fs = fs .. "tooltip[userdata;" ..
fgettext("Opens the directory that contains user-provided worlds, games, mods,\n" ..
"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
return fs

View File

@ -516,18 +516,17 @@ bilinear_filter (Bilinear filtering) bool false
trilinear_filter (Trilinear filtering) bool false
# Filtered textures can blend RGB values with fully-transparent neighbors,
# which PNG optimizers usually discard, sometimes resulting in a dark or
# light edge to transparent textures. Apply this filter to clean that up
# at texture load time.
# which PNG optimizers usually discard, often resulting in dark or
# light edges to transparent textures. Apply a filter to clean that up
# at texture load time. This is automatically enabled if mipmapping is enabled.
texture_clean_transparent (Clean transparent textures) bool false
# When using bilinear/trilinear/anisotropic filters, low-resolution textures
# can be blurred, so automatically upscale them with nearest-neighbor
# interpolation to preserve crisp pixels. This sets the minimum texture size
# for the upscaled textures; higher values look sharper, but require more
# memory. Powers of 2 are recommended. Setting this higher than 1 may not
# have a visible effect unless bilinear/trilinear/anisotropic filtering is
# enabled.
# memory. Powers of 2 are recommended. This setting is ONLY applies if
# bilinear/trilinear/anisotropic filtering is enabled.
# This is also used as the base node texture size for world-aligned
# texture autoscaling.
texture_min_size (Minimum texture size) int 64
@ -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.
texture_path (Texture path) path
# The rendering back-end for Irrlicht.
# The rendering back-end.
# A restart is required after changing this.
# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
# 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_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).
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_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
# 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
mono_font_path_bold_italic (Bold and italic monospace font path) filepath fonts/Cousine-BoldItalic.ttf
# Path of the fallback 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.
# 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:
# - <nothing> (no logging)
@ -1434,9 +1424,8 @@ enable_ipv6 (IPv6) bool true
[*Advanced]
# Default timeout for cURL, stated in milliseconds.
# Only has an effect if compiled with cURL.
curl_timeout (cURL timeout) int 5000
# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds.
curl_timeout (cURL interactive timeout) int 20000
# Limits number of parallel HTTP requests. Affects:
# - 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.
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
# Makes DirectX work with LuaJIT. Disable if it causes troubles.

View File

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

View File

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

View File

@ -146,10 +146,14 @@ void main(void)
// the brightness, so now we have to multiply these
// colors with the color of the incoming light.
// 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.
float nightRatio = 1.0 - inVertexColor.a;
color.rgb = inVertexColor.rgb * (inVertexColor.a * dayLight.rgb +
float nightRatio = 1.0 - color.a;
color.rgb = color.rgb * (color.a * dayLight.rgb +
nightRatio * artificialLight.rgb) * 2.0;
color.a = 1.0;

View File

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

View File

@ -6,5 +6,9 @@ void main(void)
varTexCoord = inTexCoord0.st;
gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
varColor = inVertexColor.bgra;
#else
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
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
DOC "Path to the directory with Irrlicht includes"
DOC "Path to the directory with IrrlichtMt includes"
PATHS
/usr/local/include/irrlicht
/usr/include/irrlicht
/system/develop/headers/irrlicht #Haiku
PATH_SUFFIXES "include/irrlicht"
/usr/local/include/${libname2}
/usr/include/${libname2}
/system/develop/headers/${libname2} #Haiku
PATH_SUFFIXES "include/${libname2}"
)
find_library(IRRLICHT_LIBRARY NAMES libIrrlicht Irrlicht
DOC "Path to the Irrlicht library file"
find_library(IRRLICHT_LIBRARY NAMES lib${libname} ${libname}
DOC "Path to the IrrlichtMt library file"
PATHS
/usr/local/lib
/usr/lib
/system/develop/lib # Haiku
)
endif()
# Users will likely need to edit these
mark_as_advanced(CLEAR IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIR)
if(IRRLICHT_INCLUDE_DIR OR IRRLICHT_LIBRARY)
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
if(WIN32)
# If VCPKG_APPLOCAL_DEPS is ON, dll's are automatically handled by VCPKG
if(NOT VCPKG_APPLOCAL_DEPS)
find_file(IRRLICHT_DLL NAMES Irrlicht.dll
DOC "Path of the Irrlicht dll (for installation)"
find_file(IRRLICHT_DLL NAMES IrrlichtMt.dll
DOC "Path of the IrrlichtMt dll (for installation)"
)
endif()
endif(WIN32)

View File

@ -42,7 +42,7 @@ else()
)
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
PATHS /usr/openwin/share/include
@ -59,7 +59,6 @@ else()
/usr/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR)
endif()

View File

@ -658,6 +658,9 @@ Minetest namespace reference
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data
* `data`: string of data to hash
* `raw`: return raw bytes instead of hex digits, default: false
* `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
restrictions applied to the current mod.
* 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
[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
(e.g. `colorname#08`). For named colors the hexadecimal string representing the alpha
value must (always) be two hexadecimal digits.
To specify the value of the alpha channel, append `#A` or `#AA` to the end of
the color name (e.g. `colorname#08`).
`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 is (`param2` / 16) nodes.
* `paramtype2 = "degrotate"`
* Only valid for "plantlike" drawtype. The rotation of the node is stored in
`param2`.
* Values range 0 - 179. The value stored in `param2` is multiplied by two to
* Valid for `plantlike` and `mesh` drawtypes. The rotation of the node is
stored in `param2`.
* Values range 0239. The value stored in `param2` is multiplied by 1.5 to
get the actual rotation in degrees of the node.
* `paramtype2 = "meshoptions"`
* 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
and 63 being full.
* 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"`
* `param2` will not be used by the engine and can be used to store
an arbitrary value
@ -1107,8 +1112,20 @@ Look for examples in `games/devtest` or `games/minetest_game`.
* Invisible, uses no texture.
* `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`
* 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`
* Often used for partially-transparent nodes.
* 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.
* `torchlike`
* A single vertical texture.
* If placed on top of a node, uses the first texture specified in `tiles`.
* If placed against the underside of a node, uses the second texture
specified in `tiles`.
* If placed on the side of a node, uses the third texture specified in
`tiles` and is perpendicular to that node.
* If `paramtype2="[color]wallmounted":
* If placed on top of a node, uses the first texture specified in `tiles`.
* If placed against the underside of a node, uses the second texture
specified in `tiles`.
* 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`
* A single texture parallel to, and mounted against, the top, underside or
side of a node.
* If `paramtype2="[color]wallmounted", it rotates according to `param2`
* If `paramtype2="none"`, it will always be on the floor.
* `plantlike`
* Two vertical and diagonal textures at right-angles to each other.
* See `paramtype2 = "meshoptions"` above for other options.
@ -1725,7 +1748,15 @@ to games.
* `3`: the node always gets the digging time 0 seconds (torch)
* `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`
* `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
* `float`: the node will not fall through liquids
* `level`: Can be used to give an additional sense of progression in the game.
@ -1745,12 +1776,15 @@ to games.
`"toolrepair"` crafting recipe
### `ObjectRef` groups
### `ObjectRef` armor groups
* `immortal`: Skips all damage and breath handling for an object. This group
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
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
players punching it by hand or a non-tool item, so that it can do something
else than take damage.
@ -3078,9 +3112,8 @@ Colors
Named colors are also supported and are equivalent to
[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 (e.g. `colorname#08`). For named colors the hexadecimal string
representing the alpha value must (always) be two hexadecimal digits.
To specify the value of the alpha channel, append `#A` or `#AA` to the end of
the color name (e.g. `colorname#08`).
`ColorSpec`
-----------
@ -3146,6 +3179,16 @@ For the following functions, `v`, `v1`, `v2` are vectors,
* Returns 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.
* `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)`:
* Returns a vector of length 1 with direction `p1` to `p2`.
* 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.
* `vector.round(v)`:
* Returns a vector, each dimension rounded to nearest integer.
* At a multiple of 0.5, rounds away from zero.
* `vector.apply(v, func)`:
* Returns a vector where the function `func` has been applied to each
component.
@ -3234,6 +3278,8 @@ Helper functions
* If the absolute value of `x` is within the `tolerance` or `x` is NaN,
`0` is returned.
* `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)`
* `separator`: string, default: `","`
* `include_empty`: boolean, default: `false`
@ -4394,6 +4440,9 @@ Utilities
direct_velocity_on_players = true,
-- nodedef's use_texture_alpha accepts new string modes (5.4.0)
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`
@ -4453,6 +4502,9 @@ Utilities
* `minetest.sha1(data, [raw])`: returns the sha1 hash of data
* `data`: string of data to hash
* `raw`: return raw bytes instead of hex digits, default: false
* `minetest.colorspec_to_colorstring(colorspec)`: Converts a ColorSpec to a
ColorString. If the ColorSpec is invalid, returns `nil`.
* `colorspec`: The ColorSpec to convert
Logging
-------
@ -4656,6 +4708,7 @@ Call these functions only at load time!
* `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of:
* `moved_too_fast`
* `interacted_too_far`
* `interacted_with_self`
* `interacted_while_dead`
* `finished_unknown_dig`
* `dug_unbreakable`
@ -4896,7 +4949,7 @@ Environment access
* Punch node with the same effects that a player would cause
* `minetest.spawn_falling_node(pos)`
* 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)`
* 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.
-- 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
@ -7437,7 +7499,10 @@ Used by `minetest.register_node`.
-- `minetest.set_node_level` and `minetest.add_node_level`.
-- 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,
-- 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",
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"
-- The http method to use. Defaults to "GET".

View File

@ -204,7 +204,8 @@ core.get_screen_info()
display_width = <width of display>,
display_height = <height of display>,
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
elseif def.paramtype2 == "leveled" then
p2_max = 127
elseif def.paramtype2 == "degrotate" and def.drawtype == "plantlike" then
p2_max = 179
elseif def.paramtype2 == "degrotate" and (def.drawtype == "plantlike" or def.drawtype == "mesh") then
p2_max = 239
elseif def.paramtype2 == "colorfacedir" or
def.paramtype2 == "colorwallmounted" or
def.paramtype2 == "colordegrotate" or
def.paramtype2 == "color" then
p2_max = 255
end
@ -143,7 +144,8 @@ local function place_nodes(param)
-- Skip undefined param2 values
if not ((def.paramtype2 == "meshoptions" and p2 % 8 > 4) 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 })
nodes_placed = nodes_placed + 1

View File

@ -15,22 +15,6 @@ testing this node easier and more convenient.
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
minetest.register_node("testnodes:normal", {
description = S("Normal Drawtype Test Node"),
@ -145,20 +129,15 @@ minetest.register_node("testnodes:fencelike", {
})
minetest.register_node("testnodes:torchlike", {
description = S("Torchlike Drawtype Test Node"),
description = S("Floor Torchlike Drawtype Test Node"),
drawtype = "torchlike",
paramtype = "light",
tiles = {
"testnodes_torchlike_floor.png",
"testnodes_torchlike_ceiling.png",
"testnodes_torchlike_wall.png",
},
tiles = { "testnodes_torchlike_floor.png^[colorize:#FF0000:64" },
walkable = false,
sunlight_propagates = true,
groups = { dig_immediate = 3 },
inventory_image = fallback_image("testnodes_torchlike_floor.png"),
})
minetest.register_node("testnodes:torchlike_wallmounted", {
@ -176,12 +155,22 @@ minetest.register_node("testnodes:torchlike_wallmounted", {
walkable = false,
sunlight_propagates = true,
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", {
minetest.register_node("testnodes:signlike_wallmounted", {
description = S("Wallmounted Signlike Drawtype Test Node"),
drawtype = "signlike",
paramtype = "light",
@ -192,7 +181,6 @@ minetest.register_node("testnodes:signlike", {
walkable = false,
groups = { dig_immediate = 3 },
sunlight_propagates = true,
inventory_image = fallback_image("testnodes_signlike.png"),
})
minetest.register_node("testnodes:plantlike", {
@ -223,6 +211,30 @@ minetest.register_node("testnodes:plantlike_waving", {
-- 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", {
description = S("Degrotate Plantlike Drawtype Test Node"),
drawtype = "plantlike",
@ -230,12 +242,43 @@ minetest.register_node("testnodes:plantlike_degrotate", {
paramtype2 = "degrotate",
tiles = { "testnodes_plantlike_degrotate.png" },
on_rightclick = rotate_on_rightclick,
place_param2 = 7,
walkable = false,
sunlight_propagates = true,
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
minetest.register_node("testnodes:plantlike_leveled", {
description = S("Leveled Plantlike Drawtype Test Node"),
@ -456,7 +499,6 @@ minetest.register_node("testnodes:airlike", {
walkable = false,
groups = { dig_immediate = 3 },
sunlight_propagates = true,
inventory_image = fallback_image("testnodes_airlike.png"),
})
-- param2 changes liquid height
@ -549,7 +591,7 @@ scale("plantlike",
scale("torchlike_wallmounted",
S("Double-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("Half-sized Wallmounted Signlike Drawtype Test Node"))
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.
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
# texture_path =
# The rendering back-end for Irrlicht.
# The rendering back-end.
# A restart is required after changing this.
# Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise.
# On other platforms, OpenGL is recommended.

View File

@ -1085,18 +1085,6 @@ msgstr ""
msgid "Invalid gamespec."
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
msgid "Shutting down..."
msgstr ""

View File

@ -55,7 +55,7 @@ if(NOT USE_CURL)
endif()
option(ENABLE_GETTEXT "Use GetText for internationalization" TRUE)
option(ENABLE_GETTEXT "Use GetText for internationalization" ${BUILD_CLIENT})
set(USE_GETTEXT FALSE)
if(ENABLE_GETTEXT)
@ -102,11 +102,11 @@ endif()
option(ENABLE_GLES "Use OpenGL ES instead of OpenGL" FALSE)
mark_as_advanced(ENABLE_GLES)
if(BUILD_CLIENT)
if(ENABLE_GLES)
find_package(OpenGLES2 REQUIRED)
else()
# transitive dependency from Irrlicht (see longer explanation below)
if(NOT WIN32)
# transitive dependency from Irrlicht (see longer explanation below)
if(NOT WIN32)
if(ENABLE_GLES)
find_package(OpenGLES2 REQUIRED)
else()
set(OPENGL_GL_PREFERENCE "LEGACY" CACHE STRING
"See CMake Policy CMP0072 for reference. GLVND is broken on some nvidia setups")
set(OpenGL_GL_PREFERENCE ${OPENGL_GL_PREFERENCE})
@ -120,13 +120,13 @@ endif()
option(ENABLE_FREETYPE "Enable FreeType2 (TrueType fonts and basic unicode support)" TRUE)
set(USE_FREETYPE FALSE)
if(ENABLE_FREETYPE)
if(BUILD_CLIENT AND ENABLE_FREETYPE)
find_package(Freetype)
if(FREETYPE_FOUND)
message(STATUS "Freetype enabled.")
set(USE_FREETYPE TRUE)
endif()
endif(ENABLE_FREETYPE)
endif()
option(ENABLE_CURSES "Enable ncurses console" TRUE)
set(USE_CURSES FALSE)
@ -146,7 +146,17 @@ option(ENABLE_POSTGRESQL "Enable PostgreSQL backend" TRUE)
set(USE_POSTGRESQL FALSE)
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)
set(USE_POSTGRESQL TRUE)
@ -526,8 +536,11 @@ if(USE_CURL)
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)
add_executable(${PROJECT_NAME} ${client_SRCS} ${extra_windows_SRCS})
@ -668,7 +681,10 @@ endif(BUILD_SERVER)
# see issue #4638
set(GETTEXT_BLACKLISTED_LOCALES
ar
dv
he
hi
kn
ky
ms_Arab
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_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_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
// would lead to unexpected behaviour, so we don't do that.
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);
// 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_fov_y = m_curr_fov_degrees * M_PI / 180.0;
// 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;
struct MapDrawControl;
class Client;
class RenderingEngine;
class WieldMeshSceneNode;
struct Nametag
@ -104,7 +105,7 @@ enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
class Camera
{
public:
Camera(MapDrawControl &draw_control, Client *client);
Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine);
~Camera();
// Get camera scene node.

View File

@ -98,6 +98,7 @@ Client::Client(
NodeDefManager *nodedef,
ISoundManager *sound,
MtEventManager *event,
RenderingEngine *rendering_engine,
bool ipv6,
GameUI *game_ui
):
@ -108,8 +109,9 @@ Client::Client(
m_nodedef(nodedef),
m_sound(sound),
m_event(event),
m_rendering_engine(rendering_engine),
m_env(
new ClientMap(this, control, 666),
new ClientMap(this, rendering_engine, control, 666),
tsrc, this
),
m_particle_manager(&m_env),
@ -301,12 +303,7 @@ Client::~Client()
}
// cleanup 3d model meshes on client shutdown
while (RenderingEngine::get_mesh_cache()->getMeshCount() != 0) {
scene::IAnimatedMesh *mesh = RenderingEngine::get_mesh_cache()->getMeshByIndex(0);
if (mesh)
RenderingEngine::get_mesh_cache()->removeMesh(mesh);
}
m_rendering_engine->cleanupMeshCache();
delete m_minimap;
m_minimap = nullptr;
@ -663,18 +660,11 @@ bool Client::loadMedia(const std::string &data, const std::string &filename,
TRACESTREAM(<< "Client: Attempting to load image "
<< "file \"" << filename << "\"" << std::endl);
io::IFileSystem *irrfs = RenderingEngine::get_filesystem();
video::IVideoDriver *vdrv = RenderingEngine::get_video_driver();
io::IFileSystem *irrfs = m_rendering_engine->get_filesystem();
video::IVideoDriver *vdrv = m_rendering_engine->get_video_driver();
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
io::IReadFile *rfile = irrfs->createMemoryReadFile(
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.");
@ -1430,6 +1420,11 @@ bool Client::updateWieldedItem()
return true;
}
scene::ISceneManager* Client::getSceneManager()
{
return m_rendering_engine->get_scene_manager();
}
Inventory* Client::getInventory(const InventoryLocation &loc)
{
switch(loc.type){
@ -1692,7 +1687,7 @@ typedef struct TextureUpdateArgs {
ITextureSource *tsrc;
} 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;
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;
std::basic_stringstream<wchar_t> strm;
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);
}
}
@ -1732,21 +1727,21 @@ void Client::afterContentReceived()
// Rebuild inherited images and recreate textures
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();
delete[] text;
// Rebuild shaders
infostream<<"- Rebuilding shaders"<<std::endl;
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();
delete[] text;
// Update node aliases
infostream<<"- Updating node aliases"<<std::endl;
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);
for (const auto &path : getTextureDirs()) {
TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
@ -1765,7 +1760,7 @@ void Client::afterContentReceived()
tu_args.last_percent = 0;
tu_args.text_base = wgettext("Initializing nodes");
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;
// Start mesh update thread after setting up content definitions
@ -1779,7 +1774,7 @@ void Client::afterContentReceived()
m_script->on_client_ready(m_env.getLocalPlayer());
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;
delete[] text;
}
@ -1797,7 +1792,7 @@ float Client::getCurRate()
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();
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
// This allows unique vertex colors and other properties for each instance
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile(
io::IReadFile *rfile = m_rendering_engine->get_filesystem()->createMemoryReadFile(
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");
scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile);
scene::IAnimatedMesh *mesh = m_rendering_engine->get_scene_manager()->getMesh(rfile);
rfile->drop();
if (!mesh)
return nullptr;
mesh->grab();
if (!cache)
RenderingEngine::get_mesh_cache()->removeMesh(mesh);
m_rendering_engine->removeMesh(mesh);
return mesh;
}

View File

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

View File

@ -235,7 +235,16 @@ void ClientEnvironment::step(float dtime)
&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) {
v3f speed_diff = info.new_speed - info.old_speed;;
@ -248,17 +257,20 @@ void ClientEnvironment::step(float dtime)
speed_diff.Z = 0;
f32 pre_factor = 1; // 1 hp per node/s
f32 tolerance = BS*14; // 5 without damage
f32 post_factor = 1; // 1 hp per node/s
if (info.type == COLLISION_NODE) {
const ContentFeatures &f = m_client->ndef()->
get(m_map->getNode(info.node_p));
// Determine fall damage multiplier
int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
pre_factor = 1.0f + (float)addp / 100.0f;
// Determine fall damage modifier
int addp_n = itemgroup_get(f.groups, "fall_damage_add_percent");
// 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();
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);
if (damage != 0) {
damageLocalPlayer(damage, true);
@ -340,7 +352,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
if (!m_ao_manager.registerObject(object))
return 0;
object->addToScene(m_texturesource);
object->addToScene(m_texturesource, m_client->getSceneManager());
// Update lighting immediately
object->updateLight(getDayNightRatio());

View File

@ -80,7 +80,7 @@ ClientLauncher::~ClientLauncher()
delete g_fontengine;
delete g_gamecallback;
delete RenderingEngine::get_instance();
delete m_rendering_engine;
#if USE_SOUND
g_sound_manager_singleton.reset();
@ -101,7 +101,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// List video modes if requested
if (list_video_modes)
return RenderingEngine::print_video_modes();
return m_rendering_engine->print_video_modes();
#if USE_SOUND
if (g_settings->getBool("enable_sound"))
@ -120,12 +120,12 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
return true;
}
if (RenderingEngine::get_video_driver() == NULL) {
if (m_rendering_engine->get_video_driver() == NULL) {
errorstream << "Could not initialize video driver." << std::endl;
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.
@ -136,15 +136,15 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// Create game callback for menus
g_gamecallback = new MainGameCallback();
RenderingEngine::get_instance()->setResizable(true);
m_rendering_engine->setResizable(true);
init_input();
RenderingEngine::get_scene_manager()->getParameters()->
m_rendering_engine->get_scene_manager()->getParameters()->
setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
guienv = RenderingEngine::get_gui_env();
skin = RenderingEngine::get_gui_env()->getSkin();
guienv = m_rendering_engine->get_gui_env();
skin = guienv->getSkin();
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_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");
// Texture dimensions should be a power of 2
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());
if (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);
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
skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128));
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49));
#endif
// Create the menu clouds
if (!g_menucloudsmgr)
g_menucloudsmgr = RenderingEngine::get_scene_manager()->createNewSceneManager();
g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager();
if (!g_menuclouds)
g_menuclouds = new Clouds(g_menucloudsmgr, -1, rand());
g_menuclouds->setHeight(100.0f);
@ -214,11 +212,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
bool retval = true;
bool *kill = porting::signal_handler_killstatus();
while (RenderingEngine::run() && !*kill &&
while (m_rendering_engine->run() && !*kill &&
!g_gamecallback->shutdown_requested) {
// Set the window caption
const wchar_t *text = wgettext("Main Menu");
RenderingEngine::get_raw_device()->
m_rendering_engine->get_raw_device()->
setWindowCaption((utf8_to_wide(PROJECT_NAME_C) +
L" " + utf8_to_wide(g_version_hash) +
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
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
custom gui elements directly on the screen.
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));
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
if (!RenderingEngine::get_raw_device()->run() || *kill) {
if (!m_rendering_engine->run() || *kill) {
if (!g_settings_path.empty())
g_settings->updateConfigFile(g_settings_path.c_str());
break;
}
RenderingEngine::get_video_driver()->setTextureCreationFlag(
m_rendering_engine->get_video_driver()->setTextureCreationFlag(
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
#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;
#endif
the_game(
kill,
input,
m_rendering_engine,
start_data,
error_message,
chat_backend,
&reconnect_requested
);
RenderingEngine::get_scene_manager()->clear();
m_rendering_engine->get_scene_manager()->clear();
#ifdef HAVE_TOUCHSCREENGUI
delete g_touchscreengui;
@ -346,8 +345,8 @@ void ClientLauncher::init_args(GameStartData &start_data, const Settings &cmd_ar
bool ClientLauncher::init_engine()
{
receiver = new MyEventReceiver();
new RenderingEngine(receiver);
return RenderingEngine::get_raw_device() != nullptr;
m_rendering_engine = new RenderingEngine(receiver);
return m_rendering_engine->get_raw_device() != nullptr;
}
void ClientLauncher::init_input()
@ -364,7 +363,7 @@ void ClientLauncher::init_input()
// Make sure this is called maximum once per
// irrlicht device, otherwise it will give you
// 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;
joystick_infos.reserve(infos.size());
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();
}
if (!RenderingEngine::run())
if (!m_rendering_engine->run())
return false;
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)
{
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;
while (RenderingEngine::get_raw_device()->run() && !*kill) {
while (m_rendering_engine->run() && !*kill) {
if (!isMenuActive())
break;
driver->beginScene(true, true, video::SColor(255, 128, 128, 128));
RenderingEngine::get_gui_env()->drawAll();
m_rendering_engine->get_gui_env()->drawAll();
driver->endScene();
// On some computers framerate doesn't seem to be automatically limited
sleep_ms(25);
@ -559,14 +558,14 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
// Cursor can be non-visible when coming from the game
#ifndef ANDROID
RenderingEngine::get_raw_device()->getCursorControl()->setVisible(true);
m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true);
#endif
/* 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 */
RenderingEngine::get_scene_manager()->clear();
m_rendering_engine->get_scene_manager()->clear();
}
void ClientLauncher::speed_tests()

View File

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

View File

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

View File

@ -68,6 +68,7 @@ class ClientMap : public Map, public scene::ISceneNode
public:
ClientMap(
Client *client,
RenderingEngine *rendering_engine,
MapDrawControl &control,
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
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,
// whichever is greater. This gives us some leeway so that
@ -258,8 +257,6 @@ void ClientMediaDownloader::initialStep(Client *client)
remote->baseurl + MTHASHSET_FILE_NAME;
fetch_request.caller = m_httpfetch_caller;
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.raw_data = required_hash_set;
fetch_request.extra_headers.emplace_back(
@ -432,9 +429,8 @@ void ClientMediaDownloader::startRemoteMediaTransfers()
fetch_request.url = url;
fetch_request.caller = m_httpfetch_caller;
fetch_request.request_id = m_httpfetch_next_id;
fetch_request.timeout = 0; // no data timeout!
fetch_request.connect_timeout =
m_httpfetch_timeout;
fetch_request.timeout =
g_settings->getS32("curl_file_download_timeout");
httpfetch_async(fetch_request);
m_remote_file_transfers.insert(std::make_pair(

View File

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

View File

@ -44,7 +44,7 @@ public:
ClientActiveObject(u16 id, Client *client, ClientEnvironment *env);
virtual ~ClientActiveObject();
virtual void addToScene(ITextureSource *tsrc) {}
virtual void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) = 0;
virtual void removeFromScene(bool permanent) {}
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
class Clouds;
Clouds *g_menuclouds = NULL;
irr::scene::ISceneManager *g_menucloudsmgr = NULL;
scene::ISceneManager *g_menucloudsmgr = NULL;
// Constant for now
static constexpr const float cloud_size = BS * 64.0f;
@ -170,7 +170,7 @@ void Clouds::render()
// 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;
vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);

View File

@ -29,8 +29,7 @@ class Clouds;
extern Clouds *g_menuclouds;
// Scene manager used for menu clouds
namespace irr{namespace scene{class ISceneManager;}}
extern irr::scene::ISceneManager *g_menucloudsmgr;
extern scene::ISceneManager *g_menucloudsmgr;
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 <IAnimatedMeshSceneNode.h>
#include "client/client.h"
#include "client/renderingengine.h"
#include "client/sound.h"
#include "client/tile.h"
#include "util/basic_macros.h"
@ -190,7 +189,7 @@ public:
static ClientActiveObject* create(Client *client, ClientEnvironment *env);
void addToScene(ITextureSource *tsrc);
void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr);
void removeFromScene(bool permanent);
void updateLight(u32 day_night_ratio);
void updateNodePos();
@ -221,7 +220,7 @@ ClientActiveObject* TestCAO::create(Client *client, ClientEnvironment *env)
return new TestCAO(client, env);
}
void TestCAO::addToScene(ITextureSource *tsrc)
void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
@ -250,7 +249,7 @@ void TestCAO::addToScene(ITextureSource *tsrc)
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
m_node = RenderingEngine::get_scene_manager()->addMeshSceneNode(mesh, NULL);
m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
updateNodePos();
}
@ -595,9 +594,9 @@ void GenericCAO::removeFromScene(bool permanent)
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) {
return;
@ -629,8 +628,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
}
auto grabMatrixNode = [this] {
m_matrixnode = RenderingEngine::get_scene_manager()->
addDummyTransformationSceneNode();
m_matrixnode = m_smgr->addDummyTransformationSceneNode();
m_matrixnode->grab();
};
@ -648,7 +646,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
if (m_prop.visual == "sprite") {
grabMatrixNode();
m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode(
m_spritenode = m_smgr->addBillboardSceneNode(
m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
m_spritenode->grab();
m_spritenode->setMaterialTexture(0,
@ -733,8 +731,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
mesh->addMeshBuffer(buf);
buf->drop();
}
m_meshnode = RenderingEngine::get_scene_manager()->
addMeshSceneNode(mesh, m_matrixnode);
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab();
mesh->drop();
// 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") {
grabMatrixNode();
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
m_meshnode = RenderingEngine::get_scene_manager()->
addMeshSceneNode(mesh, m_matrixnode);
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab();
mesh->drop();
@ -757,8 +753,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
grabMatrixNode();
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
if (mesh) {
m_animated_meshnode = RenderingEngine::get_scene_manager()->
addAnimatedMeshSceneNode(mesh, m_matrixnode);
m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode);
m_animated_meshnode->grab();
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;
item.deSerialize(m_prop.wield_item, m_client->idef());
}
m_wield_meshnode = new WieldMeshSceneNode(
RenderingEngine::get_scene_manager(), -1);
m_wield_meshnode = new WieldMeshSceneNode(m_smgr, -1);
m_wield_meshnode->setItem(item, m_client,
(m_prop.visual == "wielditem"));
@ -1089,7 +1083,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
}
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
for (u16 cao_id : m_attachment_child_ids) {
@ -1488,11 +1482,8 @@ void GenericCAO::updateAnimation()
if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed)
m_animated_meshnode->setAnimationSpeed(m_animation_speed);
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)
m_animated_meshnode->setLoopMode(m_animation_loop);
#endif
}
void GenericCAO::updateAnimationSpeed()
@ -1508,10 +1499,10 @@ void GenericCAO::updateBonePosition()
if (m_bone_position.empty() || !m_animated_meshnode)
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) {
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) {
bone->setPosition(it.second.X);
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
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)
continue;
@ -1965,7 +1956,7 @@ void GenericCAO::updateMeshCulling()
return;
}
irr::scene::ISceneNode *node = getSceneNode();
scene::ISceneNode *node = getSceneNode();
if (!node)
return;

View File

@ -189,6 +189,8 @@ public:
const bool isImmortal();
inline const ObjectProperties &getProperties() const { return m_prop; }
scene::ISceneNode *getSceneNode() const;
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const;
@ -260,7 +262,7 @@ public:
void removeFromScene(bool permanent);
void addToScene(ITextureSource *tsrc);
void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr);
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";
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") &&
!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)
@ -968,7 +966,7 @@ void MapblockMeshGenerator::drawPlantlike()
draw_style = PLANT_STYLE_CROSS;
scale = BS / 2 * f->visual_scale;
offset = v3f(0, 0, 0);
rotate_degree = 0;
rotate_degree = 0.0f;
random_offset_Y = false;
face_num = 0;
plant_height = 1.0;
@ -988,7 +986,8 @@ void MapblockMeshGenerator::drawPlantlike()
break;
case CPT2_DEGROTATE:
rotate_degree = n.param2 * 2;
case CPT2_COLORED_DEGROTATE:
rotate_degree = 1.5f * n.getDegRotate(nodedef);
break;
case CPT2_LEVELED:
@ -1343,6 +1342,7 @@ void MapblockMeshGenerator::drawMeshNode()
u8 facedir = 0;
scene::IMesh* mesh;
bool private_mesh; // as a grab/drop pair is not thread-safe
int degrotate = 0;
if (f->param_type_2 == CPT2_FACEDIR ||
f->param_type_2 == CPT2_COLORED_FACEDIR) {
@ -1354,9 +1354,12 @@ void MapblockMeshGenerator::drawMeshNode()
facedir = n.getWallMounted(nodedef);
if (!enable_mesh_cache)
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
private_mesh = false;
mesh = f->mesh_ptr[facedir];
@ -1364,7 +1367,10 @@ void MapblockMeshGenerator::drawMeshNode()
// no cache, clone and rotate mesh
private_mesh = true;
mesh = cloneMesh(f->mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh, facedir);
if (facedir)
rotateMeshBy6dFacedir(mesh, facedir);
else if (degrotate)
rotateMeshXZby(mesh, 1.5f * degrotate);
recalculateBoundingBox(mesh);
meshmanip->recalculateNormals(mesh, true, false);
} else

View File

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

View File

@ -56,7 +56,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) :
readSettings();
if (m_currentMode == FM_Standard) {
if (m_currentMode != FM_Simple) {
g_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_bold", 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_shadow", 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_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);
@ -101,6 +96,11 @@ void FontEngine::cleanCache()
/******************************************************************************/
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) {
spec.mode = m_currentMode;
@ -112,6 +112,10 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
// Support for those could be added, but who cares?
spec.bold = 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
@ -130,6 +134,13 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
else
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;
return font;
@ -204,20 +215,9 @@ unsigned int FontEngine::getFontSize(FontMode mode)
void FontEngine::readSettings()
{
if (USE_FREETYPE && g_settings->getBool("freetype")) {
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_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_size[FM_Standard] = g_settings->getU16("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_bold = g_settings->getBool("font_bold");
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);
std::string setting_prefix = "";
switch (spec.mode) {
case FM_Fallback:
setting_prefix = "fallback_";
break;
case FM_Mono:
case FM_SimpleMono:
setting_prefix = "mono_";
break;
default:
break;
}
if (spec.mode == FM_Mono)
setting_prefix = "mono_";
std::string setting_suffix = "";
if (spec.bold)
@ -305,38 +295,41 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha",
font_shadow_alpha);
std::string wanted_font_path;
wanted_font_path = g_settings->get(setting_prefix + "font_path" + setting_suffix);
std::string path_setting;
if (spec.mode == _FM_Fallback)
path_setting = "fallback_font_path";
else
path_setting = setting_prefix + "font_path" + setting_suffix;
std::string fallback_settings[] = {
wanted_font_path,
g_settings->get("fallback_font_path"),
Settings::getLayer(SL_DEFAULTS)->get(setting_prefix + "font_path")
g_settings->get(path_setting),
Settings::getLayer(SL_DEFAULTS)->get(path_setting)
};
#if USE_FREETYPE
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_shadow_alpha);
if (font)
return font;
errorstream << "FontEngine: Cannot load '" << font_path <<
if (!font) {
errorstream << "FontEngine: Cannot load '" << font_path <<
"'. 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
errorstream << "FontEngine: Tried to load freetype fonts but Minetest was"
" not compiled with that library." << std::endl;
errorstream << "FontEngine: Tried to load TTF font but Minetest was"
" compiled without Freetype." << std::endl;
#endif
abort();
return nullptr;
}
/** 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 {
FM_Standard = 0,
FM_Mono,
FM_Fallback,
_FM_Fallback, // do not use directly
FM_Simple,
FM_SimpleMono,
FM_MaxMode,
@ -47,7 +47,7 @@ struct FontSpec {
bold(bold),
italic(italic) {}
u16 getHash()
u16 getHash() const
{
return (mode << 2) | (static_cast<u8>(bold) << 1) | static_cast<u8>(italic);
}
@ -132,10 +132,12 @@ public:
void readSettings();
private:
irr::gui::IGUIFont *getFont(FontSpec spec, bool may_fail);
/** update content of font cache in case of a setting change made it invalid */
void updateFontCache();
/** initialize a new font */
/** initialize a new TTF font */
gui::IGUIFont *initFont(const FontSpec &spec);
/** initialize a font without freetype */

View File

@ -153,7 +153,7 @@ Game::~Game()
delete itemdef_manager;
delete draw_control;
extendedResourceCleanup();
clearTextureNameCache();
g_settings->deregisterChangedCallback("doubletap_jump",
&settingChangedCallback, this);
@ -191,6 +191,7 @@ Game::~Game()
bool Game::startup(bool *kill,
InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &start_data,
std::string &error_message,
bool *reconnect,
@ -198,21 +199,21 @@ bool Game::startup(bool *kill,
{
// "cache"
this->device = RenderingEngine::get_raw_device();
m_rendering_engine = rendering_engine;
device = m_rendering_engine->get_raw_device();
this->kill = kill;
this->error_message = &error_message;
this->reconnect_requested = reconnect;
reconnect_requested = reconnect;
this->input = input;
this->chat_backend = chat_backend;
this->simple_singleplayer_mode = start_data.isSinglePlayer();
simple_singleplayer_mode = start_data.isSinglePlayer();
input->keycache.populate();
driver = device->getVideoDriver();
smgr = RenderingEngine::get_scene_manager();
smgr = m_rendering_engine->get_scene_manager();
RenderingEngine::get_scene_manager()->getParameters()->
setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
// Reinit runData
runData = GameRunData();
@ -233,7 +234,7 @@ bool Game::startup(bool *kill,
if (!createClient(start_data))
return false;
RenderingEngine::initialize(client, hud);
m_rendering_engine->initialize(client, hud);
return true;
}
@ -250,7 +251,7 @@ void Game::run()
Profiler::GraphValues 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"));
@ -262,12 +263,12 @@ void Game::run()
irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screen_w"),
g_settings->getU16("screen_h"));
while (RenderingEngine::run()
while (m_rendering_engine->run()
&& !(*kill || g_gamecallback->shutdown_requested
|| (server && server->isShutdownRequested()))) {
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
// Ensure evaluating settings->getBool after verifying screensize
// First condition is cheaper
@ -280,7 +281,7 @@ void Game::run()
}
// Calculate dtime =
// RenderingEngine::run() from this iteration
// m_rendering_engine->run() from this iteration
// + Sleep time until the wanted FPS are reached
limitFps(&draw_times, &dtime);
@ -329,7 +330,7 @@ void Game::run()
void Game::shutdown()
{
RenderingEngine::finalize();
m_rendering_engine->finalize();
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8
if (g_settings->get("3d_mode") == "pageflip") {
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);
draw_control = new MapDrawControl;
draw_control = new MapDrawControl();
if (!draw_control)
return false;
@ -529,7 +530,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Camera
*/
camera = new Camera(*draw_control, client);
camera = new Camera(*draw_control, client, m_rendering_engine);
if (!camera->successfullyCreated(*error_message))
return false;
client->setCamera(camera);
@ -541,7 +542,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Skybox
*/
sky = new Sky(-1, texture_src, shader_src);
sky = new Sky(-1, m_rendering_engine, texture_src, shader_src);
scsf->setSky(sky);
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);
str += L" ";
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"Minetest Hackclient";
str += L"]";
device->setWindowCaption(str.c_str());
LocalPlayer *player = client->getEnv().getLocalPlayer();
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
hud = new Hud(guienv, client, player, &player->inventory);
hud = new Hud(client, player, &player->inventory);
mapper = client->getMinimap();
@ -663,7 +676,7 @@ bool Game::connectToServer(const GameStartData &start_data,
start_data.password, start_data.address,
*draw_control, texture_src, shader_src,
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;
@ -685,9 +698,9 @@ bool Game::connectToServer(const GameStartData &start_data,
f32 dtime;
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);
@ -724,7 +737,7 @@ bool Game::connectToServer(const GameStartData &start_data,
if (client->m_is_registration_confirmation_state) {
if (registration_confirmation_shown) {
// Keep drawing the GUI
RenderingEngine::draw_menu_scene(guienv, dtime, true);
m_rendering_engine->draw_menu_scene(guienv, dtime, true);
} else {
registration_confirmation_shown = true;
(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
@ -734,7 +747,7 @@ bool Game::connectToServer(const GameStartData &start_data,
} else {
wait_time += dtime;
// 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.";
errorstream << *error_message << std::endl;
break;
@ -760,9 +773,9 @@ bool Game::getServerContent(bool *aborted)
FpsControl fps_control = { 0 };
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);
@ -800,13 +813,13 @@ bool Game::getServerContent(bool *aborted)
if (!client->itemdefReceived()) {
const wchar_t *text = wgettext("Item definitions...");
progress = 25;
RenderingEngine::draw_load_screen(text, guienv, texture_src,
m_rendering_engine->draw_load_screen(text, guienv, texture_src,
dtime, progress);
delete[] text;
} else if (!client->nodedefReceived()) {
const wchar_t *text = wgettext("Node definitions...");
progress = 30;
RenderingEngine::draw_load_screen(text, guienv, texture_src,
m_rendering_engine->draw_load_screen(text, guienv, texture_src,
dtime, progress);
delete[] text;
} else {
@ -833,7 +846,7 @@ bool Game::getServerContent(bool *aborted)
}
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);
}
}
@ -1150,6 +1163,8 @@ void Game::processKeyInput()
toggleCinematic();
} else if (wasKeyDown(KeyType::SCREENSHOT)) {
client->makeScreenshot();
} else if (wasKeyDown(KeyType::TOGGLE_BLOCK_BOUNDS)) {
hud->toggleBlockBounds();
} else if (wasKeyDown(KeyType::TOGGLE_HUD)) {
m_game_ui->toggleHud();
} else if (wasKeyDown(KeyType::MINIMAP)) {
@ -1264,8 +1279,8 @@ void Game::openInventory()
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
TextDest *txt_dst = new TextDestPlayerInventory(client);
auto *&formspec = m_game_ui->updateFormspec("");
GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
txt_dst, client->getFormspecPrepend(), sound);
GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
&input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
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
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();
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_strength =
rangelim(event->player_damage.amount / 4.0f, 1.0f, 4.0f);
rangelim(damage_ratio * 5.0f, 1.0f, 4.0f);
}
// Play damage sound
@ -1889,8 +1908,8 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
new TextDestPlayerInventory(client, *(event->show_formspec.formname));
auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname));
GUIFormSpecMenu::create(formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend(), sound);
GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
&input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
}
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);
LocalFormspecHandler *txt_dst =
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);
}
@ -2075,6 +2094,7 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam)
"custom"
);
}
delete event->set_sky;
}
@ -2607,8 +2627,8 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
auto *&formspec = m_game_ui->updateFormspec("");
GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
txt_dst, client->getFormspecPrepend(), sound);
GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
&input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
return false;
@ -3170,7 +3190,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
} catch (SettingNotFoundException) {
}
#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);
/*
@ -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)
{
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);
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()
{
static std::string formspec_str =
@ -3430,8 +3429,8 @@ void Game::showDeathFormspec()
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
auto *&formspec = m_game_ui->getFormspecGUI();
GUIFormSpecMenu::create(formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend(), sound);
GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
&input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_respawn");
}
@ -3572,8 +3571,8 @@ void Game::showPauseMenu()
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
auto *&formspec = m_game_ui->getFormspecGUI();
GUIFormSpecMenu::create(formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend(), sound);
GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
&input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_continue");
formspec->doPause = true;
@ -3591,6 +3590,7 @@ Game *g_game;
void the_game(bool *kill,
InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &start_data,
std::string &error_message,
ChatBackend &chat_backend,
@ -3607,8 +3607,8 @@ void the_game(bool *kill,
try {
if (game.startup(kill, input, start_data, error_message,
reconnect_requested, &chat_backend)) {
if (game.startup(kill, input, rendering_engine, start_data,
error_message, reconnect_requested, &chat_backend)) {
game.run();
}

View File

@ -76,7 +76,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
class InputHandler;
class ChatBackend; /* to avoid having to include chat.h */
class ChatBackend;
class RenderingEngine;
struct SubgameSpec;
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;
#endif
class GameGlobalShaderConstantSetter : public IShaderConstantSetter
@ -530,38 +526,20 @@ public:
float eye_position_array[3];
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);
#endif
m_eye_position_pixel.set(eye_position_array, services);
m_eye_position_vertex.set(eye_position_array, services);
if (m_client->getMinimap()) {
float minimap_yaw_array[3];
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);
#endif
m_minimap_yaw.set(minimap_yaw_array, services);
}
float camera_offset_array[3];
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);
#endif
m_camera_offset_pixel.set(camera_offset_array, services);
m_camera_offset_vertex.set(camera_offset_array, services);
@ -673,6 +651,7 @@ public:
bool startup(bool *kill,
InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &game_params,
std::string &error_message,
bool *reconnect,
@ -682,8 +661,6 @@ public:
void run();
void shutdown();
void extendedResourceCleanup();
// Basic initialisation
bool init(const std::string &map_dir, const std::string &address,
u16 port, const SubgameSpec &gamespec);
@ -881,6 +858,7 @@ public:
these items (e.g. device)
*/
IrrlichtDevice *device;
RenderingEngine *m_rendering_engine;
video::IVideoDriver *driver;
scene::ISceneManager *smgr;
bool *kill;
@ -936,6 +914,7 @@ extern Game *g_game;
void the_game(bool *kill,
InputHandler *input,
RenderingEngine *rendering_engine,
const GameStartData &start_data,
std::string &error_message,
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,
false, guiroot);
// First line of debug text
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@ -102,7 +102,8 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
v3f player_position = player->getPosition();
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
v2u32 screensize = RenderingEngine::getWindowSize();
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());
m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y));
}
m_guitext_coords->setVisible(show_coords);
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
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();
if (m_flags.show_debug)
@ -276,7 +277,7 @@ void GameUI::updateProfiler()
core::position2di upper_left(6, 50);
core::position2di lower_right = upper_left;
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));
}

View File

@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include <cstdio>
#include "client/renderingengine.h"
#include "client/tile.h" // hasNPotSupport()
/* Maintain a static cache to store the images that correspond to textures
* 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"))
return src;
srcimg = driver->createImageFromData(src->getColorFormat(),
src->getSize(), src->lock(), false);
src->getSize(), src->lock(video::ETLM_READ_ONLY), false);
src->unlock();
g_imgCache[origname] = srcimg;
}
@ -117,7 +116,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
#if ENABLE_GLES
// Some platforms are picky about textures being powers of 2, so expand
// 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(),
core::dimension2d<u32>(npot2((u32)destrect.getWidth()),
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 CROSSHAIR_LINE_SIZE 10
Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
Hud::Hud(Client *client, LocalPlayer *player,
Inventory *inventory)
{
driver = RenderingEngine::get_video_driver();
this->guienv = guienv;
this->client = client;
this->player = player;
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;
scene::ICameraSceneNode* camera =
RenderingEngine::get_scene_manager()->getActiveCamera();
client->getSceneManager()->getActiveCamera();
w_pos -= intToFloat(camera_offset, BS);
core::matrix4 trans = camera->getProjectionMatrix();
trans *= camera->getViewMatrix();
@ -336,22 +335,22 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
irr::gui::IGUIFont* font = g_fontengine->getFont();
// 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++) {
HudElement *e = player->getHud(i);
if (!e)
continue;
auto it = ids.begin();
while (it != ids.end() && player->getHud(*it)->z_index <= e->z_index)
auto it = elems.begin();
while (it != elems.end() && (*it)->z_index <= e->z_index)
++it;
ids.insert(it, i);
elems.insert(it, e);
}
for (size_t i : ids) {
HudElement *e = player->getHud(i);
for (HudElement *e : elems) {
v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 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
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);
int angle = - fore.getHorizontalAngle().Y;
@ -522,8 +521,8 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
client->getMinimap()->drawMinimap(rect);
break; }
default:
infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
" of hud element ID " << i << " due to unrecognized type" << std::endl;
infostream << "Hud::drawLuaElements: ignoring drawform " << e->type
<< " 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);
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 <=
g_settings->getFloat("hud_hotbar_max_width")) {
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)
{
m_camera_offset = camera_offset;
@ -908,7 +955,7 @@ void Hud::updateSelectionMesh(const v3s16 &camera_offset)
}
void Hud::resizeHotbar() {
const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
const v2u32 &window_size = RenderingEngine::getWindowSize();
if (m_screensize != window_size) {
m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
@ -945,10 +992,18 @@ void drawItemStack(
return;
}
const ItemDefinition &def = item.getDefinition(client->idef());
ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
const static thread_local bool enable_animations =
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;
driver->clearBuffers(video::ECBF_DEPTH);
s32 delta = 0;
@ -992,9 +1047,6 @@ void drawItemStack(
core::matrix4 matrix;
matrix.makeIdentity();
static thread_local bool enable_animations =
g_settings->getBool("inventory_items_animations");
if (enable_animations) {
float timer_f = (float) delta / 5000.f;
matrix.setRotationDegrees(v3f(
@ -1040,15 +1092,29 @@ void drawItemStack(
driver->setTransform(video::ETS_PROJECTION, oldProjMat);
driver->setViewPort(oldViewPort);
// draw the inventory_overlay
if (def.type == ITEM_NODE && def.inventory_image.empty() &&
!def.inventory_overlay.empty()) {
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);
}
draw_overlay = def.type == ITEM_NODE && def.inventory_image.empty();
} else { // Otherwise just draw as 2D
video::ITexture *texture = client->idef()->getInventoryTexture(def.name, client);
if (!texture)
return;
video::SColor color =
client->idef()->getItemstackColor(item, client);
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) {

View File

@ -35,14 +35,6 @@ struct ItemStack;
class Hud
{
public:
video::IVideoDriver *driver;
scene::ISceneManager *smgr;
gui::IGUIEnvironment *guienv;
Client *client;
LocalPlayer *player;
Inventory *inventory;
ITextureSource *tsrc;
video::SColor crosshair_argb;
video::SColor selectionbox_argb;
@ -55,10 +47,13 @@ public:
bool pointing_at_object = false;
Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
Hud(Client *client, LocalPlayer *player,
Inventory *inventory);
~Hud();
void toggleBlockBounds();
void drawBlockBounds();
void drawHotbar(u16 playeritem);
void resizeHotbar();
void drawCrosshair();
@ -103,6 +98,12 @@ private:
void drawCompassRotate(HudElement *e, video::ITexture *texture,
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_scale_factor;
v3s16 m_camera_offset;
@ -125,6 +126,14 @@ private:
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
{
HIGHLIGHT_BOX,

View File

@ -19,63 +19,134 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "imagefilters.h"
#include "util/numeric.h"
#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
* appearing at borders when blending. This is because many PNG optimizers
* 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.
*
* Parameter "threshold" is the alpha level below which pixels are considered
* transparent. Should be 127 for 3d where alpha is threshold, but 0 for
* 2d where alpha is blended.
* transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF,
* 0 when alpha blending is used.
*/
void imageCleanTransparent(video::IImage *src, u32 threshold)
{
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.
for (u32 ctry = 0; ctry < dim.Height; ctry++)
for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) {
if (src->getPixel(ctrx, ctry).getAlpha() > threshold)
bitmap.set(ctrx, ctry);
}
// Ignore opaque pixels.
irr::video::SColor c = src->getPixel(ctrx, ctry);
if (c.getAlpha() > threshold)
// Exit early if all pixels opaque
if (bitmap.all())
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;
// 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;
// Walk each neighbor pixel (clipped to image bounds).
// Walk each neighbor pixel (clipped to image bounds)
for (u32 sy = (ctry < 1) ? 0 : (ctry - 1);
sy <= (ctry + 1) && sy < dim.Height; sy++)
for (u32 sx = (ctrx < 1) ? 0 : (ctrx - 1);
sx <= (ctrx + 1) && sx < dim.Width; sx++) {
// Ignore transparent pixels.
irr::video::SColor d = src->getPixel(sx, sy);
if (d.getAlpha() <= threshold)
// Ignore pixels we haven't processed
if (!bitmap.get(sx, sy))
continue;
// Add RGB values weighted by alpha.
u32 a = d.getAlpha();
// Add RGB values weighted by alpha IF the pixel is opaque, otherwise
// 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;
sr += a * d.getRed();
sg += a * d.getGreen();
sb += a * d.getBlue();
}
// If we found any neighbor RGB data, set pixel to average
// weighted by alpha.
// Set pixel to average weighted by alpha
if (ss > 0) {
c.setRed(sr / ss);
c.setGreen(sg / ss);
c.setBlue(sb / ss);
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

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
* appearing at borders when blending. This is because many PNG optimizers
* 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.
*
* Parameter "threshold" is the alpha level below which pixels are considered
* transparent. Should be 127 for 3d where alpha is threshold, but 0 for
* 2d where alpha is blended.
* transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF,
* 0 when alpha blending is used.
*/
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::CINEMATIC] = getKeySetting("keymap_cinematic");
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_CHAT] = getKeySetting("keymap_toggle_chat");
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_APPS, N_("Apps"))
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_2, "OEM 2") // different chars (on different platforms too) and thus w/o char
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_AX, "OEM AX")
DEFINEKEY1(KEY_OEM_102, "OEM 102")
#endif
DEFINEKEY1(KEY_ATTN, "Attn")
DEFINEKEY1(KEY_CRSEL, "CrSel")
DEFINEKEY1(KEY_EXSEL, "ExSel")

View File

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

View File

@ -1140,8 +1140,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
*/
{
MapblockMeshGenerator generator(data, &collector);
generator.generate();
MapblockMeshGenerator(data, &collector,
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 <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)
{
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
video::ITexture* texture = m_tsrc->getTexture(data->mode.texture);
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();
auto dim = image->getDimension();
@ -576,7 +577,7 @@ scene::SMeshBuffer *Minimap::getMinimapMeshBuffer()
void Minimap::drawMinimap()
{
// Non hud managed minimap drawing (legacy minimap)
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
v2u32 screensize = RenderingEngine::getWindowSize();
const u32 size = 0.25 * screensize.Y;
drawMinimap(core::rect<s32>(

View File

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

View File

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

View File

@ -159,7 +159,7 @@ RenderingEngine::~RenderingEngine()
s_singleton = nullptr;
}
v2u32 RenderingEngine::getWindowSize() const
v2u32 RenderingEngine::_getWindowSize() const
{
if (core)
return core->getVirtualSize();
@ -225,6 +225,20 @@ bool RenderingEngine::print_video_modes()
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)
{
// 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:
hWnd = reinterpret_cast<HWND>(exposedData.D3D9.HWnd);
break;
#if ENABLE_GLES
case video::EDT_OGLES1:
case video::EDT_OGLES2:
#endif
case video::EDT_OPENGL:
hWnd = reinterpret_cast<HWND>(exposedData.OpenGLWin32.HWnd);
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.
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,
int percent, bool clouds)
{
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
v2u32 screensize = getWindowSize();
v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight());
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.
*/
void RenderingEngine::_draw_menu_scene(gui::IGUIEnvironment *guienv,
void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv,
float dtime, bool 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;
}
void RenderingEngine::_initialize(Client *client, Hud *hud)
void RenderingEngine::initialize(Client *client, Hud *hud)
{
const std::string &draw_mode = g_settings->get("3d_mode");
core.reset(createRenderingCore(draw_mode, m_device, client, hud));
core->initialize();
}
void RenderingEngine::_finalize()
void RenderingEngine::finalize()
{
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)
{
core->draw(skycolor, show_hud, show_minimap, draw_wield_tool, draw_crosshair);

View File

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

View File

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

View File

@ -53,10 +53,12 @@ static video::SMaterial baseMaterial()
return mat;
};
Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) :
scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
RenderingEngine::get_scene_manager(), id)
Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc) :
scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
rendering_engine->get_scene_manager(), id)
{
m_seed = (u64)myrand() << 32 | myrand();
setAutomaticCulling(scene::EAC_OFF);
m_box.MaxEdge.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.
setSkyDefaults();
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) ?
tsrc->getTextureForMesh(m_moon_params.texture) : NULL;
tsrc->getTextureForMesh(m_moon_params.texture) : nullptr;
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) ?
tsrc->getTexture(m_moon_params.tonemap) : NULL;
tsrc->getTexture(m_moon_params.tonemap) : nullptr;
if (m_sun_texture) {
m_materials[3] = baseMaterial();
@ -744,14 +746,14 @@ void Sky::place_sky_body(
}
}
void Sky::setSunTexture(std::string sun_texture,
std::string sun_tonemap, ITextureSource *tsrc)
void Sky::setSunTexture(const std::string &sun_texture,
const std::string &sun_tonemap, ITextureSource *tsrc)
{
// Ignore matching textures (with modifiers) entirely,
// but lets at least update the tonemap before hand.
m_sun_params.tonemap = sun_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;
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)
{
// Ignore matching textures (with modifiers) entirely.
@ -792,14 +794,14 @@ void Sky::setSunriseTexture(std::string sunglow_texture,
);
}
void Sky::setMoonTexture(std::string moon_texture,
std::string moon_tonemap, ITextureSource *tsrc)
void Sky::setMoonTexture(const std::string &moon_texture,
const std::string &moon_tonemap, ITextureSource *tsrc)
{
// Ignore matching textures (with modifiers) entirely,
// but lets at least update the tonemap before hand.
m_moon_params.tonemap = moon_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;
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.
if (m_star_params.count != star_count || force_update) {
m_star_params.count = star_count;
m_seed = (u64)myrand() << 32 | myrand();
updateStars();
}
}
@ -893,7 +894,7 @@ void Sky::setSkyColors(const SkyColor &sky_color)
}
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:
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;
}
void Sky::addTextureToSkybox(std::string texture, int material_id,
void Sky::addTextureToSkybox(const std::string &texture, int material_id,
ITextureSource *tsrc)
{
// Sanity check for more than six textures.

View File

@ -36,7 +36,7 @@ class Sky : public scene::ISceneNode
{
public:
//! constructor
Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc);
Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc);
virtual void OnRegisterSceneNode();
@ -65,15 +65,15 @@ public:
}
void setSunVisible(bool sun_visible) { m_sun_params.visible = sun_visible; }
void setSunTexture(std::string sun_texture,
std::string sun_tonemap, ITextureSource *tsrc);
void setSunTexture(const std::string &sun_texture,
const std::string &sun_tonemap, ITextureSource *tsrc);
void setSunScale(f32 sun_scale) { m_sun_params.scale = sun_scale; }
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 setMoonTexture(std::string moon_texture,
std::string moon_tonemap, ITextureSource *tsrc);
void setMoonTexture(const std::string &moon_texture,
const std::string &moon_tonemap, ITextureSource *tsrc);
void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; }
void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; }
@ -87,21 +87,21 @@ public:
void setVisible(bool visible) { m_visible = visible; }
// Set only from set_sky API
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;
}
void overrideColors(const video::SColor &bgcolor, const video::SColor &skycolor)
void overrideColors(video::SColor bgcolor, video::SColor skycolor)
{
m_bgcolor = bgcolor;
m_skycolor = skycolor;
}
void setSkyColors(const SkyColor &sky_color);
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 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);
const video::SColorf &getCurrentStarColor() const { return m_star_color; }
@ -126,7 +126,7 @@ private:
}
// 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(
col1.getAlpha() * (1 - factor) + col2.getAlpha() * factor,
@ -135,7 +135,7 @@ private:
col1.getBlue() * (1 - factor) + col2.getBlue() * factor);
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(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 "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
*/
@ -427,6 +418,7 @@ private:
std::unordered_map<std::string, Palette> m_palettes;
// Cached settings needed for making textures from meshes
bool m_setting_mipmap;
bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter;
};
@ -447,6 +439,7 @@ TextureSource::TextureSource()
// Cache some settings
// Note: Since this is only done once, the game must be restarted
// 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_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)
{
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) &&
g_settings->getS32("texture_min_size") > 1);
// Avoid duplicating texture if it won't actually change
@ -1011,42 +1004,19 @@ video::IImage* TextureSource::generateImage(const std::string &name)
#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
* @param image image to check for npot2 alignment
* @param driver driver to use for image operations
* @return image or copy of image aligned to npot2
*/
video::IImage * Align2Npot2(video::IImage * image,
video::IVideoDriver* driver)
video::IImage *Align2Npot2(video::IImage *image,
video::IVideoDriver *driver)
{
if (image == NULL)
return image;
if (hasNPotSupport())
if (driver->queryFeature(video::EVDF_TEXTURE_NPOT))
return image;
core::dimension2d<u32> dim = image->getDimension();
@ -1636,8 +1606,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
return false;
}
// Apply the "clean transparent" filter, if configured.
if (g_settings->getBool("texture_clean_transparent"))
// Apply the "clean transparent" filter, if needed
if (m_setting_mipmap || g_settings->getBool("texture_clean_transparent"))
imageCleanTransparent(baseimg, 127);
/* Upscale textures to user's requested minimum size. This is a trick to make

View File

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

View File

@ -294,9 +294,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
}
material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter);
// 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);
#endif
if (m_enable_shaders) {
material.setTexture(2, tsrc->getShaderFlagsTexture(false));
}
@ -309,18 +307,21 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
MeshMakeData mesh_make_data(client, false);
MeshCollector collector;
mesh_make_data.setSmoothLighting(false);
MapblockMeshGenerator gen(&mesh_make_data, &collector);
MapblockMeshGenerator gen(&mesh_make_data, &collector,
client->getSceneManager()->getMeshManipulator());
if (n.getParam2()) {
// keep it
} else if (f.param_type_2 == CPT2_WALLMOUNTED ||
f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
if (f.drawtype == NDT_TORCHLIKE)
n.setParam2(1);
else if (f.drawtype == NDT_SIGNLIKE ||
if (f.drawtype == NDT_TORCHLIKE ||
f.drawtype == NDT_SIGNLIKE ||
f.drawtype == NDT_NODEBOX ||
f.drawtype == NDT_MESH)
f.drawtype == NDT_MESH) {
n.setParam2(4);
}
} else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) {
n.setParam2(1);
}
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_RAILLIKE:
case NDT_PLANTLIKE:
case NDT_PLANTLIKE_ROOTED:
case NDT_FLOWINGLIQUID: {
v3f wscale = def.wield_scale;
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);
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_ALLFACES:
case NDT_LIQUID:
@ -530,7 +539,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
content_t id = ndef->getId(def.name);
FATAL_ERROR_IF(!g_extrusion_mesh_cache, "Extrusion mesh cache is not yet initialized");
scene::SMesh *mesh = nullptr;
// Shading is on by default

View File

@ -671,7 +671,6 @@ void ClientInterface::UpdatePlayerList()
std::vector<session_t> clients = getClientIDs();
m_clients_names.clear();
if (!clients.empty())
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 <vector>
#include <set>
#include <memory>
#include <mutex>
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.
*/
#include <vector>
#include <iostream>
#include <sstream>
#include <memory>
#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)
{

View File

@ -22,9 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <json/json.h>
#include <ostream>
Json::Value fetchJsonValue(const std::string &url,
std::vector<std::string> *extra_headers);
void fastWriteJson(const Json::Value &value, std::ostream &to);
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_mapblock_limit", "7500");
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_file_download_timeout", "300000");
settings->setDefault("curl_verify_cert", "true");
@ -156,6 +156,7 @@ void set_default_settings()
settings->setDefault("keymap_increase_volume", "");
settings->setDefault("keymap_decrease_volume", "");
settings->setDefault("keymap_cinematic", "");
settings->setDefault("keymap_toggle_block_bounds", "");
settings->setDefault("keymap_toggle_hud", "KEY_F1");
settings->setDefault("keymap_toggle_chat", "KEY_F2");
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("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);
settings->setDefault("fallback_font_size", font_size_str);
#else
settings->setDefault("freetype", "false");
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;
}
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)
{
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 ":"
#endif
namespace irr { namespace io {
class IFileSystem;
}}
namespace fs
{
@ -125,6 +129,8 @@ const char *GetFilenameFromPath(const char *path);
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 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")
return FM_Mono;
else if (str == "FM_Fallback")
return FM_Fallback;
return _FM_Fallback;
else if (str == "FM_Simple")
return FM_Simple;
else if (str == "FM_SimpleMono")

View File

@ -30,7 +30,7 @@ using namespace gui;
GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
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)
: GUIButton (environment, parent, id, rectangle, tsrc, noclip)
{
@ -44,7 +44,7 @@ GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
GUIButtonItemImage *GUIButtonItemImage::addButton(IGUIEnvironment *environment,
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)
{
GUIButtonItemImage *button = new GUIButtonItemImage(environment,

View File

@ -33,13 +33,13 @@ public:
//! constructor
GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
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
static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment,
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
IGUIElement *parent, s32 id, const wchar_t *text, std::string item,
Client *client);
IGUIElement *parent, s32 id, const wchar_t *text,
const std::string &item, Client *client);
private:
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.
*/
#include "IrrCompileConfig.h"
#include "guiChatConsole.h"
#include "chat.h"
#include "client/client.h"
@ -326,7 +327,6 @@ void GUIChatConsole::drawText()
tmp->draw(
fragment.text,
destrect,
video::SColor(255, 255, 255, 255),
false,
false,
&AbsoluteClippingRect);
@ -619,6 +619,13 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
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;
}

View File

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

View File

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

View File

@ -138,6 +138,8 @@ public:
virtual void deserializeAttributes(
io::IAttributes *in, io::SAttributeReadWriteOptions *options);
virtual bool acceptsIME() { return isEnabled() && m_writable; };
protected:
virtual void breakText() = 0;
@ -156,6 +158,7 @@ protected:
virtual s32 getCursorPos(s32 x, s32 y) = 0;
bool processKey(const SEvent &event);
virtual void inputString(const core::stringw &str);
virtual void inputChar(wchar_t c);
//! 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