diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 988ef210e0248..cdea7d4fd8ce5 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -653,9 +653,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) if (!m_prop.is_visible) return; - infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl; + infostream << "GenericCAO::addToScene(): " << + enum_to_string(es_ObjectVisual, m_prop.visual)<< std::endl; - if (m_prop.visual != "node" && m_prop.visual != "wielditem" && m_prop.visual != "item") + if (m_prop.visual != OBJECTVISUAL_NODE && + m_prop.visual != OBJECTVISUAL_WIELDITEM && + m_prop.visual != OBJECTVISUAL_ITEM) { IShaderSource *shader_source = m_client->getShaderSource(); MaterialType material_type; @@ -691,7 +694,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) node->forEachMaterial(setMaterial); }; - if (m_prop.visual == "upright_sprite") { + switch(m_prop.visual) { + case OBJECTVISUAL_UPRIGHT_SPRITE: { auto mesh = make_irr<scene::SMesh>(); f32 dx = BS * m_prop.visual_size.X / 2; f32 dy = BS * m_prop.visual_size.Y / 2; @@ -732,7 +736,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) mesh->recalculateBoundingBox(); m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode); m_meshnode->grab(); - } else if (m_prop.visual == "cube") { + break; + } case OBJECTVISUAL_CUBE: { scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode); m_meshnode->grab(); @@ -745,7 +750,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) m_meshnode->forEachMaterial([this] (auto &mat) { mat.BackfaceCulling = m_prop.backface_culling; }); - } else if (m_prop.visual == "mesh") { + break; + } case OBJECTVISUAL_MESH: { scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true); if (mesh) { if (!checkMeshNormals(mesh)) { @@ -771,7 +777,10 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) }); } else errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl; - } else if (m_prop.visual == "wielditem" || m_prop.visual == "item") { + break; + } + case OBJECTVISUAL_WIELDITEM: + case OBJECTVISUAL_ITEM: { ItemStack item; if (m_prop.wield_item.empty()) { // Old format, only textures are specified. @@ -788,10 +797,11 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) } m_wield_meshnode = new WieldMeshSceneNode(m_smgr, -1); m_wield_meshnode->setItem(item, m_client, - (m_prop.visual == "wielditem")); + (m_prop.visual == OBJECTVISUAL_WIELDITEM)); m_wield_meshnode->setScale(m_prop.visual_size / 2.0f); - } else if (m_prop.visual == "node") { + break; + } case OBJECTVISUAL_NODE: { auto *mesh = generateNodeMesh(m_client, m_prop.node, m_meshnode_animation); assert(mesh); @@ -803,7 +813,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) m_meshnode->setScale(m_prop.visual_size); setSceneNodeMaterials(m_meshnode); - } else { + break; + } default: m_spritenode = m_smgr->addBillboardSceneNode(m_matrixnode); m_spritenode->grab(); @@ -814,19 +825,18 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) setBillboardTextureMatrix(m_spritenode, 1, 1, 0, 0); // This also serves as fallback for unknown visual types - if (m_prop.visual != "sprite") { - infostream << "GenericCAO::addToScene(): \"" << m_prop.visual - << "\" not supported" << std::endl; + if (m_prop.visual != OBJECTVISUAL_SPRITE) { m_spritenode->getMaterial(0).setTexture(0, tsrc->getTextureForMesh("unknown_object.png")); } + break; } /* Set VBO hint */ // wieldmesh sets its own hint, no need to handle it if (m_meshnode || m_animated_meshnode) { // sprite uses vertex animation - if (m_meshnode && m_prop.visual != "upright_sprite") + if (m_meshnode && m_prop.visual != OBJECTVISUAL_UPRIGHT_SPRITE) m_meshnode->getMesh()->setHardwareMappingHint(scene::EHM_STATIC); if (m_animated_meshnode) { @@ -930,7 +940,7 @@ void GenericCAO::updateLight(u32 day_night_ratio) void GenericCAO::setNodeLight(const video::SColor &light_color) { - if (m_prop.visual == "wielditem" || m_prop.visual == "item") { + if (m_prop.visual == OBJECTVISUAL_WIELDITEM || m_prop.visual == OBJECTVISUAL_ITEM) { if (m_wield_meshnode) m_wield_meshnode->setNodeLightColor(light_color); return; @@ -1317,7 +1327,7 @@ void GenericCAO::updateTextureAnim() } else if (m_meshnode) { - if (m_prop.visual == "upright_sprite") { + if (m_prop.visual == OBJECTVISUAL_UPRIGHT_SPRITE) { int row = m_tx_basepos.Y; int col = m_tx_basepos.X; @@ -1334,7 +1344,7 @@ void GenericCAO::updateTextureAnim() auto mesh = m_meshnode->getMesh(); setMeshBufferTextureCoords(mesh->getMeshBuffer(0), t, 4); setMeshBufferTextureCoords(mesh->getMeshBuffer(1), t, 4); - } else if (m_prop.visual == "node") { + } else if (m_prop.visual == OBJECTVISUAL_NODE) { // same calculation as MapBlockMesh::animate() with a global timer const float time = m_client->getAnimationTime(); for (auto &it : m_meshnode_animation) { @@ -1368,7 +1378,7 @@ void GenericCAO::updateTextures(std::string mod) m_current_texture_modifier = mod; if (m_spritenode) { - if (m_prop.visual == "sprite") { + if (m_prop.visual == OBJECTVISUAL_SPRITE) { std::string texturestring = "no_texture.png"; if (!m_prop.textures.empty()) texturestring = m_prop.textures[0]; @@ -1386,7 +1396,7 @@ void GenericCAO::updateTextures(std::string mod) } else if (m_animated_meshnode) { - if (m_prop.visual == "mesh") { + if (m_prop.visual == OBJECTVISUAL_MESH) { for (u32 i = 0; i < m_animated_meshnode->getMaterialCount(); ++i) { const auto texture_idx = m_animated_meshnode->getMesh()->getTextureSlot(i); if (texture_idx >= m_prop.textures.size()) @@ -1423,7 +1433,7 @@ void GenericCAO::updateTextures(std::string mod) } else if (m_meshnode) { - if(m_prop.visual == "cube") + if(m_prop.visual == OBJECTVISUAL_CUBE) { for (u32 i = 0; i < 6; ++i) { @@ -1443,7 +1453,7 @@ void GenericCAO::updateTextures(std::string mod) use_anisotropic_filter); }); } - } else if (m_prop.visual == "upright_sprite") { + } else if (m_prop.visual == OBJECTVISUAL_UPRIGHT_SPRITE) { scene::IMesh *mesh = m_meshnode->getMesh(); { std::string tname = "no_texture.png"; @@ -1607,7 +1617,7 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const */ bool uses_legacy_texture = new_.wield_item.empty() && - (new_.visual == "wielditem" || new_.visual == "item"); + (new_.visual == OBJECTVISUAL_WIELDITEM || new_.visual == OBJECTVISUAL_ITEM); // Ordered to compare primitive types before std::vectors return old.backface_culling != new_.backface_culling || old.is_visible != new_.is_visible || @@ -1999,7 +2009,7 @@ void GenericCAO::updateMeshCulling() if (!node) return; - if (m_prop.visual == "upright_sprite") { + if (m_prop.visual == OBJECTVISUAL_UPRIGHT_SPRITE) { // upright sprite has no backface culling node->forEachMaterial([=] (auto &mat) { mat.FrontfaceCulling = hidden; diff --git a/src/object_properties.cpp b/src/object_properties.cpp index feef295ba8657..35bf2e63e9789 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -8,11 +8,25 @@ #include "exceptions.h" #include "log.h" #include "util/serialize.h" +#include "util/enum_string.h" #include <sstream> #include <tuple> static const video::SColor NULL_BGCOLOR{0, 1, 1, 1}; +const struct EnumString es_ObjectVisual[] = +{ + {OBJECTVISUAL_UNKNOWN, "unknown"}, + {OBJECTVISUAL_SPRITE, "sprite"}, + {OBJECTVISUAL_UPRIGHT_SPRITE, "upright_sprite"}, + {OBJECTVISUAL_CUBE, "cube"}, + {OBJECTVISUAL_MESH, "mesh"}, + {OBJECTVISUAL_ITEM, "item"}, + {OBJECTVISUAL_WIELDITEM, "wielditem"}, + {OBJECTVISUAL_NODE, "node"}, + {0, nullptr}, +}; + ObjectProperties::ObjectProperties() { textures.emplace_back("no_texture.png"); @@ -26,7 +40,7 @@ std::string ObjectProperties::dump() const os << ", physical=" << physical; os << ", collideWithObjects=" << collideWithObjects; os << ", collisionbox=" << collisionbox.MinEdge << "," << collisionbox.MaxEdge; - os << ", visual=" << visual; + os << ", visual=" << enum_to_string(es_ObjectVisual, visual); os << ", mesh=" << mesh; os << ", visual_size=" << visual_size; os << ", textures=["; @@ -137,7 +151,10 @@ void ObjectProperties::serialize(std::ostream &os) const writeV3F32(os, selectionbox.MinEdge); writeV3F32(os, selectionbox.MaxEdge); Pointabilities::serializePointabilityType(os, pointable); - os << serializeString16(visual); + + // Convert to string for compatibility + os << serializeString16(enum_to_string(es_ObjectVisual, visual)); + writeV3F32(os, visual_size); writeU16(os, textures.size()); for (const std::string &texture : textures) { @@ -222,7 +239,14 @@ void ObjectProperties::deSerialize(std::istream &is) selectionbox.MinEdge = readV3F32(is); selectionbox.MaxEdge = readV3F32(is); pointable = Pointabilities::deSerializePointabilityType(is); - visual = deSerializeString16(is); + + std::string visual_string{deSerializeString16(is)}; + if (!string_to_enum(es_ObjectVisual, visual, visual_string)) { + infostream << "ObjectProperties::deSerialize(): visual \"" << visual_string + << "\" not supported" << std::endl; + visual = OBJECTVISUAL_UNKNOWN; + } + visual_size = readV3F32(is); textures.clear(); u32 texture_count = readU16(is); diff --git a/src/object_properties.h b/src/object_properties.h index dfb08192375e6..b898c982d0a7d 100644 --- a/src/object_properties.h +++ b/src/object_properties.h @@ -12,6 +12,22 @@ #include "util/pointabilities.h" #include "mapnode.h" +struct EnumString; + +enum ObjectVisual : u8 { + OBJECTVISUAL_UNKNOWN, + OBJECTVISUAL_SPRITE, + OBJECTVISUAL_UPRIGHT_SPRITE, + OBJECTVISUAL_CUBE, + OBJECTVISUAL_MESH, + OBJECTVISUAL_ITEM, + OBJECTVISUAL_WIELDITEM, + OBJECTVISUAL_NODE, +}; + +extern const EnumString es_ObjectVisual[]; + + struct ObjectProperties { /* member variables ordered roughly by size */ @@ -22,7 +38,7 @@ struct ObjectProperties aabb3f collisionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f); // Values are BS=1 aabb3f selectionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f); - std::string visual = "sprite"; + ObjectVisual visual = OBJECTVISUAL_SPRITE; std::string mesh; std::string damage_texture_modifier = "^[brighten"; std::string nametag; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index fb4762eecebec..f22b163ded3a4 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -353,7 +353,14 @@ void read_object_properties(lua_State *L, int index, } lua_pop(L, 1); - getstringfield(L, -1, "visual", prop->visual); + // Don't set if nil + std::string visual; + if (getstringfield(L, -1, "visual", visual)) { + if (!string_to_enum(es_ObjectVisual, prop->visual, visual)) { + script_log_unique(L, "Unsupported ObjectVisual: " + visual, warningstream); + prop->visual = OBJECTVISUAL_UNKNOWN; + } + } getstringfield(L, -1, "mesh", prop->mesh); @@ -502,7 +509,7 @@ void push_object_properties(lua_State *L, const ObjectProperties *prop) lua_setfield(L, -2, "selectionbox"); push_pointability_type(L, prop->pointable); lua_setfield(L, -2, "pointable"); - lua_pushlstring(L, prop->visual.c_str(), prop->visual.size()); + lua_pushstring(L, enum_to_string(es_ObjectVisual, prop->visual)); lua_setfield(L, -2, "visual"); lua_pushlstring(L, prop->mesh.c_str(), prop->mesh.size()); lua_setfield(L, -2, "mesh"); diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index 449dbc6cf44c7..11fc155976a73 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -26,7 +26,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t p m_prop.selectionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f); m_prop.pointable = PointabilityType::POINTABLE; // Start of default appearance, this should be overwritten by Lua - m_prop.visual = "upright_sprite"; + m_prop.visual = OBJECTVISUAL_UPRIGHT_SPRITE; m_prop.visual_size = v3f(1, 2, 1); m_prop.textures.clear(); m_prop.textures.emplace_back("player.png");