From c58caf6b42f1efbab95e4acdaa8adf9c3d53c930 Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Wed, 2 Jul 2025 09:20:59 -0700 Subject: [PATCH 01/10] Create pull_request_template.md Provide a PR template to expedite both internal and external contributions. --- .github/pull_request_template.md | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..9130b90218 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,36 @@ +## Description + + + +## Related Issues + +- [ ] **Please link to a relevant GitHub issue for additional context.** + - **Bug Fix:** Link to an issue that includes reproduction steps and testing guidance. + - **Feature/Enhancement:** Link to an issue with a write-up, rationale, and requirements. + +Issue Link: + +--- + +## Checklist + +Please ensure the following before requesting review: + +- [ ] I have provided a clear title and detailed description for this pull request. +- [ ] The PR is linked to a relevant issue with sufficient context (see above). +- [ ] I have tested the changes locally and verified they work as intended. +- [ ] All new and existing tests pass (if applicable). +- [ ] Code follows the project's style guidelines. +- [ ] Documentation (if needed) has been updated. +- [ ] Any dependent changes have been merged and published in downstream modules +- [ ] I have reviewed the [contributing guidelines](../CONTRIBUTING.md). + +--- + +## Additional Notes + + From 2e1d8c3063a7420433ac432b5f1f7f436f9294d1 Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Wed, 2 Jul 2025 09:50:23 -0700 Subject: [PATCH 02/10] Fix link in pull_request_template.md (#4329) Fix the link to CONTRIBUTING.md in the pull request template and simplify some of the checklist item language. --- .github/pull_request_template.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9130b90218..473498833e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -19,13 +19,13 @@ Issue Link: Please ensure the following before requesting review: - [ ] I have provided a clear title and detailed description for this pull request. -- [ ] The PR is linked to a relevant issue with sufficient context (see above). +- [ ] The PR is linked to a relevant issue with sufficient context. - [ ] I have tested the changes locally and verified they work as intended. -- [ ] All new and existing tests pass (if applicable). +- [ ] All new and existing tests pass. - [ ] Code follows the project's style guidelines. -- [ ] Documentation (if needed) has been updated. +- [ ] Documentation has been updated if needed. - [ ] Any dependent changes have been merged and published in downstream modules -- [ ] I have reviewed the [contributing guidelines](../CONTRIBUTING.md). +- [ ] I have reviewed the [contributing guidelines](https://github.com/secondlife/viewer/blob/develop/CONTRIBUTING.md). --- From de73d0f0093a5f5f26d0b36ecab0b4d1717e504a Mon Sep 17 00:00:00 2001 From: WolfGang Date: Wed, 2 Jul 2025 20:56:51 +0100 Subject: [PATCH 03/10] Merge pull request #4311 from WolfGangS/media-first-click-fixes-2 Fix bit logic mistake in PRIM_MEDIA_FIRST_CLICK_INTERACT work --- indra/newview/lltoolpie.cpp | 2 +- indra/newview/lltoolpie.h | 4 ++-- .../newview/skins/default/xui/en/panel_preferences_sound.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 75b980d358..618955c83b 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -1527,7 +1527,7 @@ bool LLToolPie::shouldAllowFirstMediaInteraction(const LLPickInfo& pick, bool mo return false; } // Any object with PRIM_MEDIA_FIRST_CLICK_INTERACT set to TRUE - if(FirstClickPref & MEDIA_FIRST_CLICK_ANY) + if((FirstClickPref & MEDIA_FIRST_CLICK_ANY) == MEDIA_FIRST_CLICK_ANY) { LL_DEBUGS_ONCE() << "FirstClickPref & MEDIA_FIRST_CLICK_ANY" << LL_ENDL; return true; diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index ee7945d16f..d9daad9515 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -94,8 +94,8 @@ private: MEDIA_FIRST_CLICK_NONE = 0, // Special case: Feature is disabled MEDIA_FIRST_CLICK_HUD = 1 << 0, // 0b00000001 (1) MEDIA_FIRST_CLICK_OWN = 1 << 1, // 0b00000010 (2) - MEDIA_FIRST_CLICK_GROUP = 1 << 2, // 0b00000100 (4) - MEDIA_FIRST_CLICK_FRIEND = 1 << 3, // 0b00001000 (8) + MEDIA_FIRST_CLICK_FRIEND = 1 << 2, // 0b00000100 (4) + MEDIA_FIRST_CLICK_GROUP = 1 << 3, // 0b00001000 (8) MEDIA_FIRST_CLICK_LAND = 1 << 4, // 0b00010000 (16) // Covers any object with PRIM_MEDIA_FIRST_CLICK_INTERACT (combines all previous flags) diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml index 473e54812d..de6132aec6 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml @@ -410,7 +410,7 @@ + value="7"/> Date: Wed, 9 Jul 2025 18:54:06 +0300 Subject: [PATCH 04/10] #4339 World Map Find button shouldn't autocomplete Either don't track (go) or implement trackSearch onCommitSearchResult() tracks location and 'autocompletes' as it is meant for selecting and applying items from search list. --- indra/newview/llfloaterworldmap.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index c70058145a..565642e683 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -1694,14 +1694,15 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) if (!match.isUndefined()) { mSearchResults->selectByValue(match); + mSearchResults->setFocus(true); + onCommitSearchResult(); } - // else select first found item + // else let user decide else { - mSearchResults->selectFirstItem(); + mSearchResults->operateOnAll(LLCtrlListInterface::OP_DESELECT); + mSearchResults->setFocus(true); } - mSearchResults->setFocus(true); - onCommitSearchResult(); } else { From 210abc3755038d3b8630a646734df52fa54459fd Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Thu, 10 Jul 2025 15:15:10 +0300 Subject: [PATCH 05/10] #4349 fix repeats cannot be adjusted for specular when a normal map is not applied --- indra/newview/llpanelface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 0086a9a86d..25dd37590d 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -276,7 +276,7 @@ LLRender::eTexIndex LLPanelFace::getMatTextureChannel() return LLRender::NORMAL_MAP; break; case MATTYPE_SPECULAR: // "Shininess (specular)" - if (getCurrentNormalMap().notNull()) + if (getCurrentSpecularMap().notNull()) return LLRender::SPECULAR_MAP; break; } From 2e931a55adef97812f9673b8b03691bfa134403b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 10 Jul 2025 20:45:07 +0300 Subject: [PATCH 06/10] #3725 Improve reporting of avatar statistics 1. Don't report UI avatars, they are local and UI specific 2. Split animeshes from normal avatars 3. Rename 'cloud' to 'missing parts', it's not related to 'cloud' 4. Exclude self 5. Report avatars held by meshes --- indra/newview/llagentwearables.cpp | 10 ++-- indra/newview/llappearancemgr.cpp | 2 +- indra/newview/llvoavatar.cpp | 54 +++++++++++++------ indra/newview/llvoavatar.h | 5 +- indra/newview/llvoavatarself.cpp | 8 ++- indra/newview/llvoavatarself.h | 2 +- .../newview/tests/llviewerassetstats_test.cpp | 5 +- 7 files changed, 57 insertions(+), 29 deletions(-) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index cd4222dddf..25f5cbd78f 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1094,12 +1094,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it { gAgentAvatarp->setCompositeUpdatesEnabled(true); - // If we have not yet declouded, we may want to use + // If we have not yet loaded core parts, we may want to use // baked texture UUIDs sent from the first objectUpdate message - // don't overwrite these. If we have already declouded, we've saved - // these ids as the last known good textures and can invalidate without - // re-clouding. - if (!gAgentAvatarp->getIsCloud()) + // don't overwrite these. If we have parts already, we've saved + // these texture ids as the last known good textures and can + // invalidate without having to recloud avatar. + if (!gAgentAvatarp->getHasMissingParts()) { gAgentAvatarp->invalidateAll(); } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index e9d455ae53..8a17ccfeef 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -856,7 +856,7 @@ void LLWearableHoldingPattern::checkMissingWearables() // was requested but none was found, create a default asset as a replacement. // In all other cases, don't do anything. // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud - // due to logic in LLVOAvatarSelf::getIsCloud(). + // due to logic in LLVOAvatarSelf::getHasMissingParts(). // For non-critical types (tatoo, socks, etc.) the wearable will just be missing. (requested_by_type[type] > 0) && ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index dcba891f9f..dd59979a6c 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -678,6 +678,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mVisuallyMuteSetting(AV_RENDER_NORMALLY), mMutedAVColor(LLColor4::white /* used for "uninitialize" */), mFirstFullyVisible(true), + mWaitingForMeshes(false), mFirstDecloudTime(-1.f), mFullyLoaded(false), mPreviousFullyLoaded(false), @@ -920,12 +921,12 @@ bool LLVOAvatar::isFullyTextured() const bool LLVOAvatar::hasGray() const { - return !getIsCloud() && !isFullyTextured(); + return !getHasMissingParts() && !isFullyTextured(); } S32 LLVOAvatar::getRezzedStatus() const { - if (getIsCloud()) return 0; + if (getHasMissingParts()) return 0; bool textured = isFullyTextured(); bool all_baked_loaded = allBakedTexturesCompletelyDownloaded(); if (textured && all_baked_loaded && getAttachmentCount() == mSimAttachments.size()) return 4; @@ -972,30 +973,45 @@ bool LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) } // static -void LLVOAvatar::getNearbyRezzedStats(std::vector& counts, F32& avg_cloud_time, S32& cloud_avatars) +void LLVOAvatar::getNearbyRezzedStats(std::vector& counts, F32& avg_cloud_time, S32& cloud_avatars, S32& pending_meshes, S32& control_avatars) { counts.clear(); counts.resize(5); avg_cloud_time = 0; cloud_avatars = 0; + pending_meshes = 0; + control_avatars = 0; S32 count_avg = 0; for (LLCharacter* character : LLCharacter::sInstances) { - if (LLVOAvatar* inst = (LLVOAvatar*)character) + LLVOAvatar* inst = (LLVOAvatar*)character; + if (inst && !inst->isUIAvatar() && !inst->isSelf()) { - S32 rez_status = inst->getRezzedStatus(); - counts[rez_status]++; - F32 time = inst->getFirstDecloudTime(); - if (time >= 0) + if (inst->isControlAvatar()) { - avg_cloud_time+=time; - count_avg++; + control_avatars++; } - if (!inst->isFullyLoaded() || time < 0) + else { - // still renders as cloud - cloud_avatars++; + S32 rez_status = inst->getRezzedStatus(); + counts[rez_status]++; + F32 time = inst->getFirstDecloudTime(); + if (time >= 0) + { + avg_cloud_time += time; + count_avg++; + } + if (!inst->isFullyLoaded() || time < 0) + { + // still renders as cloud + cloud_avatars++; + if (rez_status >= 4 + && inst->mWaitingForMeshes) + { + pending_meshes++; + } + } } } } @@ -1012,7 +1028,7 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status) switch (rez_status) { case 0: - return "cloud"; + return "missing parts"; case 1: return "gray"; case 2: @@ -3474,7 +3490,7 @@ void LLVOAvatar::idleUpdateNameTagText(bool new_name) is_muted = isInMuteList(); } bool is_friend = isBuddy(); - bool is_cloud = getIsCloud(); + bool is_cloud = getHasMissingParts(); if (is_appearance != mNameAppearance) { @@ -8201,7 +8217,7 @@ bool LLVOAvatar::isVisible() const } // Determine if we have enough avatar data to render -bool LLVOAvatar::getIsCloud() const +bool LLVOAvatar::getHasMissingParts() const { if (mIsDummy) { @@ -8408,8 +8424,12 @@ bool LLVOAvatar::updateIsFullyLoaded() || (mLoadedCallbackTextures < mCallbackTextureList.size() && mLastTexCallbackAddedTime.getElapsedTimeF32() < MAX_TEXTURE_WAIT_TIME_SEC) || !mPendingAttachment.empty() || (rez_status < 3 && !isFullyBaked()) - || hasPendingAttachedMeshes() ); + if (!loading) + { + mWaitingForMeshes = hasPendingAttachedMeshes(); + loading = mWaitingForMeshes; + } // compare amount of attachments to one reported by simulator if (!isSelf() && mLastCloudAttachmentCount < mSimAttachments.size() && mSimAttachments.size() > 0) diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 9eb8d3f880..178665f4c5 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -400,7 +400,7 @@ public: bool isTooComplex() const; bool visualParamWeightsAreDefault(); - virtual bool getIsCloud() const; + virtual bool getHasMissingParts() const; bool isFullyTextured() const; bool hasGray() const; S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = textured, 3 = textured and fully downloaded. @@ -427,6 +427,7 @@ protected: private: bool mFirstFullyVisible; + bool mWaitingForMeshes; F32 mFirstDecloudTime; LLFrameTimer mFirstAppearanceMessageTimer; @@ -723,7 +724,7 @@ public: bool isFullyBaked(); static bool areAllNearbyInstancesBaked(S32& grey_avatars); - static void getNearbyRezzedStats(std::vector& counts, F32& avg_cloud_time, S32& cloud_avatars); + static void getNearbyRezzedStats(std::vector& counts, F32& avg_cloud_time, S32& cloud_avatars, S32& pending_meshes, S32& control_avatars); static std::string rezStatusToString(S32 status); //-------------------------------------------------------------------- diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index ebba9ba291..8da48910c6 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1927,7 +1927,7 @@ void LLVOAvatarSelf::dumpTotalLocalTextureByteCount() LL_INFOS() << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << LL_ENDL; } -bool LLVOAvatarSelf::getIsCloud() const +bool LLVOAvatarSelf::getHasMissingParts() const { // Let people know why they're clouded without spamming them into oblivion. bool do_warn = false; @@ -2237,14 +2237,18 @@ void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url) std::vector rez_counts; F32 avg_time; S32 total_cloud_avatars; - LLVOAvatar::getNearbyRezzedStats(rez_counts, avg_time, total_cloud_avatars); + S32 waiting_for_meshes; + S32 control_avatars; + LLVOAvatar::getNearbyRezzedStats(rez_counts, avg_time, total_cloud_avatars, waiting_for_meshes, control_avatars); for (S32 rez_stat = 0; rez_stat < rez_counts.size(); ++rez_stat) { std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat); msg["nearby"][rez_status_name] = rez_counts[rez_stat]; } + msg["nearby"]["waiting_for_meshes"] = waiting_for_meshes; msg["nearby"]["avg_decloud_time"] = avg_time; msg["nearby"]["cloud_total"] = total_cloud_avatars; + msg["nearby"]["animeshes"] = control_avatars; // std::vector bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake"); std::vector by_fields; diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index f7cd974ab0..45985b2a80 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -129,7 +129,7 @@ public: // Loading state //-------------------------------------------------------------------- public: - /*virtual*/ bool getIsCloud() const; + /*virtual*/ bool getHasMissingParts() const; //-------------------------------------------------------------------- // Region state diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp index d5e281bba8..10c68432a1 100644 --- a/indra/newview/tests/llviewerassetstats_test.cpp +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -43,12 +43,15 @@ namespace LLStatViewer LLTrace::SampleStatHandle<> FPS_SAMPLE("fpssample"); } -void LLVOAvatar::getNearbyRezzedStats(std::vector& counts, F32& avg_cloud_time, S32& cloud_avatars) +void LLVOAvatar::getNearbyRezzedStats(std::vector& counts, F32& avg_cloud_time, S32& cloud_avatars, S32& pending_meshes, S32& control_avatars) { counts.resize(3); counts[0] = 0; counts[1] = 0; counts[2] = 1; + cloud_avatars = 0; + pending_meshes = 0; + control_avatars = 0; } // static From c488919ef296cd763346b48195a17d099dd19f8c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 11 Jul 2025 00:47:12 +0300 Subject: [PATCH 07/10] #4267 Offline messages not being requested According to logs onFileMuteList doesn't get triggered. I was able to repro, server just doesn't respond when file doesn't exist server side. As a workaround added timeout and state tracking into LLMuteList. --- indra/newview/llimprocessing.cpp | 4 +-- indra/newview/llmutelist.cpp | 50 ++++++++++++++++++++++++++++---- indra/newview/llmutelist.h | 14 +++++++-- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 4c02511268..7cd0171a37 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1520,10 +1520,10 @@ void LLIMProcessing::requestOfflineMessages() if (!requested && gMessageSystem && !gDisconnected - && LLMuteList::getInstance()->isLoaded() && isAgentAvatarValid() && gAgent.getRegion() - && gAgent.getRegion()->capabilitiesReceived()) + && gAgent.getRegion()->capabilitiesReceived() + && (LLMuteList::getInstance()->isLoaded() || LLMuteList::getInstance()->getLoadFailed())) { std::string cap_url = gAgent.getRegionCapability("ReadOfflineMsgs"); diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 2d51acc063..b044f6ad29 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -154,7 +154,8 @@ std::string LLMute::getDisplayType() const // LLMuteList() //----------------------------------------------------------------------------- LLMuteList::LLMuteList() : - mIsLoaded(false) + mLoadState(ML_INITIAL), + mRequestStartTime(0.f) { gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList); @@ -209,6 +210,23 @@ bool LLMuteList::isLinden(const std::string& name) return last_name == "linden"; } +bool LLMuteList::getLoadFailed() const +{ + if (mLoadState == ML_FAILED) + { + return true; + } + if (mLoadState == ML_REQUESTED) + { + constexpr F64 WAIT_SECONDS = 30; + if (mRequestStartTime + WAIT_SECONDS > LLTimer::getTotalSeconds()) + { + return true; + } + } + return false; +} + static LLVOAvatar* find_avatar(const LLUUID& id) { LLViewerObject *obj = gObjectList.findObject(id); @@ -371,11 +389,14 @@ void LLMuteList::updateAdd(const LLMute& mute) msg->addU32("MuteFlags", mute.mFlags); gAgent.sendReliableMessage(); - if (!mIsLoaded) + if (!isLoaded()) { LL_WARNS() << "Added elements to non-initialized block list" << LL_ENDL; } - mIsLoaded = true; // why is this here? -MG + // Based of logs and testing, if file doesn't exist server side, + // viewer will not receive any callback and won't know to set + // ML_LOADED. As a workaround, set it regardless of current state. + mLoadState = ML_LOADED; } @@ -564,6 +585,7 @@ bool LLMuteList::loadFromFile(const std::string& filename) if(!filename.size()) { LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL; + mLoadState = ML_FAILED; return false; } @@ -571,6 +593,7 @@ bool LLMuteList::loadFromFile(const std::string& filename) if (!fp) { LL_WARNS() << "Couldn't open mute list " << filename << LL_ENDL; + mLoadState = ML_FAILED; return false; } @@ -730,13 +753,17 @@ void LLMuteList::requestFromServer(const LLUUID& agent_id) if (gDisconnected) { LL_WARNS() << "Trying to request mute list when disconnected!" << LL_ENDL; + mLoadState = ML_FAILED; return; } if (!gAgent.getRegion()) { LL_WARNS() << "No region for agent yet, skipping mute list request!" << LL_ENDL; + mLoadState = ML_FAILED; return; } + mLoadState = ML_REQUESTED; + mRequestStartTime = LLTimer::getElapsedSeconds(); // Double amount of retries due to this request happening during busy stage // Ideally this should be turned into a capability gMessageSystem->sendReliable(gAgent.getRegionHost(), LL_DEFAULT_RELIABLE_RETRIES * 2, true, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); @@ -749,7 +776,7 @@ void LLMuteList::requestFromServer(const LLUUID& agent_id) void LLMuteList::cache(const LLUUID& agent_id) { // Write to disk even if empty. - if(mIsLoaded) + if(isLoaded()) { std::string agent_id_string; std::string filename; @@ -777,6 +804,13 @@ void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**) msg->getStringFast(_PREHASH_MuteData, _PREHASH_Filename, unclean_filename); std::string filename = LLDir::getScrubbedFileName(unclean_filename); + LLMuteList* mute_list = getInstance(); + mute_list->mLoadState = ML_REQUESTED; + mute_list->mRequestStartTime = LLTimer::getElapsedSeconds(); + + // Todo: Based of logs and testing, there is no callback + // from server if file doesn't exist server side. + // Once server side gets fixed make sure it gets handled right. std::string *local_filename_and_path = new std::string(gDirUtilp->getExpandedFilename( LL_PATH_CACHE, filename )); gXferManager->requestFile(*local_filename_and_path, filename, @@ -809,12 +843,16 @@ void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_ LLMuteList::getInstance()->loadFromFile(*local_filename_and_path); LLFile::remove(*local_filename_and_path); } + else + { + LLMuteList::getInstance()->mLoadState = ML_FAILED; + } delete local_filename_and_path; } void LLMuteList::onAccountNameChanged(const LLUUID& id, const std::string& username) { - if (mIsLoaded) + if (isLoaded()) { LLMute mute(id, username, LLMute::AGENT); mute_set_t::iterator mute_it = mMutes.find(mute); @@ -866,7 +904,7 @@ void LLMuteList::removeObserver(LLMuteListObserver* observer) void LLMuteList::setLoaded() { - mIsLoaded = true; + mLoadState = ML_LOADED; notifyObservers(); } diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index 13d579c61f..b65fd61fcc 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -74,6 +74,14 @@ class LLMuteList : public LLSingleton LLSINGLETON(LLMuteList); ~LLMuteList(); /*virtual*/ void cleanupSingleton() override; + + enum EMuteListState + { + ML_INITIAL, + ML_REQUESTED, + ML_LOADED, + ML_FAILED, + }; public: // reasons for auto-unmuting a resident enum EAutoReason @@ -107,7 +115,8 @@ public: static bool isLinden(const std::string& name); - bool isLoaded() const { return mIsLoaded; } + bool isLoaded() const { return mLoadState == ML_LOADED; } + bool getLoadFailed() const; std::vector getMutes() const; @@ -167,7 +176,8 @@ private: typedef std::set observer_set_t; observer_set_t mObservers; - bool mIsLoaded; + EMuteListState mLoadState; + F64 mRequestStartTime; friend class LLDispatchEmptyMuteList; }; From 8daa59c3299d153cd3b19ff8470284f0f2ddbea7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 11 Jul 2025 20:36:15 +0300 Subject: [PATCH 08/10] #4267 Offline messages not being requested #2 --- indra/newview/llmutelist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index b044f6ad29..f6d635f51f 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -219,7 +219,7 @@ bool LLMuteList::getLoadFailed() const if (mLoadState == ML_REQUESTED) { constexpr F64 WAIT_SECONDS = 30; - if (mRequestStartTime + WAIT_SECONDS > LLTimer::getTotalSeconds()) + if (mRequestStartTime + WAIT_SECONDS < LLTimer::getTotalSeconds()) { return true; } From 621be9cb9e0f37ffad71a12d4c4b0d23beb39993 Mon Sep 17 00:00:00 2001 From: TJ Date: Tue, 15 Jul 2025 02:09:09 +1000 Subject: [PATCH 09/10] #4365 Fix emoji hitboxes in the emoji history list in the IM floater by ensuring they are left aligned --- indra/newview/llpanelemojicomplete.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp index 3a6a6a5ec3..f0555408dd 100644 --- a/indra/newview/llpanelemojicomplete.cpp +++ b/indra/newview/llpanelemojicomplete.cpp @@ -463,6 +463,7 @@ void LLPanelEmojiComplete::updateConstraints() { mEmojiHeight = mRenderRect.getHeight(); mRenderRect.stretch((mRenderRect.getWidth() - static_cast(mVisibleEmojis) * mEmojiWidth) / -2, 0); + mRenderRect.translate(-mRenderRect.mLeft, 0); // Left align emojis to fix hitboxes } updateScrollPos(); From 268ec1f9c2428c6bdc3cf2086246ed125366af8d Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Tue, 15 Jul 2025 21:50:08 +0300 Subject: [PATCH 10/10] #4283 fix for missing items in 'My Outfits' floater --- indra/newview/lloutfitslist.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index df53c66ec1..36ffcae8df 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -34,10 +34,12 @@ #include "llaccordionctrl.h" #include "llaccordionctrltab.h" #include "llagentwearables.h" +#include "llaisapi.h" #include "llappearancemgr.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" #include "llinspecttexture.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llmenubutton.h" @@ -205,12 +207,22 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3)); - // Fetch the new outfit contents. - cat->fetch(); - - // Refresh the list of outfit items after fetch(). - // Further list updates will be triggered by the category observer. - list->updateList(cat_id); + if (AISAPI::isAvailable() && LLInventoryModelBackgroundFetch::instance().folderFetchActive()) + { + // for reliability just fetch it whole, linked items included + LLInventoryModelBackgroundFetch::instance().fetchFolderAndLinks(cat_id, [cat_id, list] + { + if (list) list->updateList(cat_id); + }); + } + else + { + // Fetch the new outfit contents. + cat->fetch(); + // Refresh the list of outfit items after fetch(). + // Further list updates will be triggered by the category observer. + list->updateList(cat_id); + } // If filter is currently applied we store the initial tab state. if (!getFilterSubString().empty())