diff --git a/indra/newview/fsareasearch.cpp b/indra/newview/fsareasearch.cpp index f786829b3c..4168f4d90b 100644 --- a/indra/newview/fsareasearch.cpp +++ b/indra/newview/fsareasearch.cpp @@ -57,7 +57,7 @@ // max number of objects that can be (de-)selected in a single packet. -const S32 MAX_OBJECTS_PER_PACKET = 254; +const S32 MAX_OBJECTS_PER_PACKET = 255; // time in seconds between refreshes when active const F32 REFRESH_INTERVAL = 1.0f; @@ -68,6 +68,9 @@ const F32 MIN_REFRESH_INTERVAL = 0.25f; // how far the avatar needs to move to trigger a distance update const F32 MIN_DISTANCE_MOVED = 1.0f; +// timeout to resend object properties request again +const F32 REQUEST_TIMEOUT = 30.0f; + class FSAreaSearch::FSParcelChangeObserver : public LLParcelObserver { @@ -108,7 +111,17 @@ FSAreaSearch::FSAreaSearch(const LLSD& key) : mBeacons(false), mExcludeAttachment(true), mExcludeTempary(true), - mExcludePhysics(true) + mExcludePhysics(true), + mColumnDistance(true), + mColumnName(true), + mColumnDescription(true), + mColumnOwner(true), + mColumnGroup(true), + mColumnCreator(true), + mColumnLastOwner(true), + mRequestQueuePause(false), + mRequestNeedsSent(false), + mOutstandingRequests(0) { //TODO: Multi-floater support and get rid of the singletin. mInstance = this; @@ -191,6 +204,7 @@ void FSAreaSearch::idle(void* user_data) { FSAreaSearch* self = (FSAreaSearch*)user_data; self->findObjects(); + self->processRequestQueue(); } // static @@ -244,6 +258,8 @@ void FSAreaSearch::checkRegion() mLastRegion = region; mRequested = 0; mObjectDetails.clear(); + mOutstandingRequests = 0; + mLastProptiesRecievedTimer.start(); mPanelList->getResultList()->deleteAllItems(); mPanelList->setCounterText(); mPanelList->setAgentLastPosition(gAgent.getPositionGlobal()); @@ -260,6 +276,8 @@ void FSAreaSearch::refreshList(bool cache_clear) { mRequested = 0; mObjectDetails.clear(); + mOutstandingRequests = 0; + mLastProptiesRecievedTimer.start(); } else { @@ -286,14 +304,15 @@ void FSAreaSearch::findObjects() return; } - LL_DEBUGS("FSAreaSearch") << "Doing a FSAreaSearch::findObjects" << LL_ENDL; + LL_DEBUGS("FSAreaSearch_spammy") << "Doing a FSAreaSearch::findObjects" << LL_ENDL; mLastUpdateTimer.stop(); // stop sets getElapsedTimeF32() time to zero. + // Pause processing of requestqueue untill done adding new requests. + mRequestQueuePause = true; checkRegion(); mRefresh = false; mSearchableObjects = 0; S32 object_count = gObjectList.getNumObjects(); - std::vector request_list; LLViewerRegion* our_region = gAgent.getRegion(); for (S32 i = 0; i < object_count; i++) @@ -318,47 +337,62 @@ void FSAreaSearch::findObjects() { FSObjectProperties& details = mObjectDetails[object_id]; details.id = object_id; - request_list.push_back(objectp->getLocalID()); - + details.local_id = objectp->getLocalID(); + mRequestNeedsSent = true; mRequested++; } else { FSObjectProperties& details = mObjectDetails[object_id]; - if (details.valid == true) + if (details.request == FSObjectProperties::FINISHED) { matchObject(details, objectp); } + + if (details.request == FSObjectProperties::FAILED) + { + // object came back into view + details.request = FSObjectProperties::NEED; + details.local_id = objectp->getLocalID(); + mRequestNeedsSent = true; + mRequested++; + } } - } - // Select then de-deslect the objects to get properties. - requestObjectProperties(request_list, true); - requestObjectProperties(request_list, false); - mPanelList->updateScrollList(); - //TODO: make mRequested more accruate. - // requests for non-existent objects will never arrive, - // update mRequested counter to reflect that. + S32 request_count = 0; + // requests for non-existent objects will never arrive, check and update the queue. for (std::map::iterator object_it = mObjectDetails.begin(); object_it != mObjectDetails.end(); ++object_it) { - if (!object_it->second.valid) + if (object_it->second.request == FSObjectProperties::NEED || object_it->second.request == FSObjectProperties::SENT) { LLUUID id = object_it->second.id; LLViewerObject* objectp = gObjectList.findObject(id); - if (((!objectp) || (!isSearchableObject(objectp, our_region))) && (mRequested > 0)) + if (!objectp) { + object_it->second.request = FSObjectProperties::FAILED; mRequested--; } + else + { + request_count++; + } } } + + if (mRequested != request_count) + { + LL_DEBUGS("FSAreaSearch") << "Requested mismatch: " << request_count << " actual vs. " << mRequested << LL_ENDL; + mRequested = request_count; + } updateCounterText(); mLastUpdateTimer.start(); // start also reset elapsed time to zero + mRequestQueuePause = false; } bool FSAreaSearch::isSearchableObject(LLViewerObject* objectp, LLViewerRegion* our_region) @@ -415,6 +449,87 @@ bool FSAreaSearch::isSearchableObject(LLViewerObject* objectp, LLViewerRegion* o return true; } +void FSAreaSearch::processRequestQueue() +{ + if (!mActive || mRequestQueuePause) + { + return; + } + + if (mLastProptiesRecievedTimer.getElapsedTimeF32() > REQUEST_TIMEOUT) + { + LL_DEBUGS("FSAreaSearch") << "Timeout reached, resending requests."<< LL_ENDL; + S32 request_count = 0; + S32 failed_count = 0; + for (std::map::iterator object_it = mObjectDetails.begin(); + object_it != mObjectDetails.end(); + ++object_it) + { + if (object_it->second.request == FSObjectProperties::SENT) + { + object_it->second.request = FSObjectProperties::NEED; + mRequestNeedsSent = true; + request_count++; + } + + if (object_it->second.request == FSObjectProperties::FAILED) + { + failed_count++; + } + } + + mOutstandingRequests = 0; + mLastProptiesRecievedTimer.start(); + if (!mRequestNeedsSent) + { + LL_DEBUGS("FSAreaSearch") << "No pending requests found."<< LL_ENDL; + } + else + { + LL_DEBUGS("FSAreaSearch") << request_count << " pending requests found."<< LL_ENDL; + } + + LL_DEBUGS("FSAreaSearch") << failed_count << " failed requests found."<< LL_ENDL; + } + + if (!mRequestNeedsSent) + { + return; + } + + if (mOutstandingRequests > (MAX_OBJECTS_PER_PACKET + 128)) + { + return; + } + + std::vector request_list; + + for (std::map::iterator object_it = mObjectDetails.begin(); + object_it != mObjectDetails.end(); + ++object_it) + { + if (object_it->second.request == FSObjectProperties::NEED) + { + request_list.push_back(object_it->second.local_id); + object_it->second.request = FSObjectProperties::SENT; + mOutstandingRequests++; + if (mOutstandingRequests >= ((MAX_OBJECTS_PER_PACKET * 3) - 3)) + { + requestObjectProperties(request_list, true); + requestObjectProperties(request_list, false); + return; + } + } + } + + if (!request_list.empty()) + { + requestObjectProperties(request_list, true); + requestObjectProperties(request_list, false); + } + mRequestNeedsSent = false; +} + void FSAreaSearch::requestObjectProperties(const std::vector& request_list, bool select) { bool start_new_message = true; @@ -448,7 +563,7 @@ void FSAreaSearch::requestObjectProperties(const std::vector& request_list, if(msg->isSendFull(NULL) || select_count >= MAX_OBJECTS_PER_PACKET) { - LL_DEBUGS("FSAreaSearch") << "Sent one" << (select ? "ObjectSelect" : "ObjectDeselect") << "message" << LL_ENDL; + LL_DEBUGS("FSAreaSearch") << "Sent one full " << (select ? "ObjectSelect" : "ObjectDeselect") << " message with " << select_count << " object data blocks." << LL_ENDL; msg->sendReliable(regionp->getHost() ); select_count = 0; start_new_message = true; @@ -457,7 +572,7 @@ void FSAreaSearch::requestObjectProperties(const std::vector& request_list, if (!start_new_message) { - LL_DEBUGS("FSAreaSearch") << "Sent one" << (select ? "ObjectSelect" : "ObjectDeselect") << "message" << LL_ENDL; + LL_DEBUGS("FSAreaSearch") << "Sent one partcial " << (select ? "ObjectSelect" : "ObjectDeselect") << " message with " << select_count << " object data blocks." << LL_ENDL; msg->sendReliable(regionp->getHost() ); } } @@ -474,7 +589,7 @@ void FSAreaSearch::processObjectProperties(LLMessageSystem* msg) bool counter_text_update = false; S32 count = msg->getNumberOfBlocksFast(_PREHASH_ObjectData); - LL_DEBUGS("FSAreaSearch") << "Got processObjectProperties message with " << count << "object(s)" << LL_ENDL; + LL_DEBUGS("FSAreaSearch") << "Got processObjectProperties message with " << count << " object(s)" << LL_ENDL; for (S32 i = 0; i < count; i++) { LLUUID object_id; @@ -486,18 +601,19 @@ void FSAreaSearch::processObjectProperties(LLMessageSystem* msg) } LLViewerObject* objectp = gObjectList.findObject(object_id); - if (!(objectp && objectp->isRootEdit())) + if (!objectp) { continue; } FSObjectProperties& details = mObjectDetails[object_id]; - if (!details.valid) + if (details.request != FSObjectProperties::FINISHED) { // We cache un-requested objects (to avoid having to request them later) // and requested objects. - details.valid = true; + details.request = FSObjectProperties::FINISHED; + mLastProptiesRecievedTimer.start(); if (details.id.isNull()) { @@ -510,6 +626,7 @@ void FSAreaSearch::processObjectProperties(LLMessageSystem* msg) { mRequested--; } + mOutstandingRequests--; counter_text_update = true; } @@ -553,7 +670,7 @@ void FSAreaSearch::processObjectProperties(LLMessageSystem* msg) // Sets the group owned BOOL and real owner id, group or owner depending if object is group owned. details.permissions.getOwnership(details.ownership_id, details.group_owned); - LL_DEBUGS("FSAreaSearch") << "Got properties for object: " << object_id << LL_ENDL; + LL_DEBUGS("FSAreaSearch_spammy") << "Got properties for object: " << object_id << LL_ENDL; if (isSearchableObject(objectp, our_region)) { @@ -771,61 +888,63 @@ void FSAreaSearch::matchObject(FSObjectProperties& details, LLViewerObject* obje //----------------------------------------------------------------------- details.listed = true; - - LLScrollListColumn* column; - LLSD element; - element["id"] = object_id; - column = mPanelList->getResultList()->getColumn("distance"); - if (column) + LLScrollListCell::Params cellParams; + cellParams.font = LLFontGL::getFontSansSerif(); + + LLScrollListItem::Params rowParams; + rowParams.value = object_id.asString(); + + if (mColumnDistance) { - element["columns"][column->mIndex]["column"] = "distance"; - element["columns"][column->mIndex]["value"] = llformat("%1.0f m", dist_vec(mPanelList->getAgentLastPosition(), objectp->getPositionGlobal())); // used mAgentLastPosition instead of gAgent->getPositionGlobal for performace + cellParams.column = "distance"; + cellParams.value = llformat("%1.0f m", dist_vec(mPanelList->getAgentLastPosition(), objectp->getPositionGlobal())); // used mAgentLastPosition instead of gAgent->getPositionGlobal for performace + rowParams.columns.add(cellParams); } - column = mPanelList->getResultList()->getColumn("name"); - if (column) + if (mColumnName) { - element["columns"][column->mIndex]["column"] = "name"; - element["columns"][column->mIndex]["value"] = details.name; + cellParams.column = "name"; + cellParams.value = details.name; + rowParams.columns.add(cellParams); } - column = mPanelList->getResultList()->getColumn("description"); - if (column) + if (mColumnDescription) { - element["columns"][column->mIndex]["column"] = "description"; - element["columns"][column->mIndex]["value"] = details.description; + cellParams.column = "description"; + cellParams.value = details.description; + rowParams.columns.add(cellParams); } - column = mPanelList->getResultList()->getColumn("owner"); - if (column) + if (mColumnOwner) { - element["columns"][column->mIndex]["column"] = "owner"; - element["columns"][column->mIndex]["value"] = owner_name; + cellParams.column = "owner"; + cellParams.value = owner_name; + rowParams.columns.add(cellParams); } - column = mPanelList->getResultList()->getColumn("group"); - if (column) + if (mColumnGroup) { - element["columns"][column->mIndex]["column"] = "group"; - element["columns"][column->mIndex]["value"] = group_name; + cellParams.column = "group"; + cellParams.value = group_name; + rowParams.columns.add(cellParams); } - column = mPanelList->getResultList()->getColumn("creator"); - if (column) + if (mColumnCreator) { - element["columns"][column->mIndex]["column"] = "creator"; - element["columns"][column->mIndex]["value"] = creator_name; + cellParams.column = "creator"; + cellParams.value = creator_name; + rowParams.columns.add(cellParams); } - column = mPanelList->getResultList()->getColumn("last_owner"); - if (column) + if (mColumnLastOwner) { - element["columns"][column->mIndex]["column"] = "last_owner"; - element["columns"][column->mIndex]["value"] = last_owner_name; + cellParams.column = "last_owner"; + cellParams.value = last_owner_name; + rowParams.columns.add(cellParams); } - LLScrollListItem* list_row = mPanelList->getResultList()->addElement(element); + LLScrollListItem* list_row = mPanelList->getResultList()->addRow(rowParams); if (objectp->flagTemporaryOnRez() || objectp->flagUsePhysics()) { @@ -1209,22 +1328,26 @@ void FSPanelAreaSearchList::updateName(LLUUID id, std::string name) if (creator_column && (id == details.creator_id)) { - item->getColumn(creator_column->mIndex)->setValue(LLSD(name)); + LLScrollListText* creator_text = (LLScrollListText*)item->getColumn(creator_column->mIndex); + creator_text->setText(name); } if (owner_column && (id == details.owner_id)) { - item->getColumn(owner_column->mIndex)->setValue(LLSD(name)); + LLScrollListText* owner_text = (LLScrollListText*)item->getColumn(owner_column->mIndex); + owner_text->setText(name); } if (group_column && (id == details.group_id)) { - item->getColumn(group_column->mIndex)->setValue(LLSD(name)); + LLScrollListText* group_text = (LLScrollListText*)item->getColumn(group_column->mIndex); + group_text->setText(name); } if (last_owner_column && (id == details.last_owner_id)) { - item->getColumn(last_owner_column->mIndex)->setValue(LLSD(name)); + LLScrollListText* last_owner_text = (LLScrollListText*)item->getColumn(last_owner_column->mIndex); + last_owner_text->setText(name); } } } @@ -1700,6 +1823,60 @@ void FSPanelAreaSearchOptions::onCommitCheckboxDisplayColumn(const LLSD& userdat } } + // untill C++ supports variable withen a variablname, have to do this instead. + // used switch instead of a huge if then else if then else... + char c = column_name.at(0); + switch(c) + { + case 'd': + { + char d = column_name.at(1); + switch (d) + { + case 'i': + { + mFSAreaSearch->setColumnDistance(checkboxctrl->get()); + } + break; + case 'e': + { + mFSAreaSearch->setColumnDescription(checkboxctrl->get()); + } + break; + default: + break; + } + } + break; + case 'n': + { + mFSAreaSearch->setColumnName(checkboxctrl->get()); + } + break; + case 'o': + { + mFSAreaSearch->setColumnOwner(checkboxctrl->get()); + } + break; + case 'g': + { + mFSAreaSearch->setColumnGroup(checkboxctrl->get()); + } + break; + case 'c': + { + mFSAreaSearch->setColumnCreator(checkboxctrl->get()); + } + break; + case 'l': + { + mFSAreaSearch->setColumnLastOwner(checkboxctrl->get()); + } + break; + default: + break; + } + result_list->updateLayout(); } diff --git a/indra/newview/fsareasearch.h b/indra/newview/fsareasearch.h index fb9a9dacad..f839ac24d1 100644 --- a/indra/newview/fsareasearch.h +++ b/indra/newview/fsareasearch.h @@ -58,7 +58,6 @@ class FSPanelAreaSearchOptions; struct FSObjectProperties { LLUUID id; - bool valid; bool listed; std::string name; std::string description; @@ -80,9 +79,19 @@ struct FSObjectProperties LLPermissions permissions; uuid_vec_t texture_ids; bool name_requested; + U32 local_id; + + typedef enum e_object_properties_request + { + NEED, + SENT, + FINISHED, + FAILED + } EObjectPropertiesRequest; + EObjectPropertiesRequest request; FSObjectProperties() : - valid(false), + request(NEED), listed(false), name_requested(false) { @@ -144,6 +153,14 @@ public: void setFilterDistance(bool b) { mFilterDistance = b; } void setFilterDistanceMin(S32 s) { mFilterDistanceMin = s; } void setFilterDistanceMax(S32 s) { mFilterDistanceMax = s; } + + void setColumnDistance(bool b) { mColumnDistance = b; } + void setColumnName(bool b) { mColumnName = b; } + void setColumnDescription(bool b) { mColumnDescription = b; } + void setColumnOwner(bool b) { mColumnOwner = b; } + void setColumnGroup(bool b) { mColumnGroup = b; } + void setColumnCreator(bool b) { mColumnCreator = b; } + void setColumnLastOwner(bool b) { mColumnLastOwner = b; } private: void requestObjectProperties(const std::vector& request_list, bool select); @@ -153,11 +170,15 @@ private: void updateCounterText(); bool regexTest(std::string text); void findObjects(); + void processRequestQueue(); S32 mRequested; bool mRefresh; S32 mSearchableObjects; bool mActive; + bool mRequestQueuePause; + bool mRequestNeedsSent; + S32 mOutstandingRequests; std::string mSearchName; std::string mSearchDescription; @@ -175,6 +196,7 @@ private: boost::regex mRegexSearchLastOwner; LLFrameTimer mLastUpdateTimer; + LLFrameTimer mLastProptiesRecievedTimer; std::vector mNamesRequested; @@ -221,6 +243,14 @@ private: bool mFilterClickAction; U8 mFilterClickActionType; + + bool mColumnDistance; + bool mColumnName; + bool mColumnDescription; + bool mColumnOwner; + bool mColumnGroup; + bool mColumnCreator; + bool mColumnLastOwner; protected: static void* createPanelList(void* data);