From 3068853e8a58ccc7370a5ce977c08223601c497a Mon Sep 17 00:00:00 2001 From: Jordan Snelling Date: Sun, 4 Oct 2020 14:10:34 +0100 Subject: Add First Person Attachments (#10360) Fixes some other third person camera specific attachments. Implements a single new flag for entities to be forced visible in first person mode. Old mods do not need to be updated to use the new flag and are fully backwards compatible. --- src/client/content_cao.cpp | 56 +++++++++++++++++++++++++++++++++++++++++----- src/client/content_cao.h | 8 +++++++ src/client/game.cpp | 3 ++- 3 files changed, 60 insertions(+), 7 deletions(-) (limited to 'src/client') diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index c1715a289..fae06554a 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -456,7 +456,8 @@ void GenericCAO::setChildrenVisible(bool toset) for (u16 cao_id : m_attachment_child_ids) { GenericCAO *obj = m_env->getGenericCAO(cao_id); if (obj) { - obj->setVisible(toset); + // Check if the entity is forced to appear in first person. + obj->setVisible(obj->isForcedVisible() ? true : toset); } } } @@ -477,8 +478,6 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone, v3f posit if (parent) parent->addAttachmentChild(m_id); } - - updateAttachments(); } @@ -498,7 +497,7 @@ void GenericCAO::clearChildAttachments() int child_id = *m_attachment_child_ids.begin(); if (ClientActiveObject *child = m_env->getActiveObject(child_id)) - child->setAttachment(0, "", v3f(), v3f()); + child->setAttachment(0, "", v3f(), v3f(), false); removeAttachmentChild(child_id); } @@ -800,6 +799,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc) updateBonePosition(); updateAttachments(); setNodeLight(m_last_light); + updateMeshCulling(); } void GenericCAO::updateLight(u32 day_night_ratio) @@ -1411,6 +1411,9 @@ void GenericCAO::updateTextures(std::string mod) setMeshColor(mesh, m_prop.colors[0]); } } + // Prevent showing the player after changing texture + if (m_is_local_player) + updateMeshCulling(); } void GenericCAO::updateAnimation() @@ -1739,12 +1742,25 @@ void GenericCAO::processMessage(const std::string &data) std::string bone = deSerializeString16(is); v3f position = readV3F32(is); v3f rotation = readV3F32(is); + m_force_visible = readU8(is); // Returns false for EOF setAttachment(parent_id, bone, position, rotation); + // Forcibly show attachments if required by set_attach + if (m_force_visible) + m_is_visible = true; // localplayer itself can't be attached to localplayer - if (!m_is_local_player) - m_is_visible = !m_attached_to_local; + else if (!m_is_local_player) { + // Objects attached to the local player should be hidden in first + // person provided the forced boolean isn't set. + m_is_visible = !m_attached_to_local || + m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST; + m_force_visible = false; + } else { + // Local players need to have this set, + // otherwise first person attachments fail. + m_is_visible = true; + } } else if (cmd == AO_CMD_PUNCHED) { u16 result_hp = readU16(is); @@ -1858,5 +1874,33 @@ std::string GenericCAO::debugInfoText() return os.str(); } +void GenericCAO::updateMeshCulling() +{ + if (!m_is_local_player) + return; + + // Grab the active player scene node so we know there's + // at least a mesh to occlude from the camera. + irr::scene::ISceneNode *node = getSceneNode(); + if (!node) + return; + + if (m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST) { + // Hide the mesh by culling both front and + // back faces. Serious hackyness but it works for our + // purposes. This also preserves the skeletal armature. + node->setMaterialFlag(video::EMF_BACK_FACE_CULLING, + true); + node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING, + true); + } else { + // Restore mesh visibility. + node->setMaterialFlag(video::EMF_BACK_FACE_CULLING, + m_prop.backface_culling); + node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING, + false); + } +} + // Prototype GenericCAO proto_GenericCAO(NULL, NULL); diff --git a/src/client/content_cao.h b/src/client/content_cao.h index 974ff9a1e..daf697767 100644 --- a/src/client/content_cao.h +++ b/src/client/content_cao.h @@ -124,6 +124,7 @@ private: float m_step_distance_counter = 0.0f; u8 m_last_light = 255; bool m_is_visible = false; + bool m_force_visible = false; s8 m_glow = 0; // Material video::E_MATERIAL_TYPE m_material_type; @@ -215,6 +216,11 @@ public: m_is_visible = toset; } + inline bool isForcedVisible() const + { + return m_force_visible; + } + void setChildrenVisible(bool toset); void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation); void getAttachment(int *parent_id, std::string *bone, v3f *position, @@ -275,4 +281,6 @@ public: { return m_prop.infotext; } + + void updateMeshCulling(); }; diff --git a/src/client/game.cpp b/src/client/game.cpp index 8f9d51417..366464467 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2950,7 +2950,8 @@ void Game::updateCamera(u32 busy_time, f32 dtime) camera->toggleCameraMode(); - playercao->setVisible(camera->getCameraMode() > CAMERA_MODE_FIRST); + // Make the player visible depending on camera mode. + playercao->updateMeshCulling(); playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST); } -- cgit v1.2.3