diff --git a/src/content_cao.cpp b/src/content_cao.cpp index b7923ff8..bd90e96a 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -723,52 +723,29 @@ void GenericCAO::setAttachments() ClientActiveObject* GenericCAO::getParent() { ClientActiveObject *obj = NULL; - for(std::vector >::const_iterator cii = m_env->attachment_list.begin(); cii != m_env->attachment_list.end(); cii++) - { - if(cii->X == getId()) // This ID is our child - { - if(cii->Y > 0) // A parent ID exists for our child - { - if(cii->X != cii->Y) // The parent and child ID are not the same - { - obj = m_env->getActiveObject(cii->Y); - } - } - break; - } + + u16 attached_id = m_env->m_attachements[getId()]; + + if ((attached_id != 0) && + (attached_id != getId())) { + obj = m_env->getActiveObject(attached_id); } - if(obj) - return obj; - return NULL; + return obj; } void GenericCAO::removeFromScene(bool permanent) { if(permanent) // Should be true when removing the object permanently and false when refreshing (eg: updating visuals) { - // Detach this object's children - for(std::vector >::iterator ii = m_env->attachment_list.begin(); - ii != m_env->attachment_list.end(); ii++) + for(std::vector::iterator ci = m_children.begin(); + ci != m_children.end(); ci++) { - if(ii->Y == getId()) // Is a child of our object - { - ii->Y = 0; - // Get the object of the child - ClientActiveObject *obj = m_env->getActiveObject(ii->X); - if(obj) - obj->setAttachments(); - } - } - // Delete this object from the attachments list - for(std::vector >::iterator ii = m_env->attachment_list.begin(); - ii != m_env->attachment_list.end(); ii++) - { - if(ii->X == getId()) // Is our object - { - m_env->attachment_list.erase(ii); - break; + if (m_env->m_attachements[*ci] == getId()) { + m_env->m_attachements[*ci] = 0; } } + + m_env->m_attachements[getId()] = 0; } if(m_meshnode) @@ -1098,45 +1075,43 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) // Attachments, part 1: All attached objects must be unparented first, // or Irrlicht causes a segmentation fault - for(std::vector >::iterator ii = m_env->attachment_list.begin(); - ii != m_env->attachment_list.end(); ii++) + for(std::vector::iterator ci = m_children.begin(); + ci != m_children.end();) { - if(ii->Y == getId()) // This is a child of our parent - { - // Get the object of the child - ClientActiveObject *obj = m_env->getActiveObject(ii->X); - if(obj) - { - scene::IMeshSceneNode *m_child_meshnode - = obj->getMeshSceneNode(); - scene::IAnimatedMeshSceneNode *m_child_animated_meshnode - = obj->getAnimatedMeshSceneNode(); - scene::IBillboardSceneNode *m_child_spritenode - = obj->getSpriteSceneNode(); - if(m_child_meshnode) - m_child_meshnode->setParent(m_smgr->getRootSceneNode()); - if(m_child_animated_meshnode) - m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode()); - if(m_child_spritenode) - m_child_spritenode->setParent(m_smgr->getRootSceneNode()); - } + if (m_env->m_attachements[*ci] != getId()) { + ci = m_children.erase(ci); + continue; } + ClientActiveObject *obj = m_env->getActiveObject(*ci); + if(obj) + { + scene::IMeshSceneNode *m_child_meshnode + = obj->getMeshSceneNode(); + scene::IAnimatedMeshSceneNode *m_child_animated_meshnode + = obj->getAnimatedMeshSceneNode(); + scene::IBillboardSceneNode *m_child_spritenode + = obj->getSpriteSceneNode(); + if(m_child_meshnode) + m_child_meshnode->setParent(m_smgr->getRootSceneNode()); + if(m_child_animated_meshnode) + m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode()); + if(m_child_spritenode) + m_child_spritenode->setParent(m_smgr->getRootSceneNode()); + } + ++ci; } removeFromScene(false); addToScene(m_smgr, m_gamedef->tsrc(), m_irr); // Attachments, part 2: Now that the parent has been refreshed, put its attachments back - for(std::vector >::iterator ii = m_env->attachment_list.begin(); - ii != m_env->attachment_list.end(); ii++) + for(std::vector::iterator ci = m_children.begin(); + ci != m_children.end(); ci++) { - if(ii->Y == getId()) // This is a child of our parent - { // Get the object of the child - ClientActiveObject *obj = m_env->getActiveObject(ii->X); + ClientActiveObject *obj = m_env->getActiveObject(*ci); if(obj) obj->setAttachments(); - } } } @@ -1803,16 +1778,8 @@ void GenericCAO::processMessage(const std::string &data) updateBonePosition(); } else if(cmd == GENERIC_CMD_SET_ATTACHMENT) { - // If an entry already exists for this object, delete it first to avoid duplicates - for(std::vector >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++) - { - if(ii->X == getId()) // This is the ID of our object - { - m_env->attachment_list.erase(ii); - break; - } - } - m_env->attachment_list.push_back(core::vector2d(getId(), readS16(is))); + m_env->m_attachements[getId()] = readS16(is); + m_children.push_back(m_env->m_attachements[getId()]); m_attachment_bone = deSerializeString(is); m_attachment_position = readV3F1000(is); m_attachment_rotation = readV3F1000(is); diff --git a/src/content_cao.h b/src/content_cao.h index 1e55babf..bf27ed79 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -102,6 +102,8 @@ private: u8 m_last_light; bool m_is_visible; + std::vector m_children; + public: GenericCAO(IGameDef *gamedef, ClientEnvironment *env); diff --git a/src/environment.cpp b/src/environment.cpp index fa7ce2ae..8103998c 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -1379,7 +1379,7 @@ bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj) { assert(obj); - v3f objectpos = obj->getBasePosition(); + v3f objectpos = obj->getBasePosition(); // The block in which the object resides in v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS)); @@ -1591,7 +1591,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object, object->m_static_block = blockpos; if(set_changed) - block->raiseModified(MOD_STATE_WRITE_NEEDED, + block->raiseModified(MOD_STATE_WRITE_NEEDED, "addActiveObjectRaw"); } else { v3s16 p = floatToInt(objectpos, BS); @@ -1828,7 +1828,7 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s) If force_delete is set, active object is deleted nevertheless. It shall only be set so in the destructor of the environment. - If block wasn't generated (not in memory or on disk), + If block wasn't generated (not in memory or on disk), */ void ServerEnvironment::deactivateFarObjects(bool force_delete) { @@ -1849,7 +1849,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete) continue; u16 id = i->first; - v3f objectpos = obj->getBasePosition(); + v3f objectpos = obj->getBasePosition(); // The block in which the object resides in v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS)); @@ -2078,6 +2078,8 @@ ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr, m_gamedef(gamedef), m_irr(irr) { + char zero = 0; + memset(m_attachements, zero, sizeof(m_attachements)); } ClientEnvironment::~ClientEnvironment() diff --git a/src/environment.h b/src/environment.h index 5062b9c3..cecc9133 100644 --- a/src/environment.h +++ b/src/environment.h @@ -492,7 +492,7 @@ public: // Get event from queue. CEE_NONE is returned if queue is empty. ClientEnvEvent getClientEvent(); - std::vector > attachment_list; // X is child ID, Y is parent ID + u16 m_attachements[USHRT_MAX]; std::list getPlayerNames() { return m_player_names; }