diff --git a/doc/lua_api.md b/doc/lua_api.md index ca3a5fee7..c24f63e5f 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -9516,6 +9516,16 @@ Player properties need to be saved manually. -- `false` will cause the background to be set automatically based on user settings. -- Default: false + nametag_fontsize = false, + -- Sets the font size of the nametag in pixels. + -- `false` will cause the size to be set automatically based on user settings. + -- Default: false + + nametag_scale_z = false, + -- If enabled, the nametag will be scaled by Z in screen space, meaning it becomes + -- smaller the further way the object is. + -- Default: false + infotext = "", -- Same as infotext for nodes. Empty by default diff --git a/src/client/camera.cpp b/src/client/camera.cpp index cdc4711c3..8039b64f3 100644 --- a/src/client/camera.cpp +++ b/src/client/camera.cpp @@ -660,9 +660,8 @@ void Camera::drawNametags() auto *font = g_fontengine->getFont(font_size); assert(font); - std::wstring text = - unescape_translate(utf8_to_wide(nametag->text)); - core::dimension2d textsize = font->getDimension(text.c_str()); + std::wstring real_text = translate_string(utf8_to_wide(nametag->text)); + core::dimension2d textsize = font->getDimension(real_text.c_str()); v2s32 screen_pos; screen_pos.X = screensize.X * (0.5f + transformed_pos[0] * zDiv * 0.5f) - textsize.Width / 2; @@ -676,26 +675,24 @@ void Camera::drawNametags() driver->draw2DRectangle(bgcolor, bg_size + screen_pos); } - font->draw( - translate_string(utf8_to_wide(nametag->text)).c_str(), + font->draw(real_text.c_str(), size + screen_pos, nametag->textcolor); } } -Nametag *Camera::addNametag(scene::ISceneNode *parent_node, - const std::string &text, video::SColor textcolor, - std::optional bgcolor, const v3f &pos) +Nametag *Camera::addNametag(const Nametag ¶ms) { - assert(parent_node); - Nametag *nametag = new Nametag{ - parent_node, text, textcolor, bgcolor, std::nullopt, pos, false}; + assert(params.parent_node); + auto *nametag = new Nametag(params); m_nametags.push_back(nametag); return nametag; } void Camera::removeNametag(Nametag *nametag) { - m_nametags.remove(nametag); + auto it = std::find(m_nametags.begin(), m_nametags.end(), nametag); + assert(it != m_nametags.end()); + m_nametags.erase(it); delete nametag; } diff --git a/src/client/camera.h b/src/client/camera.h index 743330fb0..c15cb373b 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -178,9 +178,7 @@ public: return m_camera_mode; } - Nametag *addNametag(scene::ISceneNode *parent_node, - const std::string &text, video::SColor textcolor, - std::optional bgcolor, const v3f &pos); + Nametag *addNametag(const Nametag ¶ms); void removeNametag(Nametag *nametag); diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index ecfe0f2de..f42cd4028 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -930,17 +930,15 @@ void GenericCAO::updateNametag() v3f pos; pos.Y = m_prop.selectionbox.MaxEdge.Y + 0.3f; + // Add or update nametag + Nametag tmp{node, m_prop.nametag, m_prop.nametag_color, + m_prop.nametag_bgcolor, m_prop.nametag_fontsize, pos, + m_prop.nametag_scale_z}; if (!m_nametag) { - // Add nametag - m_nametag = m_client->getCamera()->addNametag(node, - m_prop.nametag, m_prop.nametag_color, - m_prop.nametag_bgcolor, pos); + m_nametag = m_client->getCamera()->addNametag(tmp); + assert(m_nametag); } else { - // Update nametag - m_nametag->text = m_prop.nametag; - m_nametag->textcolor = m_prop.nametag_color; - m_nametag->bgcolor = m_prop.nametag_bgcolor; - m_nametag->pos = pos; + *m_nametag = tmp; } } diff --git a/src/object_properties.cpp b/src/object_properties.cpp index 35bf2e63e..e1538242e 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -34,6 +34,11 @@ ObjectProperties::ObjectProperties() std::string ObjectProperties::dump() const { + const auto &put_color = [] (std::ostream &os, video::SColor color) { + os << "\"" << color.getAlpha() << "," << color.getRed() << "," + << color.getGreen() << "," << color.getBlue() << "\" "; + }; + std::ostringstream os(std::ios::binary); os << "hp_max=" << hp_max; os << ", breath_max=" << breath_max; @@ -49,10 +54,8 @@ std::string ObjectProperties::dump() const } os << "]"; os << ", colors=["; - for (const video::SColor &color : colors) { - os << "\"" << color.getAlpha() << "," << color.getRed() << "," - << color.getGreen() << "," << color.getBlue() << "\" "; - } + for (const video::SColor &color : colors) + put_color(os, color); os << "]"; os << ", spritediv=" << spritediv; os << ", initial_sprite_basepos=" << initial_sprite_basepos; @@ -62,15 +65,18 @@ std::string ObjectProperties::dump() const os << ", backface_culling="<< backface_culling; os << ", glow=" << glow; os << ", nametag=" << nametag; - os << ", nametag_color=" << "\"" << nametag_color.getAlpha() << "," << nametag_color.getRed() - << "," << nametag_color.getGreen() << "," << nametag_color.getBlue() << "\" "; - + os << ", nametag_color="; + put_color(os, nametag_color); + os << ", nametag_bgcolor="; if (nametag_bgcolor) - os << ", nametag_bgcolor=" << "\"" << nametag_color.getAlpha() << "," << nametag_color.getRed() - << "," << nametag_color.getGreen() << "," << nametag_color.getBlue() << "\" "; + put_color(os, nametag_bgcolor.value()); else - os << ", nametag_bgcolor=null "; - + os << "=null "; + os << ", nametag_fontsize="; + if (nametag_fontsize) + os << "=" << nametag_fontsize.value() << " "; + else + os << "=null "; os << ", selectionbox=" << selectionbox.MinEdge << "," << selectionbox.MaxEdge; os << ", rotate_selectionbox=" << rotate_selectionbox; os << ", pointable=" << Pointabilities::toStringPointabilityType(pointable); @@ -83,22 +89,24 @@ std::string ObjectProperties::dump() const os << ", damage_texture_modifier=" << damage_texture_modifier; os << ", shaded=" << shaded; os << ", show_on_minimap=" << show_on_minimap; + os << ", nametag_scale_z=" << nametag_scale_z; return os.str(); } -static auto tie(const ObjectProperties &o) +static inline auto tie(const ObjectProperties &o) { // Make sure to add new members to this list! return std::tie( o.textures, o.colors, o.collisionbox, o.selectionbox, o.visual, o.mesh, o.damage_texture_modifier, o.nametag, o.infotext, o.wield_item, o.visual_size, - o.nametag_color, o.nametag_bgcolor, o.spritediv, o.initial_sprite_basepos, + o.nametag_color, o.nametag_bgcolor, o.nametag_fontsize, o.spritediv, + o.initial_sprite_basepos, o.stepheight, o.automatic_rotate, o.automatic_face_movement_dir_offset, o.automatic_face_movement_max_rotation_per_sec, o.eye_height, o.zoom_fov, o.node, o.hp_max, o.breath_max, o.glow, o.pointable, o.physical, o.collideWithObjects, o.rotate_selectionbox, o.is_visible, o.makes_footstep_sound, o.automatic_face_movement_dir, o.backface_culling, o.static_save, o.use_texture_alpha, - o.shaded, o.show_on_minimap + o.shaded, o.show_on_minimap, o.nametag_scale_z ); } @@ -202,6 +210,13 @@ void ObjectProperties::serialize(std::ostream &os) const writeU8(os, node.getParam1()); writeU8(os, node.getParam2()); + if (!nametag_fontsize) + writeU32(os, U32_MAX); // nil placeholder + else + writeU32(os, nametag_fontsize.value()); + + writeU8(os, nametag_scale_z); + // Add stuff only at the bottom. // Never remove anything, because we don't want new versions of this! } @@ -306,5 +321,14 @@ void ObjectProperties::deSerialize(std::istream &is) node.param1 = readU8(is); node.param2 = readU8(is); + u32 fontsize; + if (!tryRead(fontsize, is)) + return; + if (fontsize != U32_MAX) + nametag_fontsize = fontsize; + else + nametag_fontsize = std::nullopt; + nametag_scale_z = readU8(is); + // Add new properties down here and remember to use either tryRead<> or a try-catch. } diff --git a/src/object_properties.h b/src/object_properties.h index b898c982d..8cfa8cec7 100644 --- a/src/object_properties.h +++ b/src/object_properties.h @@ -56,6 +56,7 @@ struct ObjectProperties f32 automatic_face_movement_max_rotation_per_sec = -1.0f; float eye_height = 1.625f; float zoom_fov = 0.0f; + std::optional nametag_fontsize; MapNode node = MapNode(CONTENT_IGNORE); u16 hp_max = 1; u16 breath_max = 0; @@ -73,6 +74,7 @@ struct ObjectProperties bool use_texture_alpha = false; bool shaded = true; bool show_on_minimap = false; + bool nametag_scale_z = false; ObjectProperties(); diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 91aa5b405..078a17a1d 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -267,7 +267,7 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i) } /******************************************************************************/ -const std::array object_property_keys = { +const std::array object_property_keys = { "hp_max", "breath_max", "physical", @@ -302,6 +302,8 @@ const std::array object_property_keys = { "damage_texture_modifier", "show_on_minimap", // "node" is intentionally not here as it's gated behind `fallback` below! + "nametag_fontsize", + "nametag_scale_z", }; /******************************************************************************/ @@ -467,7 +469,7 @@ void read_object_properties(lua_State *L, int index, lua_pop(L, 1); lua_getfield(L, -1, "nametag_bgcolor"); if (!lua_isnil(L, -1)) { - if (lua_toboolean(L, -1)) { + if (lua_toboolean(L, -1)) { // truthy video::SColor color; if (read_color(L, -1, &color)) prop->nametag_bgcolor = color; @@ -476,6 +478,16 @@ void read_object_properties(lua_State *L, int index, } } lua_pop(L, 1); + lua_getfield(L, -1, "nametag_fontsize"); + if (!lua_isnil(L, -1)) { + if (lua_toboolean(L, -1)) { // truthy + prop->nametag_fontsize = lua_tointeger(L, -1); + } else { + prop->nametag_fontsize = std::nullopt; + } + } + lua_pop(L, 1); + getboolfield(L, -1, "nametag_scale_z", prop->nametag_scale_z); getstringfield(L, -1, "infotext", prop->infotext); getboolfield(L, -1, "static_save", prop->static_save); @@ -577,6 +589,15 @@ void push_object_properties(lua_State *L, const ObjectProperties *prop) lua_pushboolean(L, false); lua_setfield(L, -2, "nametag_bgcolor"); } + if (prop->nametag_fontsize) { + lua_pushinteger(L, prop->nametag_fontsize.value()); + lua_setfield(L, -2, "nametag_fontsize"); + } else { + lua_pushboolean(L, false); + lua_setfield(L, -2, "nametag_fontsize"); + } + lua_pushboolean(L, prop->nametag_scale_z); + lua_setfield(L, -2, "nametag_scale_z"); lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size()); lua_setfield(L, -2, "infotext"); lua_pushboolean(L, prop->static_save); diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index f57c15797..99c243705 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -60,8 +60,7 @@ extern struct EnumString es_TileAnimationType[]; extern struct EnumString es_ItemType[]; extern struct EnumString es_TouchInteractionMode[]; - -extern const std::array object_property_keys; +extern const std::array object_property_keys; void read_content_features(lua_State *L, ContentFeatures &f, int index); void push_content_features(lua_State *L, const ContentFeatures &c);