From f85e9ab9254e2ae4ac13170f9edea00fb8d931a2 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Wed, 17 Feb 2021 19:51:28 +0000 Subject: [PATCH] Add nametag background setting and object property (#10937) --- .clang-format | 1 + builtin/settingtypes.txt | 4 ++ doc/lua_api.txt | 18 +++-- games/devtest/mods/testentities/visuals.lua | 16 ++++- src/activeobjectmgr.h | 3 +- src/client/camera.cpp | 33 ++++----- src/client/camera.h | 47 +++++++++---- src/client/content_cao.cpp | 12 ++-- src/defaultsettings.cpp | 1 + src/object_properties.cpp | 22 ++++++ src/object_properties.h | 2 + src/script/common/c_content.cpp | 18 +++++ src/script/common/helper.cpp | 24 ++++--- src/script/common/helper.h | 3 +- src/script/lua_api/l_object.cpp | 29 +++++++- src/util/Optional.h | 77 +++++++++++++++++++++ src/util/serialize.h | 2 +- 17 files changed, 254 insertions(+), 58 deletions(-) create mode 100644 src/util/Optional.h diff --git a/.clang-format b/.clang-format index dc7380ffd..0db8ab167 100644 --- a/.clang-format +++ b/.clang-format @@ -29,3 +29,4 @@ AlignAfterOpenBracket: DontAlign ContinuationIndentWidth: 16 ConstructorInitializerIndentWidth: 16 BreakConstructorInitializers: AfterColon +AlwaysBreakTemplateDeclarations: Yes diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 8b6227b37..f800f71ab 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -451,6 +451,10 @@ keymap_decrease_viewing_range_min (View range decrease key) key - [**Basic] +# Whether nametag backgrounds should be shown by default. +# Mods may still set a background. +show_nametag_backgrounds (Show nametag backgrounds by default) bool true + # Enable vertex buffer objects. # This should greatly improve graphics performance. enable_vbo (VBO) bool true diff --git a/doc/lua_api.txt b/doc/lua_api.txt index a09b98924..a9c3bcdd9 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -6274,15 +6274,21 @@ object you are working with still exists. * `get_nametag_attributes()` * returns a table with the attributes of the nametag of an object * { - color = {a=0..255, r=0..255, g=0..255, b=0..255}, text = "", + color = {a=0..255, r=0..255, g=0..255, b=0..255}, + bgcolor = {a=0..255, r=0..255, g=0..255, b=0..255}, } * `set_nametag_attributes(attributes)` * sets the attributes of the nametag of an object * `attributes`: { - color = ColorSpec, text = "My Nametag", + color = ColorSpec, + -- ^ Text color + bgcolor = ColorSpec or false, + -- ^ Sets background color of nametag + -- `false` will cause the background to be set automatically based on user settings + -- Default: false } #### Lua entity only (no-op for other objects) @@ -6956,9 +6962,13 @@ Player properties need to be saved manually. -- For all other objects, a nil or empty string removes the nametag. -- To hide a nametag, set its color alpha to zero. That will disable it entirely. - nametag_color = , - -- Sets color of nametag + -- Sets text color of nametag + + nametag_bgcolor = , + -- Sets background color of nametag + -- `false` will cause the background to be set automatically based on user settings. + -- Default: false infotext = "", -- By default empty, text to be shown when pointed at object diff --git a/games/devtest/mods/testentities/visuals.lua b/games/devtest/mods/testentities/visuals.lua index e3b758329..e382ec44c 100644 --- a/games/devtest/mods/testentities/visuals.lua +++ b/games/devtest/mods/testentities/visuals.lua @@ -103,23 +103,35 @@ minetest.register_entity("testentities:nametag", { on_activate = function(self, staticdata) if staticdata ~= "" then - self.color = minetest.deserialize(staticdata).color + local data = minetest.deserialize(staticdata) + self.color = data.color + self.bgcolor = data.bgcolor else self.color = { r = math.random(0, 255), g = math.random(0, 255), b = math.random(0, 255), } + + if math.random(0, 10) > 5 then + self.bgcolor = { + r = math.random(0, 255), + g = math.random(0, 255), + b = math.random(0, 255), + a = math.random(0, 255), + } + end end assert(self.color) self.object:set_properties({ nametag = tostring(math.random(1000, 10000)), nametag_color = self.color, + nametag_bgcolor = self.bgcolor, }) end, get_staticdata = function(self) - return minetest.serialize({ color = self.color }) + return minetest.serialize({ color = self.color, bgcolor = self.bgcolor }) end, }) diff --git a/src/activeobjectmgr.h b/src/activeobjectmgr.h index 95e7d3344..aa0538e60 100644 --- a/src/activeobjectmgr.h +++ b/src/activeobjectmgr.h @@ -25,7 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., class TestClientActiveObjectMgr; class TestServerActiveObjectMgr; -template class ActiveObjectMgr +template +class ActiveObjectMgr { friend class ::TestClientActiveObjectMgr; friend class ::TestServerActiveObjectMgr; diff --git a/src/client/camera.cpp b/src/client/camera.cpp index 9a08254b4..350b685e1 100644 --- a/src/client/camera.cpp +++ b/src/client/camera.cpp @@ -79,6 +79,7 @@ Camera::Camera(MapDrawControl &draw_control, Client *client): m_cache_fov = std::fmax(g_settings->getFloat("fov"), 45.0f); m_arm_inertia = g_settings->getBool("arm_inertia"); m_nametags.clear(); + m_show_nametag_backgrounds = g_settings->getBool("show_nametag_backgrounds"); } Camera::~Camera() @@ -696,18 +697,14 @@ void Camera::drawNametags() v2u32 screensize = driver->getScreenSize(); for (const Nametag *nametag : m_nametags) { - if (nametag->nametag_color.getAlpha() == 0) { - // Enforce hiding nametag, - // because if freetype is enabled, a grey - // shadow can remain. - continue; - } - v3f pos = nametag->parent_node->getAbsolutePosition() + nametag->nametag_pos * BS; + // Nametags are hidden in GenericCAO::updateNametag() + + v3f pos = nametag->parent_node->getAbsolutePosition() + nametag->pos * BS; f32 transformed_pos[4] = { pos.X, pos.Y, pos.Z, 1.0f }; trans.multiplyWith1x4Matrix(transformed_pos); if (transformed_pos[3] > 0) { std::wstring nametag_colorless = - unescape_translate(utf8_to_wide(nametag->nametag_text)); + unescape_translate(utf8_to_wide(nametag->text)); core::dimension2d textsize = font->getDimension( nametag_colorless.c_str()); f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f : @@ -720,26 +717,22 @@ void Camera::drawNametags() core::rect size(0, 0, textsize.Width, textsize.Height); core::rect bg_size(-2, 0, textsize.Width+2, textsize.Height); - video::SColor textColor = nametag->nametag_color; - - bool darkBackground = textColor.getLuminance() > 186; - video::SColor backgroundColor = darkBackground - ? video::SColor(50, 50, 50, 50) - : video::SColor(50, 255, 255, 255); - driver->draw2DRectangle(backgroundColor, bg_size + screen_pos); + auto bgcolor = nametag->getBgColor(m_show_nametag_backgrounds); + if (bgcolor.getAlpha() != 0) + driver->draw2DRectangle(bgcolor, bg_size + screen_pos); font->draw( - translate_string(utf8_to_wide(nametag->nametag_text)).c_str(), - size + screen_pos, textColor); + translate_string(utf8_to_wide(nametag->text)).c_str(), + size + screen_pos, nametag->textcolor); } } } Nametag *Camera::addNametag(scene::ISceneNode *parent_node, - const std::string &nametag_text, video::SColor nametag_color, - const v3f &pos) + const std::string &text, video::SColor textcolor, + Optional bgcolor, const v3f &pos) { - Nametag *nametag = new Nametag(parent_node, nametag_text, nametag_color, pos); + Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos); m_nametags.push_back(nametag); return nametag; } diff --git a/src/client/camera.h b/src/client/camera.h index 16a1961be..6fd8d9aa7 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -25,27 +25,47 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "util/Optional.h" class LocalPlayer; struct MapDrawControl; class Client; class WieldMeshSceneNode; -struct Nametag { +struct Nametag +{ + scene::ISceneNode *parent_node; + std::string text; + video::SColor textcolor; + Optional bgcolor; + v3f pos; + Nametag(scene::ISceneNode *a_parent_node, - const std::string &a_nametag_text, - const video::SColor &a_nametag_color, - const v3f &a_nametag_pos): + const std::string &text, + const video::SColor &textcolor, + const Optional &bgcolor, + const v3f &pos): parent_node(a_parent_node), - nametag_text(a_nametag_text), - nametag_color(a_nametag_color), - nametag_pos(a_nametag_pos) + text(text), + textcolor(textcolor), + bgcolor(bgcolor), + pos(pos) { } - scene::ISceneNode *parent_node; - std::string nametag_text; - video::SColor nametag_color; - v3f nametag_pos; + + video::SColor getBgColor(bool use_fallback) const + { + if (bgcolor) + return bgcolor.value(); + else if (!use_fallback) + return video::SColor(0, 0, 0, 0); + else if (textcolor.getLuminance() > 186) + // Dark background for light text + return video::SColor(50, 50, 50, 50); + else + // Light background for dark text + return video::SColor(50, 255, 255, 255); + } }; enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT}; @@ -164,8 +184,8 @@ public: } Nametag *addNametag(scene::ISceneNode *parent_node, - const std::string &nametag_text, video::SColor nametag_color, - const v3f &pos); + const std::string &text, video::SColor textcolor, + Optional bgcolor, const v3f &pos); void removeNametag(Nametag *nametag); @@ -245,4 +265,5 @@ private: bool m_arm_inertia; std::list m_nametags; + bool m_show_nametag_backgrounds; }; diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index c65977b44..97ae9afc4 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -934,7 +934,7 @@ void GenericCAO::updateNametag() if (m_is_local_player) // No nametag for local player return; - if (m_prop.nametag.empty()) { + if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) { // Delete nametag if (m_nametag) { m_client->getCamera()->removeNametag(m_nametag); @@ -952,12 +952,14 @@ void GenericCAO::updateNametag() if (!m_nametag) { // Add nametag m_nametag = m_client->getCamera()->addNametag(node, - m_prop.nametag, m_prop.nametag_color, pos); + m_prop.nametag, m_prop.nametag_color, + m_prop.nametag_bgcolor, pos); } else { // Update nametag - m_nametag->nametag_text = m_prop.nametag; - m_nametag->nametag_color = m_prop.nametag_color; - m_nametag->nametag_pos = pos; + m_nametag->text = m_prop.nametag; + m_nametag->textcolor = m_prop.nametag_color; + m_nametag->bgcolor = m_prop.nametag_bgcolor; + m_nametag->pos = pos; } } diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 41c4922a4..cda953082 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -240,6 +240,7 @@ void set_default_settings() #endif settings->setDefault("enable_particles", "true"); settings->setDefault("arm_inertia", "true"); + settings->setDefault("show_nametag_backgrounds", "true"); settings->setDefault("enable_minimap", "true"); settings->setDefault("minimap_shape_round", "true"); diff --git a/src/object_properties.cpp b/src/object_properties.cpp index f31773060..2eebc27d6 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/basic_macros.h" #include +static const video::SColor NULL_BGCOLOR{0, 1, 1, 1}; + ObjectProperties::ObjectProperties() { textures.emplace_back("unknown_object.png"); @@ -62,6 +64,13 @@ std::string ObjectProperties::dump() os << ", nametag=" << nametag; os << ", nametag_color=" << "\"" << nametag_color.getAlpha() << "," << nametag_color.getRed() << "," << nametag_color.getGreen() << "," << nametag_color.getBlue() << "\" "; + + if (nametag_bgcolor) + os << ", nametag_bgcolor=" << "\"" << nametag_color.getAlpha() << "," << nametag_color.getRed() + << "," << nametag_color.getGreen() << "," << nametag_color.getBlue() << "\" "; + else + os << ", nametag_bgcolor=null "; + os << ", selectionbox=" << PP(selectionbox.MinEdge) << "," << PP(selectionbox.MaxEdge); os << ", pointable=" << pointable; os << ", static_save=" << static_save; @@ -121,6 +130,13 @@ void ObjectProperties::serialize(std::ostream &os) const writeU8(os, shaded); writeU8(os, show_on_minimap); + if (!nametag_bgcolor) + writeARGB8(os, NULL_BGCOLOR); + else if (nametag_bgcolor.value().getAlpha() == 0) + writeARGB8(os, video::SColor(0, 0, 0, 0)); + else + writeARGB8(os, nametag_bgcolor.value()); + // Add stuff only at the bottom. // Never remove anything, because we don't want new versions of this } @@ -182,5 +198,11 @@ void ObjectProperties::deSerialize(std::istream &is) if (is.eof()) return; show_on_minimap = tmp; + + auto bgcolor = readARGB8(is); + if (bgcolor != NULL_BGCOLOR) + nametag_bgcolor = bgcolor; + else + nametag_bgcolor = nullopt; } catch (SerializationError &e) {} } diff --git a/src/object_properties.h b/src/object_properties.h index adb483527..db28eebfd 100644 --- a/src/object_properties.h +++ b/src/object_properties.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "util/Optional.h" struct ObjectProperties { @@ -53,6 +54,7 @@ struct ObjectProperties s8 glow = 0; std::string nametag = ""; video::SColor nametag_color = video::SColor(255, 255, 255, 255); + Optional nametag_bgcolor = nullopt; f32 automatic_face_movement_max_rotation_per_sec = -1.0f; std::string infotext; //! For dropped items, this contains item information. diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 2f9fbd74b..6995f6b61 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -312,6 +312,17 @@ void read_object_properties(lua_State *L, int index, prop->nametag_color = color; } lua_pop(L, 1); + lua_getfield(L, -1, "nametag_bgcolor"); + if (!lua_isnil(L, -1)) { + if (lua_toboolean(L, -1)) { + video::SColor color; + if (read_color(L, -1, &color)) + prop->nametag_bgcolor = color; + } else { + prop->nametag_bgcolor = nullopt; + } + } + lua_pop(L, 1); lua_getfield(L, -1, "automatic_face_movement_max_rotation_per_sec"); if (lua_isnumber(L, -1)) { @@ -403,6 +414,13 @@ void push_object_properties(lua_State *L, ObjectProperties *prop) lua_setfield(L, -2, "nametag"); push_ARGB8(L, prop->nametag_color); lua_setfield(L, -2, "nametag_color"); + if (prop->nametag_bgcolor) { + push_ARGB8(L, prop->nametag_bgcolor.value()); + lua_setfield(L, -2, "nametag_bgcolor"); + } else { + lua_pushboolean(L, false); + lua_setfield(L, -2, "nametag_bgcolor"); + } lua_pushnumber(L, prop->automatic_face_movement_max_rotation_per_sec); lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec"); lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size()); diff --git a/src/script/common/helper.cpp b/src/script/common/helper.cpp index 488144790..fbf24e1b7 100644 --- a/src/script/common/helper.cpp +++ b/src/script/common/helper.cpp @@ -50,22 +50,26 @@ bool LuaHelper::isNaN(lua_State *L, int idx) /* * Read template functions */ -template <> bool LuaHelper::readParam(lua_State *L, int index) +template <> +bool LuaHelper::readParam(lua_State *L, int index) { return lua_toboolean(L, index) != 0; } -template <> s16 LuaHelper::readParam(lua_State *L, int index) +template <> +s16 LuaHelper::readParam(lua_State *L, int index) { return lua_tonumber(L, index); } -template <> int LuaHelper::readParam(lua_State *L, int index) +template <> +int LuaHelper::readParam(lua_State *L, int index) { return luaL_checkint(L, index); } -template <> float LuaHelper::readParam(lua_State *L, int index) +template <> +float LuaHelper::readParam(lua_State *L, int index) { if (isNaN(L, index)) throw LuaError("NaN value is not allowed."); @@ -73,7 +77,8 @@ template <> float LuaHelper::readParam(lua_State *L, int index) return (float)luaL_checknumber(L, index); } -template <> v2s16 LuaHelper::readParam(lua_State *L, int index) +template <> +v2s16 LuaHelper::readParam(lua_State *L, int index) { v2s16 p; CHECK_POS_TAB(index); @@ -88,7 +93,8 @@ template <> v2s16 LuaHelper::readParam(lua_State *L, int index) return p; } -template <> v2f LuaHelper::readParam(lua_State *L, int index) +template <> +v2f LuaHelper::readParam(lua_State *L, int index) { v2f p; CHECK_POS_TAB(index); @@ -103,7 +109,8 @@ template <> v2f LuaHelper::readParam(lua_State *L, int index) return p; } -template <> v3f LuaHelper::readParam(lua_State *L, int index) +template <> +v3f LuaHelper::readParam(lua_State *L, int index) { v3f p; CHECK_POS_TAB(index); @@ -122,7 +129,8 @@ template <> v3f LuaHelper::readParam(lua_State *L, int index) return p; } -template <> std::string LuaHelper::readParam(lua_State *L, int index) +template <> +std::string LuaHelper::readParam(lua_State *L, int index) { size_t length; std::string result; diff --git a/src/script/common/helper.h b/src/script/common/helper.h index 7a794dc9b..6491e73cf 100644 --- a/src/script/common/helper.h +++ b/src/script/common/helper.h @@ -38,7 +38,8 @@ protected: * @param index Lua Index to read * @return read value from Lua */ - template static T readParam(lua_State *L, int index); + template + static T readParam(lua_State *L, int index); /** * Read a value using a template type T from Lua State L and index diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 07aa3f7c9..8ae99b929 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -737,6 +737,18 @@ int ObjectRef::l_set_nametag_attributes(lua_State *L) } lua_pop(L, 1); + lua_getfield(L, -1, "bgcolor"); + if (!lua_isnil(L, -1)) { + if (lua_toboolean(L, -1)) { + video::SColor color; + if (read_color(L, -1, &color)) + prop->nametag_bgcolor = color; + } else { + prop->nametag_bgcolor = nullopt; + } + } + lua_pop(L, 1); + std::string nametag = getstringfield_default(L, 2, "text", ""); prop->nametag = nametag; @@ -758,13 +770,24 @@ int ObjectRef::l_get_nametag_attributes(lua_State *L) if (!prop) return 0; - video::SColor color = prop->nametag_color; - lua_newtable(L); - push_ARGB8(L, color); + + push_ARGB8(L, prop->nametag_color); lua_setfield(L, -2, "color"); + + if (prop->nametag_bgcolor) { + push_ARGB8(L, prop->nametag_bgcolor.value()); + lua_setfield(L, -2, "bgcolor"); + } else { + lua_pushboolean(L, false); + lua_setfield(L, -2, "bgcolor"); + } + lua_pushstring(L, prop->nametag.c_str()); lua_setfield(L, -2, "text"); + + + return 1; } diff --git a/src/util/Optional.h b/src/util/Optional.h new file mode 100644 index 000000000..9c2842b43 --- /dev/null +++ b/src/util/Optional.h @@ -0,0 +1,77 @@ +/* +Minetest +Copyright (C) 2021 rubenwardy + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +#include "debug.h" + +struct nullopt_t +{ +}; +constexpr nullopt_t nullopt{}; + +/** + * An implementation of optional for C++11, which aims to be + * compatible with a subset of std::optional features. + * + * Unfortunately, Minetest doesn't use C++17 yet. + * + * @tparam T The type to be stored + */ +template +class Optional +{ + bool m_has_value = false; + T m_value; + +public: + Optional() noexcept {} + Optional(nullopt_t) noexcept {} + Optional(const T &value) noexcept : m_has_value(true), m_value(value) {} + Optional(const Optional &other) noexcept : + m_has_value(other.m_has_value), m_value(other.m_value) + { + } + + void operator=(nullopt_t) noexcept { m_has_value = false; } + + void operator=(const Optional &other) noexcept + { + m_has_value = other.m_has_value; + m_value = other.m_value; + } + + T &value() + { + FATAL_ERROR_IF(!m_has_value, "optional doesn't have value"); + return m_value; + } + + const T &value() const + { + FATAL_ERROR_IF(!m_has_value, "optional doesn't have value"); + return m_value; + } + + const T &value_or(const T &def) const { return m_has_value ? m_value : def; } + + bool has_value() const noexcept { return m_has_value; } + + explicit operator bool() const { return m_has_value; } +}; diff --git a/src/util/serialize.h b/src/util/serialize.h index b3ec28eab..15bdd050d 100644 --- a/src/util/serialize.h +++ b/src/util/serialize.h @@ -290,7 +290,7 @@ inline void writeS8(u8 *data, s8 i) inline void writeS16(u8 *data, s16 i) { - writeU16(data, (u16)i); + writeU16(data, (u16)i); } inline void writeS32(u8 *data, s32 i)