diff --git a/src/clientobject.h b/src/clientobject.h index 8b0b57147..e08b78c57 100644 --- a/src/clientobject.h +++ b/src/clientobject.h @@ -56,6 +56,11 @@ public: virtual core::aabbox3d* getSelectionBox(){return NULL;} virtual core::aabbox3d* getCollisionBox(){return NULL;} virtual v3f getPosition(){return v3f(0,0,0);} + virtual scene::IMeshSceneNode *getMeshSceneNode(){return NULL;} + virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode(){return NULL;} + virtual scene::IBillboardSceneNode *getSpriteSceneNode(){return NULL;} + virtual bool isPlayer(){return false;} + virtual bool isLocalPlayer(){return false;} virtual bool doShowSelectionBox(){return true;} // Step object in time diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 613ec6153..60d458318 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -554,7 +554,7 @@ private: // Only set at initialization std::string m_name; bool m_is_player; - bool m_is_local_player; // determined locally + bool m_is_local_player; int m_id; // Property-ish things ObjectProperties m_prop; @@ -594,6 +594,7 @@ private: bool m_visuals_expired; float m_step_distance_counter; u8 m_last_light; + bool m_is_visible; public: GenericCAO(IGameDef *gamedef, ClientEnvironment *env): @@ -634,7 +635,8 @@ public: m_reset_textures_timer(-1), m_visuals_expired(false), m_step_distance_counter(0), - m_last_light(255) + m_last_light(255), + m_is_visible(false) { if(gamedef == NULL) ClientActiveObject::registerType(getType(), create); @@ -691,7 +693,7 @@ public: } core::aabbox3d* getSelectionBox() { - if(!m_prop.is_visible || m_is_local_player) + if(!m_prop.is_visible || !m_is_visible || m_is_local_player) return NULL; return &m_selection_box; } @@ -700,6 +702,31 @@ public: return pos_translator.vect_show; } + scene::IMeshSceneNode *getMeshSceneNode() + { + return m_meshnode; + } + + scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() + { + return m_animated_meshnode; + } + + scene::IBillboardSceneNode *getSpriteSceneNode() + { + return m_spritenode; + } + + bool isPlayer() + { + return m_is_player; + } + + bool isLocalPlayer() + { + return m_is_local_player; + } + void removeFromScene() { if(m_meshnode){ @@ -891,22 +918,27 @@ public: void updateLight(u8 light_at_pos) { - bool is_visible = (m_hp != 0); + // Objects attached to the local player should always be hidden + if(m_attachment_parent != NULL && m_attachment_parent->isLocalPlayer()) + m_is_visible = false; + else + m_is_visible = (m_hp != 0); u8 li = decode_light(light_at_pos); + if(li != m_last_light){ m_last_light = li; video::SColor color(255,li,li,li); if(m_meshnode){ setMeshColor(m_meshnode->getMesh(), color); - m_meshnode->setVisible(is_visible); + m_meshnode->setVisible(m_is_visible); } if(m_animated_meshnode){ setMeshColor(m_animated_meshnode->getMesh(), color); - m_animated_meshnode->setVisible(is_visible); + m_animated_meshnode->setVisible(m_is_visible); } if(m_spritenode){ m_spritenode->setColor(color); - m_spritenode->setVisible(is_visible); + m_spritenode->setVisible(m_is_visible); } } } @@ -948,6 +980,7 @@ public: addToScene(m_smgr, m_gamedef->tsrc(), m_irr); updateAnimations(); updateBonePosRot(); + updateAttachments(); } if(m_attachment_parent == NULL) // Attachments should be glued to their parent by Irrlicht @@ -1019,6 +1052,9 @@ public: m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI; updateNodePos(); } + + if(m_animated_meshnode) + errorstream<<"Attachment position: "<getPosition().X<<","<getPosition().Y<<","<getPosition().Z<isLocalPlayer()) + { + // REMAINING ATTACHMENT ISSUES: + // The code below should cause the child to get attached, but for some reason it's not working + // A debug print confirms both position and absolute position are set accordingly, but the object still shows at origin 0,0,0 + + scene::IMeshSceneNode *parent_mesh = NULL; + if(m_attachment_parent->getMeshSceneNode()) + parent_mesh = m_attachment_parent->getMeshSceneNode(); + scene::IAnimatedMeshSceneNode *parent_animated_mesh = NULL; + if(m_attachment_parent->getAnimatedMeshSceneNode()) + parent_animated_mesh = m_attachment_parent->getAnimatedMeshSceneNode(); + scene::IBillboardSceneNode *parent_sprite = NULL; + if(m_attachment_parent->getSpriteSceneNode()) + parent_sprite = m_attachment_parent->getSpriteSceneNode(); + + scene::IBoneSceneNode *parent_bone = NULL; + if(parent_animated_mesh && m_attachment_bone != "") + parent_bone = parent_animated_mesh->getJointNode(m_attachment_bone.c_str()); + if(!parent_bone) // Should be false if the bone doesn't exist on the mesh + parent_bone = NULL; + + // TODO: Perhaps use polymorphism here to save code duplication + if(m_meshnode){ + if(parent_bone){ + m_meshnode->setPosition(parent_bone->getPosition()); + m_meshnode->setRotation(parent_bone->getRotation()); + m_meshnode->updateAbsolutePosition(); + //m_meshnode->setParent(parent_bone); + } + else + { + if(parent_mesh){ + m_meshnode->setPosition(parent_mesh->getPosition()); + m_meshnode->setRotation(parent_mesh->getRotation()); + m_meshnode->updateAbsolutePosition(); + //m_meshnode->setParent(parent_mesh); + } + else if(parent_animated_mesh){ + m_meshnode->setPosition(parent_animated_mesh->getPosition()); + m_meshnode->setRotation(parent_animated_mesh->getRotation()); + m_meshnode->updateAbsolutePosition(); + //m_meshnode->setParent(parent_animated_mesh); + } + else if(parent_sprite){ + m_meshnode->setPosition(parent_sprite->getPosition()); + m_meshnode->setRotation(parent_sprite->getRotation()); + m_meshnode->updateAbsolutePosition(); + //m_meshnode->setParent(parent_sprite); + } + } + } + if(m_animated_meshnode){ + if(parent_bone){ + m_animated_meshnode->setPosition(parent_bone->getPosition()); + m_animated_meshnode->setRotation(parent_bone->getRotation()); + m_animated_meshnode->updateAbsolutePosition(); + //m_animated_meshnode->setParent(parent_bone); + } + else + { + if(parent_mesh){ + m_animated_meshnode->setPosition(parent_mesh->getPosition()); + m_animated_meshnode->setRotation(parent_mesh->getRotation()); + m_animated_meshnode->updateAbsolutePosition(); + //m_animated_meshnode->setParent(parent_mesh); + } + else if(parent_animated_mesh){ + m_animated_meshnode->setPosition(parent_animated_mesh->getPosition()); + m_animated_meshnode->setRotation(parent_animated_mesh->getRotation()); + m_animated_meshnode->updateAbsolutePosition(); + //m_animated_meshnode->setParent(parent_animated_mesh); + } + else if(parent_sprite){ + m_animated_meshnode->setPosition(parent_sprite->getPosition()); + m_animated_meshnode->setRotation(parent_sprite->getRotation()); + m_animated_meshnode->updateAbsolutePosition(); + //m_animated_meshnode->setParent(parent_sprite); + } + } + } + if(m_spritenode){ + if(parent_bone){ + m_spritenode->setPosition(parent_bone->getPosition()); + m_spritenode->setRotation(parent_bone->getRotation()); + m_spritenode->updateAbsolutePosition(); + //m_spritenode->setParent(parent_bone); + } + else + { + if(parent_mesh){ + m_spritenode->setPosition(parent_mesh->getPosition()); + m_spritenode->setRotation(parent_mesh->getRotation()); + m_spritenode->updateAbsolutePosition(); + //m_spritenode->setParent(parent_mesh); + } + else if(parent_animated_mesh){ + m_spritenode->setPosition(parent_animated_mesh->getPosition()); + m_spritenode->setRotation(parent_animated_mesh->getRotation()); + m_spritenode->updateAbsolutePosition(); + //m_spritenode->setParent(parent_animated_mesh); + } + else if(parent_sprite){ + m_spritenode->setPosition(parent_sprite->getPosition()); + m_spritenode->setRotation(parent_sprite->getRotation()); + m_spritenode->updateAbsolutePosition(); + //m_spritenode->setParent(parent_sprite); + } + } + } + } } void processMessage(const std::string &data) @@ -1334,11 +1483,9 @@ public: } else if(cmd == GENERIC_CMD_SET_ATTACHMENT) { - ClientActiveObject *obj; int parent_id = readS16(is); - if(parent_id > 0) - obj = m_env->getActiveObject(parent_id); - else + ClientActiveObject *obj = m_env->getActiveObject(parent_id); + if(!parent_id || !obj) obj = NULL; m_attachment_parent = obj; m_attachment_bone = deSerializeString(is); diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 7787e33fb..3289f9077 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -444,11 +444,12 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) m_last_sent_position_timer += dtime; + // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally + // If the object gets detached this comes into effect automatically from the last known origin if(m_parent != NULL) { - // REMAINING ATTACHMENT ISSUES: - // This is causing a segmentation fault, investigate why! - //m_base_position = m_parent->getBasePosition(); + v3f pos = m_parent->getBasePosition(); + m_base_position = pos; m_velocity = v3f(0,0,0); m_acceleration = v3f(0,0,0); } @@ -486,20 +487,23 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) if(send_recommended == false) return; - - // TODO: force send when acceleration changes enough? - float minchange = 0.2*BS; - if(m_last_sent_position_timer > 1.0){ - minchange = 0.01*BS; - } else if(m_last_sent_position_timer > 0.2){ - minchange = 0.05*BS; - } - float move_d = m_base_position.getDistanceFrom(m_last_sent_position); - move_d += m_last_sent_move_precision; - float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); - if(move_d > minchange || vel_d > minchange || - fabs(m_yaw - m_last_sent_yaw) > 1.0){ - sendPosition(true, false); + + if(m_parent != NULL) + { + // TODO: force send when acceleration changes enough? + float minchange = 0.2*BS; + if(m_last_sent_position_timer > 1.0){ + minchange = 0.01*BS; + } else if(m_last_sent_position_timer > 0.2){ + minchange = 0.05*BS; + } + float move_d = m_base_position.getDistanceFrom(m_last_sent_position); + move_d += m_last_sent_move_precision; + float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); + if(move_d > minchange || vel_d > minchange || + fabs(m_yaw - m_last_sent_yaw) > 1.0){ + sendPosition(true, false); + } } if(m_armor_groups_sent == false){ @@ -686,11 +690,11 @@ void LuaEntitySAO::setAttachment(ServerActiveObject *parent, std::string bone, v { // Attachments need to be handled on both the server and client. // If we just attach on the server, we can only copy the position of the parent. Attachments - // are still sent to clients at an interval so players would see them following the parent - // instead of sticking to it, plus we can't read and attach to skeletal bones. + // are still sent to clients at an interval so players might see them lagging, plus we can't + // read and attach to skeletal bones. // If we just attach on the client, the server still sees the child at its original location. - // This can break some things, so we also give the server the most accurate representation - // even if players will only see the client changes since they override server-sent position. + // This breaks some things so we also give the server the most accurate representation + // even if players only see the client changes. // Server attachment: m_parent = parent; @@ -776,6 +780,7 @@ std::string LuaEntitySAO::getPropertyPacket() void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { + // If the object is attached client-side, don't waste bandwidth sending its position to clients if(m_parent != NULL) return; @@ -925,7 +930,7 @@ std::string PlayerSAO::getStaticData() } void PlayerSAO::step(float dtime, bool send_recommended) -{ +{ if(!m_properties_sent) { m_properties_sent = true; @@ -938,7 +943,16 @@ void PlayerSAO::step(float dtime, bool send_recommended) m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; - if(m_parent == NULL) + // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally + // If the object gets detached this comes into effect automatically from the last known origin + if(m_parent != NULL) + { + v3f pos = m_parent->getBasePosition(); + m_last_good_position = pos; + m_last_good_position_age = 0; + m_player->setPosition(pos); + } + else { if(m_is_singleplayer || g_settings->getBool("disable_anticheat")) { @@ -999,15 +1013,13 @@ void PlayerSAO::step(float dtime, bool send_recommended) if(send_recommended == false) return; - // If the object is attached client-side, don't waste bandwidth and send its position to clients + // If the object is attached client-side, don't waste bandwidth sending its position to clients if(m_position_not_sent && m_parent == NULL) { m_position_not_sent = false; float update_interval = m_env->getSendRecommendedInterval(); v3f pos; - // REMAINING ATTACHMENT ISSUES: - // This is causing a segmentation fault, investigate why! - if(m_parent != NULL) + if(m_parent != NULL) // Just in case we ever do send attachment position too pos = m_parent->getBasePosition(); else pos = m_player->getPosition() + v3f(0,BS*1,0); @@ -1043,8 +1055,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) void PlayerSAO::setBasePosition(const v3f &position) { - if(m_parent != NULL) - return; + // This needs to be ran for attachments too ServerActiveObject::setBasePosition(position); m_position_not_sent = true; } @@ -1183,11 +1194,11 @@ void PlayerSAO::setAttachment(ServerActiveObject *parent, std::string bone, v3f { // Attachments need to be handled on both the server and client. // If we just attach on the server, we can only copy the position of the parent. Attachments - // are still sent to clients at an interval so players would see them following the parent - // instead of sticking to it, plus we can't read and attach to skeletal bones. + // are still sent to clients at an interval so players might see them lagging, plus we can't + // read and attach to skeletal bones. // If we just attach on the client, the server still sees the child at its original location. - // This can break some things, so we also give the server the most accurate representation - // even if players will only see the client changes since they override server-sent position. + // This breaks some things so we also give the server the most accurate representation + // even if players only see the client changes. // Server attachment: m_parent = parent; diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 180219ba8..53deea11b 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -254,6 +254,7 @@ void ContentFeatures::serialize(std::ostream &os) os<