summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llagentwearables.cpp10
-rw-r--r--indra/newview/llappearancemgr.cpp2
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp9
-rw-r--r--indra/newview/llimprocessing.cpp4
-rw-r--r--indra/newview/llmutelist.cpp50
-rw-r--r--indra/newview/llmutelist.h14
-rw-r--r--indra/newview/lloutfitslist.cpp24
-rw-r--r--indra/newview/llpanelemojicomplete.cpp1
-rw-r--r--indra/newview/llpanelface.cpp2
-rw-r--r--indra/newview/llvoavatar.cpp54
-rw-r--r--indra/newview/llvoavatar.h5
-rw-r--r--indra/newview/llvoavatarself.cpp8
-rw-r--r--indra/newview/llvoavatarself.h2
-rw-r--r--indra/newview/tests/llviewerassetstats_test.cpp5
14 files changed, 140 insertions, 50 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/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
{
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..f6d635f51f 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<LLMuteList>
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<LLMute> getMutes() const;
@@ -167,7 +176,8 @@ private:
typedef std::set<LLMuteListObserver*> observer_set_t;
observer_set_t mObservers;
- bool mIsLoaded;
+ EMuteListState mLoadState;
+ F64 mRequestStartTime;
friend class LLDispatchEmptyMuteList;
};
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())
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<S32>(mVisibleEmojis) * mEmojiWidth) / -2, 0);
+ mRenderRect.translate(-mRenderRect.mLeft, 0); // Left align emojis to fix hitboxes
}
updateScrollPos();
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;
}
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<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars)
+void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& 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<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars);
+ static void getNearbyRezzedStats(std::vector<S32>& 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<S32> 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<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake");
std::vector<std::string> 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<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars)
+void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& 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