diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 5307047c4ce2e..1e07846a73ee5 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -597,7 +597,7 @@ 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(): " << es_ObjectVisual[m_prop.visual].str << std::endl; m_material_type_param = 0.5f; // May cut off alpha < 128 depending on m_material_type @@ -634,140 +634,154 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) node->forEachMaterial(setMaterial); }; - if (m_prop.visual == "sprite") { - grabMatrixNode(); - m_spritenode = m_smgr->addBillboardSceneNode( - m_matrixnode, v2f(1, 1), v3f(0,0,0), -1); - m_spritenode->grab(); - video::ITexture *tex = tsrc->getTextureForMesh("no_texture.png"); - m_spritenode->forEachMaterial([tex] (auto &mat) { - mat.setTexture(0, tex); - }); + switch(m_prop.visual) { + case OBJECTVISUAL_SPRITE: { + grabMatrixNode(); + m_spritenode = m_smgr->addBillboardSceneNode( + m_matrixnode, v2f(1, 1), v3f(0,0,0), -1); + m_spritenode->grab(); + video::ITexture *tex = tsrc->getTextureForMesh("no_texture.png"); + m_spritenode->forEachMaterial([tex] (auto &mat) { + mat.setTexture(0, tex); + }); - setSceneNodeMaterials(m_spritenode); + setSceneNodeMaterials(m_spritenode); - m_spritenode->setSize(v2f(m_prop.visual_size.X, - m_prop.visual_size.Y) * BS); - { - const float txs = 1.0 / 1; - const float tys = 1.0 / 1; - setBillboardTextureMatrix(m_spritenode, - txs, tys, 0, 0); - } - } else if (m_prop.visual == "upright_sprite") { - grabMatrixNode(); - auto mesh = make_irr(); - f32 dx = BS * m_prop.visual_size.X / 2; - f32 dy = BS * m_prop.visual_size.Y / 2; - video::SColor c(0xFFFFFFFF); - - video::S3DVertex vertices[4] = { - video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1), - video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1), - video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0), - video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0), - }; - if (m_is_player) { - // Move minimal Y position to 0 (feet position) - for (auto &vertex : vertices) - vertex.Pos.Y += dy; + m_spritenode->setSize(v2f(m_prop.visual_size.X, + m_prop.visual_size.Y) * BS); + { + const float txs = 1.0 / 1; + const float tys = 1.0 / 1; + setBillboardTextureMatrix(m_spritenode, + txs, tys, 0, 0); + } } - const u16 indices[] = {0,1,2,2,3,0}; - - for (int face : {0, 1}) { - auto buf = make_irr(); - // Front (0) or Back (1) - if (face == 1) { - for (auto &v : vertices) - v.Normal *= -1; - for (int i : {0, 2}) - std::swap(vertices[i].Pos, vertices[i+1].Pos); + break; + case OBJECTVISUAL_UPRIGHT_SPRITE: { + grabMatrixNode(); + auto mesh = make_irr(); + f32 dx = BS * m_prop.visual_size.X / 2; + f32 dy = BS * m_prop.visual_size.Y / 2; + video::SColor c(0xFFFFFFFF); + + video::S3DVertex vertices[4] = { + video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1), + video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1), + video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0), + video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0), + }; + if (m_is_player) { + // Move minimal Y position to 0 (feet position) + for (auto &vertex : vertices) + vertex.Pos.Y += dy; } - buf->append(vertices, 4, indices, 6); + const u16 indices[] = {0,1,2,2,3,0}; + + for (int face : {0, 1}) { + auto buf = make_irr(); + // Front (0) or Back (1) + if (face == 1) { + for (auto &v : vertices) + v.Normal *= -1; + for (int i : {0, 2}) + std::swap(vertices[i].Pos, vertices[i+1].Pos); + } + buf->append(vertices, 4, indices, 6); - // Set material - setMaterial(buf->getMaterial()); - buf->getMaterial().ColorParam = c; + // Set material + setMaterial(buf->getMaterial()); + buf->getMaterial().ColorParam = c; - // Add to mesh - mesh->addMeshBuffer(buf.get()); - } + // Add to mesh + mesh->addMeshBuffer(buf.get()); + } - mesh->recalculateBoundingBox(); - m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode); - m_meshnode->grab(); - } else if (m_prop.visual == "cube") { - grabMatrixNode(); - scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); - m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode); - m_meshnode->grab(); - mesh->drop(); + mesh->recalculateBoundingBox(); + m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode); + m_meshnode->grab(); + } + break; + case OBJECTVISUAL_CUBE: { + grabMatrixNode(); + scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); + m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode); + m_meshnode->grab(); + mesh->drop(); - m_meshnode->setScale(m_prop.visual_size); + m_meshnode->setScale(m_prop.visual_size); - setSceneNodeMaterials(m_meshnode); + setSceneNodeMaterials(m_meshnode); - m_meshnode->forEachMaterial([this] (auto &mat) { - mat.BackfaceCulling = m_prop.backface_culling; - }); - } else if (m_prop.visual == "mesh") { - grabMatrixNode(); - scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true); - if (mesh) { - if (!checkMeshNormals(mesh)) { - infostream << "GenericCAO: recalculating normals for mesh " - << m_prop.mesh << std::endl; - m_smgr->getMeshManipulator()-> - recalculateNormals(mesh, true, false); - } + m_meshnode->forEachMaterial([this] (auto &mat) { + mat.BackfaceCulling = m_prop.backface_culling; + }); + } + break; + case OBJECTVISUAL_MESH: { + grabMatrixNode(); + scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true); + if (mesh) { + if (!checkMeshNormals(mesh)) { + infostream << "GenericCAO: recalculating normals for mesh " + << m_prop.mesh << std::endl; + m_smgr->getMeshManipulator()-> + recalculateNormals(mesh, true, false); + } - m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode); - m_animated_meshnode->grab(); - mesh->drop(); // The scene node took hold of it - m_animated_meshnode->animateJoints(); // Needed for some animations - m_animated_meshnode->setScale(m_prop.visual_size); + m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode); + m_animated_meshnode->grab(); + mesh->drop(); // The scene node took hold of it + m_animated_meshnode->animateJoints(); // Needed for some animations + m_animated_meshnode->setScale(m_prop.visual_size); - // set vertex colors to ensure alpha is set - setMeshColor(m_animated_meshnode->getMesh(), video::SColor(0xFFFFFFFF)); + // set vertex colors to ensure alpha is set + setMeshColor(m_animated_meshnode->getMesh(), video::SColor(0xFFFFFFFF)); - setSceneNodeMaterials(m_animated_meshnode); + setSceneNodeMaterials(m_animated_meshnode); - m_animated_meshnode->forEachMaterial([this] (auto &mat) { - mat.BackfaceCulling = m_prop.backface_culling; - }); - } else - errorstream<<"GenericCAO::addToScene(): Could not load mesh "<idef(); - item = ItemStack(m_prop.textures[0], 1, 0, idef); - } - } else { - infostream << "serialized form: " << m_prop.wield_item << std::endl; - item.deSerialize(m_prop.wield_item, m_client->idef()); + m_animated_meshnode->forEachMaterial([this] (auto &mat) { + mat.BackfaceCulling = m_prop.backface_culling; + }); + } else + errorstream<<"GenericCAO::addToScene(): Could not load mesh "<setItem(item, m_client, - (m_prop.visual == "wielditem")); + break; + case OBJECTVISUAL_WIELDITEM_ITEM: + case OBJECTVISUAL_ITEM: { + grabMatrixNode(); + ItemStack item; + if (m_prop.wield_item.empty()) { + // Old format, only textures are specified. + infostream << "textures: " << m_prop.textures.size() << std::endl; + if (!m_prop.textures.empty()) { + infostream << "textures[0]: " << m_prop.textures[0] + << std::endl; + IItemDefManager *idef = m_client->idef(); + item = ItemStack(m_prop.textures[0], 1, 0, idef); + } + } else { + infostream << "serialized form: " << m_prop.wield_item << std::endl; + item.deSerialize(m_prop.wield_item, m_client->idef()); + } + m_wield_meshnode = new WieldMeshSceneNode(m_smgr, -1); + m_wield_meshnode->setItem(item, m_client, + (m_prop.visual == OBJECTVISUAL_WIELDITEM_ITEM)); - m_wield_meshnode->setScale(m_prop.visual_size / 2.0f); - } else { - infostream<<"GenericCAO::addToScene(): \""<setScale(m_prop.visual_size / 2.0f); + } + break; + default: + infostream << "GenericCAO::addToScene(): \"" + << es_ObjectVisual[m_prop.visual].str + << "\" not supported"<getMesh()->setHardwareMappingHint(scene::EHM_STATIC); if (m_animated_meshnode) { @@ -873,7 +887,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_ITEM || m_prop.visual == OBJECTVISUAL_ITEM) { if (m_wield_meshnode) m_wield_meshnode->setNodeLightColor(light_color); return; @@ -1259,7 +1273,7 @@ void GenericCAO::updateTexturePos() } 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; @@ -1293,7 +1307,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]; @@ -1312,7 +1326,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()) @@ -1350,7 +1364,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) { @@ -1371,7 +1385,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"; @@ -1563,7 +1577,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_ITEM || 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 || @@ -1954,7 +1968,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 63a0ef01bc438..fa42d7a591574 100644 --- a/src/object_properties.cpp +++ b/src/object_properties.cpp @@ -8,11 +8,24 @@ #include "exceptions.h" #include "log.h" #include "util/serialize.h" +#include "common/c_content.h" #include #include 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_ITEM, "wielditem_item"}, + {0, nullptr}, +}; + ObjectProperties::ObjectProperties() { textures.emplace_back("no_texture.png"); @@ -27,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=" << es_ObjectVisual[visual].str; os << ", mesh=" << mesh; os << ", visual_size=" << visual_size; os << ", textures=["; @@ -136,7 +149,7 @@ void ObjectProperties::serialize(std::ostream &os) const writeV3F32(os, selectionbox.MinEdge); writeV3F32(os, selectionbox.MaxEdge); Pointabilities::serializePointabilityType(os, pointable); - os << serializeString16(visual); + os << serializeString16(es_ObjectVisual[visual].str); writeV3F32(os, visual_size); writeU16(os, textures.size()); for (const std::string &texture : textures) { @@ -197,7 +210,14 @@ void ObjectProperties::deSerialize(std::istream &is) selectionbox.MinEdge = readV3F32(is); selectionbox.MaxEdge = readV3F32(is); pointable = Pointabilities::deSerializePointabilityType(is); - visual = deSerializeString16(is); + + // Don't convert to a string when introducing a new version (>4) + int result; + if (string_to_enum(es_ObjectVisual, result, deSerializeString16(is))) + visual = static_cast(result); + else + 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 d97b4997eb369..1aea6fdfb5a18 100644 --- a/src/object_properties.h +++ b/src/object_properties.h @@ -11,6 +11,21 @@ #include #include "util/pointabilities.h" +struct EnumString; + +enum ObjectVisual : u8 { + OBJECTVISUAL_UNKNOWN, + OBJECTVISUAL_SPRITE, + OBJECTVISUAL_UPRIGHT_SPRITE, + OBJECTVISUAL_CUBE, + OBJECTVISUAL_MESH, + OBJECTVISUAL_ITEM, + OBJECTVISUAL_WIELDITEM_ITEM, +}; + +extern const EnumString es_ObjectVisual[]; + + struct ObjectProperties { /* member variables ordered roughly by size */ @@ -21,7 +36,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 e343d50db2af4..86191983f9be0 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -334,7 +334,8 @@ void read_object_properties(lua_State *L, int index, } lua_pop(L, 1); - getstringfield(L, -1, "visual", prop->visual); + prop->visual = static_cast(getenumfield(L, -1, "visual", es_ObjectVisual, + OBJECTVISUAL_UNKNOWN)); getstringfield(L, -1, "mesh", prop->mesh); @@ -473,7 +474,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, es_ObjectVisual[prop->visual].str); 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 5d6b891fa95fe..60d6eadca4fa1 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");