diff options
author | Erik Kundiman <erik@megapahit.org> | 2025-08-08 07:30:46 +0800 |
---|---|---|
committer | Erik Kundiman <erik@megapahit.org> | 2025-08-08 07:37:27 +0800 |
commit | cfc4f075a82f9dc1156fce6994083143de6727a8 (patch) | |
tree | 2948ea5c6ebfbbc15721a2838804d6a766742887 /indra | |
parent | 73fdef6693017f1160875d1f7a79875945df3929 (diff) | |
parent | 55f1c8b9797836c9816528bb5b772eb83b083b50 (diff) |
Merge tag 'Second_Life_Release#55f1c8b9-2025.06' into 2025.06
Diffstat (limited to 'indra')
95 files changed, 1433 insertions, 1181 deletions
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 6ac00fd131..0153e69d5b 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -6,6 +6,9 @@ include(CMakeCopyIfDifferent) include(Linking) +if (USE_DISCORD) + include(Discord) +endif () include(OPENAL) # When we copy our dependent libraries, we almost always want to copy them to @@ -75,6 +78,10 @@ if(WINDOWS) endif(ADDRESS_SIZE EQUAL 32) endif (USE_BUGSPLAT) + if (TARGET ll::discord_sdk) + list(APPEND release_files discord_partner_sdk.dll) + endif () + if (TARGET ll::openal) list(APPEND release_files openal32.dll alut.dll) endif () @@ -180,6 +187,10 @@ elseif(DARWIN) ) endif() + if (TARGET ll::discord_sdk) + list(APPEND release_files libdiscord_partner_sdk.dylib) + endif () + if (TARGET ll::openal) list(APPEND release_files libalut.dylib libopenal.dylib) endif () diff --git a/indra/cmake/Discord.cmake b/indra/cmake/Discord.cmake index 52c0765ae7..1896c12853 100644 --- a/indra/cmake/Discord.cmake +++ b/indra/cmake/Discord.cmake @@ -1,18 +1,23 @@ include(Prebuilt) -add_library(ll::discord INTERFACE IMPORTED) -target_compile_definitions(ll::discord INTERFACE LL_DISCORD=1) +include_guard() -if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/discord_installed OR NOT ${discord_installed} EQUAL 0) +add_library(ll::discord_sdk INTERFACE IMPORTED) +target_compile_definitions(ll::discord_sdk INTERFACE LL_DISCORD=1) + +#use_prebuilt_binary(discord_sdk) + +if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/discord_sdk_installed OR NOT ${discord_sdk_installed} EQUAL 0) file(ARCHIVE_EXTRACT INPUT $ENV{HOME}/Downloads/DiscordSocialSdk-1.4.9649.zip DESTINATION ${CMAKE_BINARY_DIR} ) + file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/include/discord_sdk) file( COPY ${CMAKE_BINARY_DIR}/discord_social_sdk/include/cdiscord.h ${CMAKE_BINARY_DIR}/discord_social_sdk/include/discordpp.h - DESTINATION ${LIBS_PREBUILT_DIR}/include + DESTINATION ${LIBS_PREBUILT_DIR}/include/discord_sdk ) if (WINDOWS) file( @@ -38,8 +43,8 @@ if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKIN DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE} ) endif () - file(WRITE ${PREBUILD_TRACKING_DIR}/discord_installed "0") + file(WRITE ${PREBUILD_TRACKING_DIR}/discord_sdk_installed "0") endif () -target_include_directories(ll::discord SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) -target_link_libraries(ll::discord INTERFACE discord_partner_sdk) +target_include_directories(ll::discord_sdk SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/discord_sdk) +target_link_libraries(ll::discord_sdk INTERFACE discord_partner_sdk) diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index fe60800700..3defad8f3b 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -995,6 +995,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) // TODO - figure out if this should be moved into the noclobber fields above mThumbnailUUID.setNull(); mFavorite = false; + mPermissions.init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null); // iterate as map to avoid making unnecessary temp copies of everything LLSD::map_const_iterator i, end; @@ -1053,7 +1054,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) if (i->first == INV_PERMISSIONS_LABEL) { - mPermissions = ll_permissions_from_sd(i->second); + mPermissions.importLLSD(i->second); continue; } @@ -1522,53 +1523,68 @@ void LLInventoryCategory::exportLLSD(LLSD& cat_data) const } } -bool LLInventoryCategory::importLLSD(const LLSD& cat_data) +bool LLInventoryCategory::importLLSDMap(const LLSD& cat_data) { - if (cat_data.has(INV_FOLDER_ID_LABEL)) + LLSD::map_const_iterator i, end; + end = cat_data.endMap(); + for ( i = cat_data.beginMap(); i != end; ++i) + { + importLLSD(i->first, i->second); + } + return true; +} + +bool LLInventoryCategory::importLLSD(const std::string& label, const LLSD& value) +{ + if (label == INV_FOLDER_ID_LABEL) { - setUUID(cat_data[INV_FOLDER_ID_LABEL].asUUID()); + setUUID(value.asUUID()); + return true; } - if (cat_data.has(INV_PARENT_ID_LABEL)) + else if (label == INV_PARENT_ID_LABEL) { - setParent(cat_data[INV_PARENT_ID_LABEL].asUUID()); + setParent(value.asUUID()); + return true; } - if (cat_data.has(INV_ASSET_TYPE_LABEL)) + else if (label == INV_ASSET_TYPE_LABEL) { - setType(LLAssetType::lookup(cat_data[INV_ASSET_TYPE_LABEL].asString())); + setType(LLAssetType::lookup(value.asString())); + return true; } - if (cat_data.has(INV_PREFERRED_TYPE_LABEL)) + else if (label == INV_PREFERRED_TYPE_LABEL) { - setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString())); + setPreferredType(LLFolderType::lookup(value.asString())); + return true; } - if (cat_data.has(INV_THUMBNAIL_LABEL)) + else if (label == INV_THUMBNAIL_LABEL) { LLUUID thumbnail_uuid; - const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL]; - if (thumbnail_data.has(INV_ASSET_ID_LABEL)) + if (value.has(INV_ASSET_ID_LABEL)) { - thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID(); + thumbnail_uuid = value[INV_ASSET_ID_LABEL].asUUID(); } setThumbnailUUID(thumbnail_uuid); + return true; } - if (cat_data.has(INV_FAVORITE_LABEL)) + if (label == INV_FAVORITE_LABEL) { bool favorite = false; - const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL]; - if (favorite_data.has(INV_TOGGLED_LABEL)) + if (value.has(INV_TOGGLED_LABEL)) { - favorite = favorite_data[INV_TOGGLED_LABEL].asBoolean(); + favorite = value[INV_TOGGLED_LABEL].asBoolean(); } setFavorite(favorite); } - if (cat_data.has(INV_NAME_LABEL)) + else if (label == INV_NAME_LABEL) { - mName = cat_data[INV_NAME_LABEL].asString(); + mName = value.asString(); LLStringUtil::replaceNonstandardASCII(mName, ' '); LLStringUtil::replaceChar(mName, '|', ' '); + return true; } - - return true; + return false; } + ///---------------------------------------------------------------------------- /// Local function definitions for testing purposes ///---------------------------------------------------------------------------- diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 17670d2ea1..181c46226c 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -274,7 +274,8 @@ public: virtual bool exportLegacyStream(std::ostream& output_stream, bool include_asset_key = true) const; virtual void exportLLSD(LLSD& sd) const; - bool importLLSD(const LLSD& cat_data); + bool importLLSDMap(const LLSD& cat_data); + virtual bool importLLSD(const std::string& label, const LLSD& value); //-------------------------------------------------------------------- // Member Variables //-------------------------------------------------------------------- diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index d800ca02c9..ebf7445c65 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -704,6 +704,79 @@ bool LLPermissions::exportLegacyStream(std::ostream& output_stream) const return true; } +static const std::string PERM_CREATOR_ID_LABEL("creator_id"); +static const std::string PERM_OWNER_ID_LABEL("owner_id"); +static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id"); +static const std::string PERM_GROUP_ID_LABEL("group_id"); +static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group"); +static const std::string PERM_BASE_MASK_LABEL("base_mask"); +static const std::string PERM_OWNER_MASK_LABEL("owner_mask"); +static const std::string PERM_GROUP_MASK_LABEL("group_mask"); +static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask"); +static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask"); + +void LLPermissions::importLLSD(const LLSD& sd_perm) +{ + LLSD::map_const_iterator i, end; + end = sd_perm.endMap(); + for (i = sd_perm.beginMap(); i != end; ++i) + { + const std::string& label = i->first; + if (label == PERM_CREATOR_ID_LABEL) + { + mCreator = i->second.asUUID(); + continue; + } + if (label == PERM_OWNER_ID_LABEL) + { + mOwner = i->second.asUUID(); + continue; + } + if (label == PERM_LAST_OWNER_ID_LABEL) + { + mLastOwner = i->second.asUUID(); + continue; + } + if (label == PERM_GROUP_ID_LABEL) + { + mGroup = i->second.asUUID(); + continue; + } + if (label == PERM_BASE_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskBase = mask; + continue; + } + if (label == PERM_OWNER_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskOwner = mask; + continue; + } + if (label == PERM_EVERYONE_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskEveryone = mask; + continue; + } + if (label == PERM_GROUP_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskGroup = mask; + continue; + } + if (label == PERM_NEXT_OWNER_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskNextOwner = mask; + continue; + } + } + + fix(); +} + bool LLPermissions::operator==(const LLPermissions &rhs) const { return @@ -998,16 +1071,6 @@ std::string mask_to_string(U32 mask) ///---------------------------------------------------------------------------- /// exported functions ///---------------------------------------------------------------------------- -static const std::string PERM_CREATOR_ID_LABEL("creator_id"); -static const std::string PERM_OWNER_ID_LABEL("owner_id"); -static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id"); -static const std::string PERM_GROUP_ID_LABEL("group_id"); -static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group"); -static const std::string PERM_BASE_MASK_LABEL("base_mask"); -static const std::string PERM_OWNER_MASK_LABEL("owner_mask"); -static const std::string PERM_GROUP_MASK_LABEL("group_mask"); -static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask"); -static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask"); LLSD ll_create_sd_from_permissions(const LLPermissions& perm) { @@ -1032,25 +1095,6 @@ void ll_fill_sd_from_permissions(LLSD& rv, const LLPermissions& perm) LLPermissions ll_permissions_from_sd(const LLSD& sd_perm) { LLPermissions rv; - rv.init( - sd_perm[PERM_CREATOR_ID_LABEL].asUUID(), - sd_perm[PERM_OWNER_ID_LABEL].asUUID(), - sd_perm[PERM_LAST_OWNER_ID_LABEL].asUUID(), - sd_perm[PERM_GROUP_ID_LABEL].asUUID()); - - // We do a cast to U32 here since LLSD does not attempt to - // represent unsigned ints. - PermissionMask mask; - mask = (U32)(sd_perm[PERM_BASE_MASK_LABEL].asInteger()); - rv.setMaskBase(mask); - mask = (U32)(sd_perm[PERM_OWNER_MASK_LABEL].asInteger()); - rv.setMaskOwner(mask); - mask = (U32)(sd_perm[PERM_EVERYONE_MASK_LABEL].asInteger()); - rv.setMaskEveryone(mask); - mask = (U32)(sd_perm[PERM_GROUP_MASK_LABEL].asInteger()); - rv.setMaskGroup(mask); - mask = (U32)(sd_perm[PERM_NEXT_OWNER_MASK_LABEL].asInteger()); - rv.setMaskNext(mask); - rv.fix(); + rv.importLLSD(sd_perm); return rv; } diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index f3e10af25c..82cdc03727 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -299,6 +299,8 @@ public: bool importLegacyStream(std::istream& input_stream); bool exportLegacyStream(std::ostream& output_stream) const; + void importLLSD(const LLSD& sd_perm); + bool operator==(const LLPermissions &rhs) const; bool operator!=(const LLPermissions &rhs) const; diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index e41500b4c5..f11a4c3bf7 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -518,7 +518,7 @@ namespace tut file.close(); LLPointer<LLInventoryCategory> src2 = new LLInventoryCategory(); - src2->importLLSD(s_item); + src2->importLLSDMap(s_item); ensure_equals("1.item id::getUUID() failed", src1->getUUID(), src2->getUUID()); ensure_equals("2.parent::getParentUUID() failed", src1->getParentUUID(), src2->getParentUUID()); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index d56891cab3..e5521e0ffc 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5711,7 +5711,15 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) S32 vert_count = 0; if (!data.p.empty()) { - vert_count = static_cast<S32>(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count)); + try + { + vert_count = static_cast<S32>(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count)); + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("LLCoros") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL; + } } if (vert_count < 65535 && vert_count != 0) diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index ba9d0b8de3..2865b789b9 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -224,6 +224,7 @@ public: virtual S32 getSortVersion() = 0; virtual void setSortVersion(S32 version) = 0; virtual void setParent(LLFolderViewModelItem* parent) = 0; + virtual const LLFolderViewModelItem* getParent() = 0; virtual bool hasParent() = 0; protected: @@ -254,14 +255,14 @@ public: mChildren.clear(); } - void requestSort() { mSortVersion = -1; } - S32 getSortVersion() { return mSortVersion; } - void setSortVersion(S32 version) { mSortVersion = version;} + void requestSort() override { mSortVersion = -1; } + S32 getSortVersion() override { return mSortVersion; } + void setSortVersion(S32 version) override { mSortVersion = version;} - S32 getLastFilterGeneration() const { return mLastFilterGeneration; } + S32 getLastFilterGeneration() const override { return mLastFilterGeneration; } S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; } - S32 getMarkedDirtyGeneration() const { return mMarkedDirtyGeneration; } - void dirtyFilter() + S32 getMarkedDirtyGeneration() const override { return mMarkedDirtyGeneration; } + void dirtyFilter() override { if(mMarkedDirtyGeneration < 0) { @@ -276,7 +277,7 @@ public: mParent->dirtyFilter(); } } - void dirtyDescendantsFilter() + void dirtyDescendantsFilter() override { mMostFilteredDescendantGeneration = -1; if (mParent) @@ -284,13 +285,13 @@ public: mParent->dirtyDescendantsFilter(); } } - bool hasFilterStringMatch(); - std::string::size_type getFilterStringOffset(); - std::string::size_type getFilterStringSize(); + bool hasFilterStringMatch() override; + std::string::size_type getFilterStringOffset() override; + std::string::size_type getFilterStringSize() override; - typedef std::list<LLFolderViewModelItem*> child_list_t; + typedef std::list<LLPointer<LLFolderViewModelItem> > child_list_t; - virtual void addChild(LLFolderViewModelItem* child) + virtual void addChild(LLFolderViewModelItem* child) override { mChildren.push_back(child); child->setParent(this); @@ -298,15 +299,15 @@ public: requestSort(); } - virtual void removeChild(LLFolderViewModelItem* child) + virtual void removeChild(LLFolderViewModelItem* child) override final { - mChildren.remove(child); child->setParent(NULL); + mChildren.remove(child); dirtyDescendantsFilter(); dirtyFilter(); } - virtual void clearChildren() + virtual void clearChildren() override { // We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); }); @@ -319,7 +320,7 @@ public: child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); } child_list_t::size_type getChildrenCount() const { return mChildren.size(); } - void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) + void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) override { mPassedFilter = passed; mLastFilterGeneration = filter_generation; @@ -328,20 +329,20 @@ public: mMarkedDirtyGeneration = -1; } - void setPassedFolderFilter(bool passed, S32 filter_generation) + void setPassedFolderFilter(bool passed, S32 filter_generation) override { mPassedFolderFilter = passed; mLastFolderFilterGeneration = filter_generation; } - virtual bool potentiallyVisible() + virtual bool potentiallyVisible() override { return passedFilter() // we've passed the filter || (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet || descendantsPassedFilter(); } - virtual bool passedFilter(S32 filter_generation = -1) + virtual bool passedFilter(S32 filter_generation = -1) override { if (filter_generation < 0) { @@ -352,7 +353,7 @@ public: return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation)); } - virtual bool descendantsPassedFilter(S32 filter_generation = -1) + virtual bool descendantsPassedFilter(S32 filter_generation = -1) override { if (filter_generation < 0) { @@ -361,10 +362,10 @@ public: return mMostFilteredDescendantGeneration >= filter_generation; } - protected: - virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; } - virtual bool hasParent() { return mParent != NULL; } + virtual void setParent(LLFolderViewModelItem* parent) override final { mParent = parent; } + virtual const LLFolderViewModelItem* getParent() override { return mParent; }; + virtual bool hasParent() override { return mParent != NULL; } S32 mSortVersion; bool mPassedFilter; @@ -381,7 +382,7 @@ protected: LLFolderViewModelItem* mParent; LLFolderViewModelInterface& mRootViewModel; - void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;} + void setFolderViewItem(LLFolderViewItem* folder_view_item) override { mFolderViewItem = folder_view_item;} LLFolderViewItem* mFolderViewItem; }; @@ -395,15 +396,15 @@ public: mFolderView(NULL) {} - virtual void requestSortAll() + virtual void requestSortAll() override { // sort everything mTargetSortVersion++; } - virtual std::string getStatusText(bool is_empty_folder = false); - virtual void filter(); + virtual std::string getStatusText(bool is_empty_folder = false) override; + virtual void filter() override; - void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;} + void setFolderView(LLFolderView* folder_view) override { mFolderView = folder_view;} protected: bool needsSort(class LLFolderViewModelItem* item); @@ -433,14 +434,14 @@ public: virtual const SortType& getSorter() const { return *mSorter; } virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); } - virtual FilterType& getFilter() { return *mFilter; } - virtual const FilterType& getFilter() const { return *mFilter; } + virtual FilterType& getFilter() override { return *mFilter; } + virtual const FilterType& getFilter() const override { return *mFilter; } virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); } // By default, we assume the content is available. If a network fetch mechanism is implemented for the model, // this method needs to be overloaded and return the relevant fetch status. - virtual bool contentsReady() { return true; } - virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; } + virtual bool contentsReady() override { return true; } + virtual bool isFolderComplete(LLFolderViewFolder* folder) override { return true; } struct ViewModelCompare { @@ -461,7 +462,7 @@ public: const SortType& mSorter; }; - void sort(LLFolderViewFolder* folder) + void sort(LLFolderViewFolder* folder) override { if (needsSort(folder->getViewModelItem())) { diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 778b253c3c..7007049e1c 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2228,6 +2228,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.ReportAbuse", boost::bind(&LLUrlAction::reportAbuse, url)); registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url)); registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); + registrar.add("Url.ShowParcelOnMap", boost::bind(&LLUrlAction::showParcelOnMap, url)); registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index b6b450c2a1..fdae22cfa1 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -30,6 +30,7 @@ #include "llview.h" #include "llwindow.h" #include "llurlregistry.h" +#include "v3dmath.h" // global state for the callback functions @@ -128,6 +129,23 @@ void LLUrlAction::showLocationOnMap(std::string url) } } +void LLUrlAction::showParcelOnMap(std::string url) +{ + LLSD path_array = LLURI(url).pathArray(); + auto path_parts = path_array.size(); + + if (path_parts < 3) // no parcel id + { + LL_WARNS() << "Global coordinates are missing in url: [" << url << "]" << LL_ENDL; + return; + } + + LLVector3d parcel_pos = LLUrlEntryParcel::getParcelPos(LLUUID(LLURI::unescape(path_array[2]))); + std::ostringstream pos; + pos << parcel_pos.mdV[VX] << '/' << parcel_pos.mdV[VY] << '/' << parcel_pos.mdV[VZ]; + executeSLURL("secondlife:///app/worldmap_global/" + pos.str()); +} + void LLUrlAction::copyURLToClipboard(std::string url) { LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url)); @@ -142,6 +160,16 @@ void LLUrlAction::copyLabelToClipboard(std::string url) } } +std::string LLUrlAction::getURLLabel(std::string url) +{ + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + return match.getLabel(); + } + return ""; +} + void LLUrlAction::showProfile(std::string url) { // Get id from 'secondlife:///app/{cmd}/{id}/{action}' diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index ac9741a7ad..8b7ab0e7c5 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -63,6 +63,8 @@ public: /// if the Url specifies an SL location, show it on a map static void showLocationOnMap(std::string url); + static void showParcelOnMap(std::string url); + /// perform the appropriate action for left-clicking on a Url static void clickAction(std::string url, bool trusted_content); @@ -72,6 +74,8 @@ public: /// copy a Url to the clipboard static void copyURLToClipboard(std::string url); + static std::string getURLLabel(std::string url); + /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile static void showProfile(std::string url); static std::string getUserID(std::string url); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index bcd13b7f0b..95603d7ed5 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -41,8 +41,7 @@ #include "lluicolortable.h" #include "message.h" #include "llexperiencecache.h" - -#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" +#include "v3dmath.h" // Utility functions std::string localize_slapp_label(const std::string& url, const std::string& full_name); @@ -1084,6 +1083,7 @@ LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null); LLHost LLUrlEntryParcel::sRegionHost; bool LLUrlEntryParcel::sDisconnected(false); std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers; +std::map<LLUUID, LLVector3d> LLUrlEntryParcel::sParcelPos; /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., @@ -1176,6 +1176,20 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); } } + if (sParcelPos.find(parcel_data.parcel_id) == sParcelPos.end()) + { + sParcelPos[parcel_data.parcel_id] = LLVector3d(parcel_data.global_x, parcel_data.global_y, parcel_data.global_z); + } +} + +// static +LLVector3d LLUrlEntryParcel::getParcelPos(const LLUUID& parcel_id) +{ + if (sParcelPos.find(parcel_id) != sParcelPos.end()) + { + return sParcelPos[parcel_id]; + } + return LLVector3d(); } // diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 6e7d2fc80f..efb5081103 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -41,6 +41,9 @@ #include <map> class LLAvatarName; +class LLVector3d; + +#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" typedef boost::signals2::signal<void (const std::string& url, const std::string& label, @@ -434,6 +437,8 @@ public: // Processes parcel label and triggers notifying observers. static void processParcelInfo(const LLParcelData& parcel_data); + static LLVector3d getParcelPos(const LLUUID& parcel_id); + // Next setters are used to update agent and viewer connection information // upon events like user login, viewer disconnect and user changing region host. // These setters are made public to be accessible from newview and should not be @@ -447,6 +452,7 @@ private: static LLHost sRegionHost; static bool sDisconnected; static std::set<LLUrlEntryParcel*> sParcelInfoObservers; + static std::map<LLUUID, LLVector3d> sParcelPos; }; /// diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index 2ee6d912c1..b245774516 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -672,7 +672,10 @@ LLWebRTCPeerConnectionInterface *LLWebRTCImpl::newPeerConnection() peerConnection->init(this); mPeerConnections.emplace_back(peerConnection); - peerConnection->enableSenderTracks(!mMute); + // Should it really start disabled? + // Seems like something doesn't get the memo and senders need to be reset later + // to remove the voice indicator from taskbar + peerConnection->enableSenderTracks(false); if (mPeerConnections.empty()) { setRecording(true); @@ -706,7 +709,7 @@ void LLWebRTCImpl::freePeerConnection(LLWebRTCPeerConnectionInterface* peer_conn LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() : mWebRTCImpl(nullptr), mPeerConnection(nullptr), - mMute(true), + mMute(MUTE_INITIAL), mAnswerReceived(false) { } @@ -741,6 +744,19 @@ void LLWebRTCPeerConnectionImpl::terminate() } } + // to remove 'Secondlife is recording' icon from taskbar + // if user was speaking + auto senders = mPeerConnection->GetSenders(); + for (auto& sender : senders) + { + auto track = sender->track(); + if (track) + { + track->set_enabled(false); + } + } + mPeerConnection->SetAudioRecording(false); + mPeerConnection->Close(); if (mLocalStream) { @@ -830,6 +846,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti audioOptions.auto_gain_control = true; audioOptions.echo_cancellation = true; audioOptions.noise_suppression = true; + audioOptions.init_recording_on_send = false; mLocalStream = mPeerConnectionFactory->CreateLocalMediaStream("SLStream"); @@ -894,6 +911,7 @@ void LLWebRTCPeerConnectionImpl::enableSenderTracks(bool enable) { sender->track()->set_enabled(enable); } + mPeerConnection->SetAudioRecording(enable); } } @@ -934,9 +952,17 @@ void LLWebRTCPeerConnectionImpl::AnswerAvailable(const std::string &sdp) void LLWebRTCPeerConnectionImpl::setMute(bool mute) { - mMute = mute; + EMicMuteState new_state = mute ? MUTE_MUTED : MUTE_UNMUTED; + if (new_state == mMute) + { + return; // no change + } + bool force_reset = mMute == MUTE_INITIAL && mute; + bool enable = !mute; + mMute = new_state; + mWebRTCImpl->PostSignalingTask( - [this]() + [this, force_reset, enable]() { if (mPeerConnection) { @@ -948,16 +974,34 @@ void LLWebRTCPeerConnectionImpl::setMute(bool mute) auto track = sender->track(); if (track) { - track->set_enabled(!mMute); + if (force_reset) + { + // Force notify observers + // Was it disabled too early? + // Without this microphone icon in Win's taskbar will stay + track->set_enabled(true); + } + track->set_enabled(enable); } } + mPeerConnection->SetAudioRecording(enable); } }); } void LLWebRTCPeerConnectionImpl::resetMute() { - setMute(mMute); + switch(mMute) + { + case MUTE_MUTED: + setMute(true); + break; + case MUTE_UNMUTED: + setMute(false); + break; + default: + break; + } } void LLWebRTCPeerConnectionImpl::setReceiveVolume(float volume) diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 99accb2c20..dfdb19e9be 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -425,7 +425,12 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory; - bool mMute; + typedef enum { + MUTE_INITIAL, + MUTE_MUTED, + MUTE_UNMUTED, + } EMicMuteState; + EMicMuteState mMute; // signaling std::vector<LLWebRTCSignalingObserver *> mSignalingObserverList; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 8960519bc2..2656f21def 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -76,6 +76,11 @@ #pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems #pragma comment(lib, "dinput8") +#pragma comment(lib, "UxTheme.lib") +#pragma comment(lib, "Dwmapi.lib") +#include <Uxtheme.h> +#include <dwmapi.h> // needed for DwmSetWindowAttribute to set window theme + const S32 MAX_MESSAGE_PER_UPDATE = 20; const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; @@ -85,6 +90,10 @@ const F32 ICON_FLASH_TIME = 0.5f; #define USER_DEFAULT_SCREEN_DPI 96 // Win7 #endif +#ifndef WM_DWMCOLORIZATIONCOLORCHANGED +#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 +#endif + // Claim a couple unused GetMessage() message IDs const UINT WM_DUMMY_(WM_USER + 0x0017); const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); @@ -104,6 +113,7 @@ static std::thread::id sMainThreadId; LPWSTR gIconResource = IDI_APPLICATION; +LPWSTR gIconSmallResource = IDI_APPLICATION; LPDIRECTINPUT8 gDirectInput8; LLW32MsgCallback gAsyncMsgCallback = NULL; @@ -137,6 +147,17 @@ typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( _Out_ UINT *dpiX, _Out_ UINT *dpiY); +typedef enum PREFERRED_APP_MODE +{ + DEFAULT, + ALLOW_DARK, + FORCE_DARK, + FORCE_LIGHT, + MAX +} PREFERRED_APP_MODE; + +typedef PREFERRED_APP_MODE(WINAPI* fnSetPreferredAppMode)(PREFERRED_APP_MODE mode); + // // LLWindowWin32 // @@ -512,6 +533,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mFSAASamples = fsaa_samples; mIconResource = gIconResource; + mIconSmallResource = gIconSmallResource; mOverrideAspectRatio = 0.f; mNativeAspectRatio = 0.f; mInputProcessingPaused = false; @@ -846,6 +868,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Initialize (boot strap) the Language text input management, // based on the system's (or user's) default settings. allowLanguageTextInput(NULL, false); + updateWindowTheme(); + setCustomIcon(); } @@ -3020,6 +3044,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ WINDOW_IMP_POST(window_imp->mMouseVanish = true); } } + // Check if theme-related settings changed + else if (l_param && (wcscmp((LPCWSTR)l_param, L"ImmersiveColorSet") == 0)) + { + WINDOW_IMP_POST(window_imp->updateWindowTheme()); + } + } + break; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + { + WINDOW_IMP_POST(window_imp->updateWindowTheme()); } break; @@ -4962,3 +4997,69 @@ void LLWindowWin32::updateWindowRect() }); } } + +bool LLWindowWin32::isSystemAppDarkMode() +{ + HKEY hKey; + DWORD dwValue = 1; // Default to light theme + DWORD dwSize = sizeof(DWORD); + + // Check registry for system theme preference + LSTATUS ret_code = + RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey); + if (ERROR_SUCCESS == ret_code) + { + if (RegQueryValueExW(hKey, L"AppsUseLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS) + { + // If AppsUseLightTheme is not found, check SystemUsesLightTheme + dwSize = sizeof(DWORD); + RegQueryValueExW(hKey, L"SystemUsesLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize); + } + RegCloseKey(hKey); + } + + // Return true if dark mode + return dwValue == 0; +} + +void LLWindowWin32::updateWindowTheme() +{ + bool use_dark_mode = isSystemAppDarkMode(); + if (use_dark_mode == mCurrentDarkMode) + { + return; + } + mCurrentDarkMode = use_dark_mode; + + HMODULE hUxTheme = LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (hUxTheme) + { + auto SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxTheme, "SetPreferredAppMode"); + if (SetPreferredAppMode) + { + SetPreferredAppMode(use_dark_mode ? ALLOW_DARK : FORCE_LIGHT); + } + FreeLibrary(hUxTheme); + } + BOOL dark_mode(use_dark_mode); + DwmSetWindowAttribute(mWindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark_mode, sizeof(dark_mode)); + + LL_INFOS("Window") << "Viewer window theme is set to " << (use_dark_mode ? "dark" : "light") << " mode" << LL_ENDL; +} + +void LLWindowWin32::setCustomIcon() +{ + if (mWindowHandle) + { + HICON hDefaultIcon = LoadIcon(mhInstance, mIconResource); + HICON hSmallIcon = LoadIcon(mhInstance, mIconSmallResource); + mWindowThread->post([=]() + { + SendMessage(mWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hDefaultIcon); + SendMessage(mWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon); + + SetClassLongPtr(mWindowHandle, GCLP_HICON, (LONG_PTR)hDefaultIcon); + SetClassLongPtr(mWindowHandle, GCLP_HICONSM, (LONG_PTR)hSmallIcon); + }); + } +} diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 561f07d388..7196706f87 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -214,6 +214,7 @@ protected: bool mCustomGammaSet; LPWSTR mIconResource; + LPWSTR mIconSmallResource; bool mInputProcessingPaused; // The following variables are for Language Text Input control. @@ -246,6 +247,11 @@ protected: RECT mRect; RECT mClientRect; + void updateWindowTheme(); + bool isSystemAppDarkMode(); + void setCustomIcon(); + bool mCurrentDarkMode { false }; + struct LLWindowWin32Thread; LLWindowWin32Thread* mWindowThread = nullptr; LLThreadSafeQueue<std::function<void()>> mFunctionQueue; @@ -281,6 +287,7 @@ private: extern LLW32MsgCallback gAsyncMsgCallback; extern LPWSTR gIconResource; +extern LPWSTR gIconSmallResource; S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 019d656471..9b30902de9 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1605,6 +1605,7 @@ if (WINDOWS) res-sdl/ll_icon.BMP res/ll_icon.BMP res/ll_icon.ico + res/ll_icon_small.ico res/resource.h res/toolpickobject.cur res/toolpickobject2.cur @@ -1913,6 +1914,12 @@ if (WINDOWS) ) endif (ADDRESS_SIZE EQUAL 64) + if (TARGET ll::discord_sdk) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/discord_partner_sdk.dll + ) + endif () + if (TARGET ll::openal) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/OpenAL32.dll @@ -1929,6 +1936,7 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" "--openal=${USE_OPENAL}" "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} @@ -1967,6 +1975,7 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" "--openal=${USE_OPENAL}" "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} @@ -2044,6 +2053,7 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" "--openal=${USE_OPENAL}" "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} @@ -2151,7 +2161,7 @@ if (ENABLE_MEDIA_PLUGINS) endif () if (USE_DISCORD) - target_link_libraries(${VIEWER_BINARY_NAME} ll::discord ) + target_link_libraries(${VIEWER_BINARY_NAME} ll::discord_sdk ) endif () if( TARGET ll::intel_memops ) @@ -2269,6 +2279,7 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" "--openal=${USE_OPENAL}" "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} @@ -2351,6 +2362,7 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" "--openal=${USE_OPENAL}" "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} @@ -2453,6 +2465,7 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" "--openal=${USE_OPENAL}" "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} @@ -2507,6 +2520,7 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" "--openal=${USE_OPENAL}" "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ff9f2b96a7..2b26eb105e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1219,13 +1219,13 @@ <key>DiskCachePercentOfTotal</key> <map> <key>Comment</key> - <string>The percent of total cache size (defined by CacheSize) to use for the disk cache</string> + <string>The percent of total cache size (defined by CacheSize) to use for the disk cache (ex: asset storage, excludes textures)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>F32</string> <key>Value</key> - <real>40.0</real> + <real>35.0</real> </map> <key>DiskCacheDirName</key> <map> @@ -1269,7 +1269,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>4096</integer> + <integer>6144</integer> </map> <key>CacheValidateCounter</key> <map> @@ -9716,6 +9716,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>ObscureBalanceInStatusBar</key> + <map> + <key>Comment</key> + <string>If true, balance will be shows as '*'</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>RenderUIBuffer</key> <map> <key>Comment</key> @@ -13940,7 +13951,7 @@ <key>FullScreen</key> <map> <key>Comment</key> - <string>run a fullscreen session</string> + <string>Run a fullscreen session. MacOS not supported</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -16837,5 +16848,49 @@ <key>Value</key> <integer>31</integer> </map> + <key>EnableSelectionHints</key> + <map> + <key>Comment</key> + <string>Whether or not to send editing hints to animate the arm when editing an object.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>EnableLookAtTarget</key> + <map> + <key>Comment</key> + <string>Whether or not to animate the avatar head and send look at targets when moving the cursor or focusing on objects</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>LimitLookAtTarget</key> + <map> + <key>Comment</key> + <string>Whether or not to clamp the look at targets around the avatar head before sending</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>LimitLookAtTargetDistance</key> + <map> + <key>Comment</key> + <string>Distance to limit look at target to</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>2</integer> + </map> </map> </llsd> diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 5211884bc2..93cc4941f1 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 4050bda024..71dec10e01 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/llappviewer.cpp b/indra/newview/llappviewer.cpp index 53a3978086..32f4421ce2 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3178,7 +3178,15 @@ bool LLAppViewer::initWindow() .height(gSavedSettings.getU32("WindowHeight")) .min_width(gSavedSettings.getU32("MinWindowWidth")) .min_height(gSavedSettings.getU32("MinWindowHeight")) +#ifdef LL_DARWIN + // Setting it to true causes black screen with no UI displayed. + // Given that it's a DEBUG settings and application goes fullscreen + // on mac simply by expanding it, it was decided to not support/use + // this setting on mac. + .fullscreen(false) +#else // LL_DARWIN .fullscreen(gSavedSettings.getBOOL("FullScreen")) +#endif .ignore_pixel_depth(ignorePixelDepth) .first_run(mIsFirstRun); @@ -4365,8 +4373,8 @@ bool LLAppViewer::initCache() const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); const U32 MB = 1024 * 1024; - const uintmax_t MIN_CACHE_SIZE = 256 * MB; - const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; + const uintmax_t MIN_CACHE_SIZE = 896 * MB; + const uintmax_t MAX_CACHE_SIZE = 32768ll * MB; const uintmax_t setting_cache_total_size = uintmax_t(gSavedSettings.getU32("CacheSize")) * MB; const uintmax_t cache_total_size = llclamp(setting_cache_total_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index f3214e2a20..d5cce28a3d 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -460,6 +460,7 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, // *FIX: global gIconResource = MAKEINTRESOURCE(IDI_LL_ICON); #endif + gIconSmallResource = MAKEINTRESOURCE(IDI_LL_ICON_SMALL); LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(ll_convert_wide_to_string(pCmdLine).c_str()); diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index af5a46742c..774e8fd4c5 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -300,7 +300,7 @@ void LLConversationItemSession::updateName(LLConversationItemParticipant* partic for (auto itemp : mChildren) { - LLConversationItem* current_participant = dynamic_cast<LLConversationItem*>(itemp); + LLConversationItem* current_participant = dynamic_cast<LLConversationItem*>(itemp.get()); // Add the avatar uuid to the list (except if it's the own agent uuid) if (current_participant->getUUID() != gAgentID) { @@ -329,6 +329,7 @@ void LLConversationItemSession::updateName(LLConversationItemParticipant* partic void LLConversationItemSession::removeParticipant(LLConversationItemParticipant* participant) { + LLPointer<LLFolderViewModelItem> holder(participant); removeChild(participant); mNeedsRefresh = true; updateName(participant); @@ -360,15 +361,10 @@ void LLConversationItemSession::clearAndDeparentModels() for (child_list_t::iterator it = mChildren.begin(); it != mChildren.end();) { LLFolderViewModelItem* child = *it; - if (child->getNumRefs() == 0) + // Note that model might still be assigned to some view/widget + // and have a different parent + if (child->getParent() == this) { - // LLConversationItemParticipant can be created but not assigned to any view, - // it was waiting for an "add_participant" event to be processed - delete child; - } - else - { - // Model is still assigned to some view/widget child->setParent(NULL); } it = mChildren.erase(it); @@ -383,7 +379,7 @@ LLConversationItemParticipant* LLConversationItemSession::findParticipant(const child_list_t::iterator iter; for (iter = mChildren.begin(); iter != mChildren.end(); iter++) { - participant = dynamic_cast<LLConversationItemParticipant*>(*iter); + participant = dynamic_cast<LLConversationItemParticipant*>((*iter).get()); if (participant && participant->hasSameValue(participant_id)) { break; @@ -493,7 +489,7 @@ const bool LLConversationItemSession::getTime(F64& time) const child_list_t::const_iterator iter; for (iter = mChildren.begin(); iter != mChildren.end(); iter++) { - participant = dynamic_cast<LLConversationItemParticipant*>(*iter); + participant = dynamic_cast<LLConversationItemParticipant*>((*iter).get()); F64 participant_time; if (participant && participant->getTime(participant_time)) { @@ -517,7 +513,7 @@ void LLConversationItemSession::dumpDebugData(bool dump_children) { for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); iter++) { - LLConversationItemParticipant* participant = dynamic_cast<LLConversationItemParticipant*>(*iter); + LLConversationItemParticipant* participant = dynamic_cast<LLConversationItemParticipant*>((*iter).get()); if (participant) { participant->dumpDebugData(); diff --git a/indra/newview/llfloaterchatmentionpicker.cpp b/indra/newview/llfloaterchatmentionpicker.cpp index 1cfed122a9..a3eb286375 100644 --- a/indra/newview/llfloaterchatmentionpicker.cpp +++ b/indra/newview/llfloaterchatmentionpicker.cpp @@ -88,7 +88,7 @@ uuid_vec_t LLFloaterChatMentionPicker::getParticipantIds() LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); + LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>((*current_participant_model).get()); if (participant_model) { avatar_ids.push_back(participant_model->getUUID()); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index f254fdafaf..42a5df5d17 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -32,6 +32,7 @@ #include "llimagetga.h" #include "llimagejpeg.h" #include "llimagepng.h" +#include "llimagej2c.h" #include "llagent.h" #include "llagentbenefits.h" @@ -43,6 +44,10 @@ #include "llrender.h" #include "llface.h" #include "llfocusmgr.h" +#include "llfilesystem.h" +#include "llfloaterperms.h" +#include "llnotificationsutil.h" +#include "llstatusbar.h" // can_afford_transaction() #include "lltextbox.h" #include "lltoolmgr.h" #include "llui.h" @@ -52,6 +57,7 @@ #include "llvoavatar.h" #include "pipeline.h" #include "lluictrlfactory.h" +#include "llviewermenufile.h" // upload_new_resource() #include "llviewershadermgr.h" #include "llviewertexturelist.h" #include "llstring.h" @@ -140,7 +146,7 @@ bool LLFloaterImagePreview::postBuild() } } - getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this)); + getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterImagePreview::onBtnOK, this)); return true; } @@ -244,6 +250,59 @@ void LLFloaterImagePreview::clearAllPreviewTextures() } //----------------------------------------------------------------------------- +// onBtnOK() +//----------------------------------------------------------------------------- +void LLFloaterImagePreview::onBtnOK() +{ + getChildView("ok_btn")->setEnabled(false); // don't allow inadvertent extra uploads + + S32 expected_upload_cost = getExpectedUploadCost(); + if (can_afford_transaction(expected_upload_cost)) + { + LL_INFOS() << "saving texture: " << mRawImagep->getWidth() << "x" << mRawImagep->getHeight() << LL_ENDL; + // gen a new uuid for this asset + LLTransactionID tid; + tid.generate(); + LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLPointer<LLImageJ2C> formatted = new LLImageJ2C; + + if (formatted->encode(mRawImagep, 0.0f)) + { + LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE); + fmt_file.write(formatted->getData(), formatted->getDataSize()); + + LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo( + tid, LLAssetType::AT_TEXTURE, + getChild<LLUICtrl>("name_form")->getValue().asString(), + getChild<LLUICtrl>("description_form")->getValue().asString(), + 0, + LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost + )); + + upload_new_resource(assetUploadInfo); + } + else + { + LLNotificationsUtil::add("ErrorEncodingImage"); + LL_WARNS() << "Error encoding image" << LL_ENDL; + } + } + else + { + LLSD args; + args["COST"] = llformat("%d", expected_upload_cost); + LLNotificationsUtil::add("ErrorCannotAffordUpload", args); + } + + closeFloater(false); +} + +//----------------------------------------------------------------------------- // draw() //----------------------------------------------------------------------------- void LLFloaterImagePreview::draw() @@ -364,19 +423,6 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) return false; } - S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); - S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); - - if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) - { - LLStringUtil::format_map_t args; - args["WIDTH"] = llformat("%d", max_width); - args["HEIGHT"] = llformat("%d", max_height); - - mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); - return false; - } - // Load the image LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); if (image.isNull()) @@ -399,6 +445,46 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) image->setLastError("Image files with less than 3 or more than 4 components are not supported."); return false; } + // Downscale images to fit the max_texture_dimensions_* + S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); + S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); + + S32 orig_width = raw_image->getWidth(); + S32 orig_height = raw_image->getHeight(); + + if (orig_width > max_width || orig_height > max_height) + { + // Calculate scale factors + F32 width_scale = (F32)max_width / (F32)orig_width; + F32 height_scale = (F32)max_height / (F32)orig_height; + F32 scale = llmin(width_scale, height_scale); + + // Calculate new dimensions, preserving aspect ratio + S32 new_width = LLImageRaw::contractDimToPowerOfTwo( + llclamp((S32)llroundf(orig_width * scale), 4, max_width) + ); + S32 new_height = LLImageRaw::contractDimToPowerOfTwo( + llclamp((S32)llroundf(orig_height * scale), 4, max_height) + ); + + if (!raw_image->scale(new_width, new_height)) + { + LL_WARNS() << "Failed to scale image from " + << orig_width << "x" << orig_height + << " to " << new_width << "x" << new_height << LL_ENDL; + return false; + } + + // Inform the resident about the resized image + LLSD subs; + subs["[ORIGINAL_WIDTH]"] = orig_width; + subs["[ORIGINAL_HEIGHT]"] = orig_height; + subs["[NEW_WIDTH]"] = new_width; + subs["[NEW_HEIGHT]"] = new_height; + subs["[MAX_WIDTH]"] = max_width; + subs["[MAX_HEIGHT]"] = max_height; + LLNotificationsUtil::add("ImageUploadResized", subs); + } raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); mRawImagep = raw_image; diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h index 9bc57246cf..5e5f4932c2 100644 --- a/indra/newview/llfloaterimagepreview.h +++ b/indra/newview/llfloaterimagepreview.h @@ -126,6 +126,8 @@ public: void clearAllPreviewTextures(); + void onBtnOK(); + protected: static void onPreviewTypeCommit(LLUICtrl*,void*); void draw() override; diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 59ae8a9a81..bff0457a7d 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -460,7 +460,7 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate() LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = session_model->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); + LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>((*current_participant_model).get()); if (participant_model) { // Get the avatar name for this participant id from the cache and update the model @@ -511,7 +511,7 @@ void LLFloaterIMContainer::idleUpdate() bool can_ban = haveAbilityToBan(); while (current_participant_model != end_participant_model) { - LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); + LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>((*current_participant_model).get()); if (participant_model) { participant_model->setModeratorOptionsVisible(is_moderator); @@ -1882,7 +1882,7 @@ LLConversationItem* LLFloaterIMContainer::addConversationListItem(const LLUUID& LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); + LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>((*current_participant_model).get()); LLConversationViewParticipant* participant_view = createConversationViewParticipant(participant_model); participant_view->addToFolder(widget); current_participant_model++; diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 733e178de3..5160ac4d34 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -107,26 +107,6 @@ LLFloaterIMSessionTab::~LLFloaterIMSessionTab() delete mRefreshTimer; LLIMMgr::instance().removeSessionObserver(this); mEmojiCloseConn.disconnect(); - - LLFloaterIMContainer* im_container = LLFloaterIMContainer::findInstance(); - if (im_container) - { - LLParticipantList* session = dynamic_cast<LLParticipantList*>(im_container->getSessionModel(mSessionID)); - if (session) - { - for (const conversations_widgets_map::value_type& widget_pair : mConversationsWidgets) - { - LLFolderViewItem* widget = widget_pair.second; - LLFolderViewModelItem* item_vmi = widget->getViewModelItem(); - if (item_vmi && item_vmi->getNumRefs() == 1) - { - // This is the last pointer, remove participant from session - // before participant gets deleted on destroyView. - session->removeChild(item_vmi); - } - } - } - } } // static @@ -731,7 +711,7 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant() LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); + LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>((*current_participant_model).get()); if (participant_model) { addConversationViewParticipant(participant_model); @@ -775,27 +755,6 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id); if (widget) { - LLFolderViewModelItem* item_vmi = widget->getViewModelItem(); - if (item_vmi && item_vmi->getNumRefs() == 1) - { - // This is the last pointer, remove participant from session - // before participant gets deleted on destroyView. - // - // Floater (widget) and participant's view can simultaneously - // co-own the model, in which case view is responsible for - // the deletion and floater is free to clear and recreate - // the list, yet there are cases where only widget owns - // the pointer so it should do the cleanup. - // See "add_participant". - // - // Todo: If it keeps causing issues turn participants - // into LLPointers in the session - LLParticipantList* session = getParticipantList(); - if (session) - { - session->removeChild(item_vmi); - } - } widget->destroyView(); } mConversationsWidgets.erase(participant_id); @@ -861,7 +820,7 @@ void LLFloaterIMSessionTab::refreshConversation() LLIMSpeakerMgr *speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); while (current_participant_model != end_participant_model) { - LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); + LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>((*current_participant_model).get()); if (speaker_mgr && participant_model) { LLSpeaker *participant_speaker = speaker_mgr->findSpeaker(participant_model->getUUID()); diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp index 2496887c9d..81eab52e6c 100644 --- a/indra/newview/llfloatermediasettings.cpp +++ b/indra/newview/llfloatermediasettings.cpp @@ -180,8 +180,15 @@ void LLFloaterMediaSettings::onClose(bool app_quitting) //////////////////////////////////////////////////////////////////////////////// //static -void LLFloaterMediaSettings::initValues( const LLSD& media_settings, bool editable ) +void LLFloaterMediaSettings::initValues( const LLSD& media_settings, bool editable, bool has_media_info, bool multiple_media, bool multiple_valid_media) { + if (!sInstance) + { + return; + } + sInstance->mIdenticalHasMediaInfo = has_media_info; + sInstance->mMultipleMedia = multiple_media; + sInstance->mMultipleValidMedia = multiple_valid_media; if (sInstance->hasFocus()) return; // Clear values diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h index 38730ddc98..7ed7ab246f 100644 --- a/indra/newview/llfloatermediasettings.h +++ b/indra/newview/llfloatermediasettings.h @@ -48,7 +48,7 @@ public: static LLFloaterMediaSettings* getInstance(); static bool instanceExists(); static void apply(); - static void initValues( const LLSD& media_settings , bool editable); + static void initValues( const LLSD& media_settings , bool editable, bool has_media_info, bool multiple_media, bool multiple_valid_media); static void clearValues( bool editable); LLPanelMediaSettingsSecurity* getPanelSecurity(){return mPanelMediaSettingsSecurity;}; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 234885eba7..6a6766fb3f 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -165,7 +165,7 @@ bool LLFloaterModelPreview::postBuild() for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) { LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]); - lod_source_combo->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLoDSourceCommit, this, lod, true)); + lod_source_combo->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLoDSourceCommit, this, lod)); lod_source_combo->setCurrentByIndex(mLODMode[lod]); getChild<LLButton>("lod_browse_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onBrowseLOD, this, lod)); @@ -766,7 +766,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[i]); if (lod_source_combo->getCurrentIndex() == LLModelPreview::USE_LOD_ABOVE) { - onLoDSourceCommit(i, false); + onLoDSourceCommit(i); } else { @@ -1760,7 +1760,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) } } -void LLFloaterModelPreview::onLoDSourceCommit(S32 lod, bool refresh_ui) +void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) { mModelPreview->updateLodControls(lod); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index f8f2cd7812..7b652a3613 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -206,7 +206,7 @@ private: void onClickCalculateBtn(); void onJointListSelection(); - void onLoDSourceCommit(S32 lod, bool refresh_ui); + void onLoDSourceCommit(S32 lod); void modelUpdated(bool calculate_visible); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 36a68a7017..dc5346634e 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -528,6 +528,10 @@ bool LLFloaterPreference::postBuild() getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); } +#ifndef LL_DISCORD + getChild<LLTabContainer>("privacy_tab_container")->childDisable("privacy_preferences_discord"); +#endif + return true; } diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 8cc01f6dc6..01108b5cfa 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -207,14 +207,14 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) mSettingNameText->setToolTip(controlp->getName()); mComment->setVisible(true); - std::string old_text = mComment->getText(); std::string new_text = controlp->getComment(); // Don't setText if not nessesary, it will reset scroll // This is a debug UI that reads from xml, there might // be use cases where comment changes, but not the name - if (old_text != new_text) + if (mOldText != new_text) { mComment->setText(controlp->getComment()); + mOldText = new_text; } mValSpinner1->setMaxValue(F32_MAX); @@ -467,6 +467,7 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) } default: mComment->setText(std::string("unknown")); + mOldText = "unknown"; break; } } diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index b813cf4a74..8781cd3b67 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -82,6 +82,7 @@ protected: LLColorSwatchCtrl* mColorSwatch = nullptr; std::string mSearchFilter; + std::string mOldText; }; #endif //LLFLOATERDEBUGSETTINGS_H diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 6e6eaa3a20..03979edbc1 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -169,6 +169,52 @@ public: }; LLWorldMapHandler gWorldMapHandler; +// handle secondlife:///app/worldmap_global/{GLOBAL_COORDS} URLs +class LLWorldMapGlobalHandler : public LLCommandHandler +{ +public: + LLWorldMapGlobalHandler() : LLCommandHandler("worldmap_global", UNTRUSTED_THROTTLE) + {} + + virtual bool canHandleUntrusted( + const LLSD& params, + const LLSD& query_map, + LLMediaCtrl* web, + const std::string& nav_type) + { + if (nav_type == NAV_TYPE_CLICKED + || nav_type == NAV_TYPE_EXTERNAL) + { + // NAV_TYPE_EXTERNAL will be throttled + return true; + } + + return false; + } + + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) + { + if (params.size() < 3) + { + LL_WARNS() << "Correct global coordinates are not provided." << LL_ENDL; + return true; + } + + LLVector3d parcel_global_pos = LLVector3d(params[0].asInteger(), params[1].asInteger(), params[2].asInteger()); + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if (!parcel_global_pos.isExactlyZero() && worldmap_instance) + { + worldmap_instance->trackLocation(parcel_global_pos); + LLFloaterReg::showInstance("world_map", "center"); + } + return true; + } +}; +LLWorldMapGlobalHandler gWorldMapGlobalHandler; + // SocialMap handler secondlife:///app/maptrackavatar/id class LLMapTrackAvatarHandler : public LLCommandHandler { diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index d0d2ee191a..776d2dd31e 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -37,6 +37,7 @@ #include "lldrawable.h" #include "llviewerobjectlist.h" #include "llviewercontrol.h" +#include "llvoavatarself.h" #include "llrendersphere.h" #include "llselectmgr.h" #include "llglheaders.h" @@ -397,6 +398,21 @@ bool LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *objec return false; } + static LLCachedControl<bool> enable_lookat_hints(gSavedSettings, "EnableLookAtTarget", true); + if (!enable_lookat_hints) + { + // Clear the effect so it doesn't linger around if it gets disabled + if (mTargetType != LOOKAT_TARGET_IDLE) + { + mTargetObject = gAgentAvatarp; + mTargetType = LOOKAT_TARGET_IDLE; + mTargetOffsetGlobal.set(2.f, 0.f, 0.f); + setDuration(3.f); + setNeedsSendToSim(true); + } + return false; + } + if (target_type >= LOOKAT_NUM_TARGETS) { LL_WARNS() << "Bad target_type " << (int)target_type << " - ignoring." << LL_ENDL; @@ -409,6 +425,29 @@ bool LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *objec return false; } + static LLCachedControl<bool> limit_lookat_hints(gSavedSettings, "LimitLookAtTarget", true); + // Don't affect the look at if object is gAgentAvatarp (cursor head follow) + if (limit_lookat_hints && object != gAgentAvatarp) + { + // If it is a object + if (object) + { + position += object->getRenderPosition(); + object = NULL; + } + + LLVector3 agentHeadPosition = gAgentAvatarp->mHeadp->getWorldPosition(); + float dist = (float)dist_vec(agentHeadPosition, position); + + static LLCachedControl<F32> limit_lookat_hints_distance(gSavedSettings, "LimitLookAtTargetDistance", 2.0f); + if (dist > limit_lookat_hints_distance) + { + LLVector3 headOffset = position - agentHeadPosition; + headOffset *= limit_lookat_hints_distance / dist; + position.setVec(agentHeadPosition + headOffset); + } + } + F32 current_time = mTimer.getElapsedTimeF32(); // type of lookat behavior or target object has changed diff --git a/indra/newview/llhudeffectpointat.cpp b/indra/newview/llhudeffectpointat.cpp index eeb38cd6aa..c600010f6b 100644 --- a/indra/newview/llhudeffectpointat.cpp +++ b/indra/newview/llhudeffectpointat.cpp @@ -34,6 +34,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "lldrawable.h" +#include "llviewercontrol.h" #include "llviewerobjectlist.h" #include "llvoavatar.h" #include "message.h" @@ -226,6 +227,19 @@ bool LLHUDEffectPointAt::setPointAt(EPointAtType target_type, LLViewerObject *ob return false; } + static LLCachedControl<bool> enable_selection_hints(gSavedSettings, "EnableSelectionHints", true); + if (!enable_selection_hints) + { + // Clear the effect so it doesn't linger around if it gets disabled + if (mTargetType != POINTAT_TARGET_NONE) + { + clearPointAtTarget(); + setDuration(1.f); + setNeedsSendToSim(true); + } + return false; + } + if (target_type >= POINTAT_NUM_TARGETS) { LL_WARNS() << "Bad target_type " << (int)target_type << " - ignoring." << LL_ENDL; 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/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index edefb5d109..359a009fef 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4555,6 +4555,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.push_back(std::string("Rename")); items.push_back(std::string("thumbnail")); + addInventoryFavoritesMenuOptions(items); addDeleteContextMenuOptions(items, disabled_items); // EXT-4030: disallow deletion of currently worn outfit const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); @@ -4572,6 +4573,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items EMyOutfitsSubfolderType in_my_outfits = myoutfit_object_subfolder_type(model, mUUID, outfits_id); if (in_my_outfits != MY_OUTFITS_NO) { + // Either an outfit or a subfolder inside MY_OUTFITS if (in_my_outfits == MY_OUTFITS_SUBFOLDER) { // Not inside an outfit, but inside 'my outfits' @@ -4581,6 +4583,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.push_back(std::string("Rename")); items.push_back(std::string("thumbnail")); + addInventoryFavoritesMenuOptions(items); addDeleteContextMenuOptions(items, disabled_items); } else @@ -4629,14 +4632,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID) { items.push_back(std::string("Copy outfit list to clipboard")); - if (isFavorite()) - { - items.push_back(std::string("Remove from Favorites")); - } - else - { - items.push_back(std::string("Add to Favorites")); - } + addInventoryFavoritesMenuOptions(items); addOpenFolderMenuOptions(flags, items); } @@ -4898,6 +4894,18 @@ void LLFolderBridge::addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items) } } +void LLFolderBridge::addInventoryFavoritesMenuOptions(menuentry_vec_t& items) +{ + if (isFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else + { + items.push_back(std::string("Add to Favorites")); + } +} + bool LLFolderBridge::hasChildren() const { LLInventoryModel* model = getInventoryModel(); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index ea80b6959a..d96adbd1d2 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -345,6 +345,7 @@ protected: void buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items); void buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items); void addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items); + void addInventoryFavoritesMenuOptions(menuentry_vec_t& items); // Inventory favorites, not toolbar favorites //-------------------------------------------------------------------- // Menu callbacks diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index a3e4f6a65d..d1fd82a7f1 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -3998,15 +3998,17 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) for (; set_iter != selected_items.end(); ++set_iter) { viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*set_iter)->getViewModelItem()); - if (!viewModel || !viewModel->getInventoryObject()) continue; - if (gInventory.isObjectDescendentOf(viewModel->getInventoryObject()->getParentUUID(), marketplacelistings_id)) + if (!viewModel) continue; + LLInventoryObject* inv_obj = viewModel->getInventoryObject(); + if (!inv_obj) continue; + if (gInventory.isObjectDescendentOf(inv_obj->getParentUUID(), marketplacelistings_id)) { - const LLUUID &parent_id = viewModel->getInventoryObject()->getParentUUID(); + const LLUUID &parent_id = inv_obj->getParentUUID(); if (parent_id != marketplacelistings_id) { sMarketplaceFolders.push_back(parent_id); } - const LLUUID &curr_id = viewModel->getInventoryObject()->getUUID(); + const LLUUID &curr_id = inv_obj->getUUID(); if (curr_id != marketplacelistings_id) { sMarketplaceFolders.push_back(curr_id); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index d419f67d47..943f41b6a7 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -78,7 +78,7 @@ // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect. -const S32 LLInventoryModel::sCurrentInvCacheVersion = 4; +const S32 LLInventoryModel::sCurrentInvCacheVersion = 5; bool LLInventoryModel::sFirstTimeInViewer2 = true; S32 LLInventoryModel::sPendingSystemFolders = 0; @@ -3384,7 +3384,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; - llifstream file(filename.c_str()); + llifstream file(filename.c_str(), std::ifstream::in | std::ifstream::binary); if (!file.is_open()) { @@ -3393,80 +3393,92 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } is_cache_obsolete = true; // Obsolete until proven current - - //U64 lines_count = 0U; - std::string line; - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - while (std::getline(file, line)) + U32 value_nbo = 0; + file.read((char*)&value_nbo, sizeof(U32)); + if (file.fail()) + { + LL_WARNS(LOG_INV) << "Failed to read cache version. Unable to load inventory from: " << filename << LL_ENDL; + } + else { - LLSD s_item; - std::istringstream iss(line); - if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + S32 version = (S32)ntohl(value_nbo); + if (version == sCurrentInvCacheVersion) { - LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; - break; + // Cache is up to date + is_cache_obsolete = false; } - - if (s_item.has("inv_cache_version")) + else { - S32 version = s_item["inv_cache_version"].asInteger(); - if (version == sCurrentInvCacheVersion) - { - // Cache is up to date - is_cache_obsolete = false; - continue; - } - else - { - LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; - break; - } + LL_WARNS(LOG_INV) << "Inventory cache is out of date" << LL_ENDL; } - else if (s_item.has("cat_id")) + } + + LLSD inventory; + if (!is_cache_obsolete) + { + LLPointer<LLSDParser> parser = new LLSDBinaryParser(); + + if (parser->parse(file, inventory, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) { - if (is_cache_obsolete) - break; + is_cache_obsolete = true; + LL_WARNS(LOG_INV) << "Parsing inventory cache failed" << LL_ENDL; + } + } - LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if(inv_cat->importLLSD(s_item)) + if (!is_cache_obsolete) + { + const LLSD& llsd_cats = inventory["categories"]; + if (llsd_cats.isArray()) + { + LLSD::array_const_iterator iter = llsd_cats.beginArray(); + LLSD::array_const_iterator end = llsd_cats.endArray(); + for (; iter != end; ++iter) { - categories.push_back(inv_cat); + LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null); + if (inv_cat->importLLSDMap(*iter)) + { + categories.push_back(inv_cat); + } } } - else if (s_item.has("item_id")) - { - if (is_cache_obsolete) - break; - LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem; - if( inv_item->fromLLSD(s_item) ) + const LLSD& llsd_items = inventory["items"]; + if (llsd_items.isArray()) + { + LLSD::array_const_iterator iter = llsd_items.beginArray(); + LLSD::array_const_iterator end = llsd_items.endArray(); + for (; iter != end; ++iter) { - if(inv_item->getUUID().isNull()) - { - LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; - } - else + LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem; + if (inv_item->fromLLSD(*iter)) { - if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + if (inv_item->getUUID().isNull()) { - cats_to_update.insert(inv_item->getParentUUID()); + LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " + << inv_item->getName() << LL_ENDL; } else { - items.push_back(inv_item); + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } } } + + // TODO(brad) - figure out how to reenable this without breaking everything else + // static constexpr U64 BATCH_SIZE = 512U; + // if ((++lines_count % BATCH_SIZE) == 0) + // { + // // SL-19968 - make sure message system code gets a chance to run every so often + // pump_idle_startup_network(); + // } } } - -// TODO(brad) - figure out how to reenable this without breaking everything else -// static constexpr U64 BATCH_SIZE = 512U; -// if ((++lines_count % BATCH_SIZE) == 0) -// { -// // SL-19968 - make sure message system code gets a chance to run every so often -// pump_idle_startup_network(); -// } } file.close(); @@ -3489,58 +3501,54 @@ bool LLInventoryModel::saveToFile(const std::string& filename, try { - llofstream fileXML(filename.c_str()); - if (!fileXML.is_open()) + llofstream fileSD(filename.c_str(), std::ios_base::out | std::ios_base::binary); + if (!fileSD.is_open()) { LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL; return false; } - - LLSD cache_ver; - cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; - - if (fileXML.fail()) + U32 value_nbo = htonl(sCurrentInvCacheVersion); + fileSD.write((const char*)(&value_nbo), sizeof(U32)); + if (fileSD.fail()) { - LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL; + LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL; return false; } - fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl; + LLSD inventory; + inventory["categories"] = LLSD::emptyArray(); + LLSD& cat_array = inventory["categories"]; S32 cat_count = 0; for (auto& cat : categories) { if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { - LLSD sd = LLSD::emptyMap(); + LLSD sd; cat->exportLLSD(sd); - fileXML << LLSDOStreamer<LLSDNotationFormatter>(sd) << std::endl; + cat_array.append(sd); cat_count++; } - - if (fileXML.fail()) - { - LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL; - return false; - } } + inventory["items"] = LLSD::emptyArray(); + LLSD& item_array = inventory["items"]; auto it_count = items.size(); for (auto& item : items) { - LLSD sd = LLSD::emptyMap(); + LLSD sd; item->asLLSD(sd); - fileXML << LLSDOStreamer<LLSDNotationFormatter>(sd) << std::endl; - - if (fileXML.fail()) - { - LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL; - return false; - } + item_array.append(sd); + } + fileSD << LLSDOStreamer<LLSDBinaryFormatter>(inventory) << std::endl; + if (fileSD.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL; + return false; } - fileXML.flush(); + fileSD.flush(); - fileXML.close(); + fileSD.close(); LL_INFOS(LOG_INV) << "Inventory saved: " << (S32)cat_count << " categories, " << (S32)it_count << " items." << LL_ENDL; } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index e86599035e..9034678782 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,6 +32,8 @@ #include "lllogchat.h" #include "llregex.h" #include "lltrans.h" +#include "llurlaction.h" +#include "llurlentry.h" #include "llviewercontrol.h" #include "lldiriterator.h" @@ -360,13 +362,29 @@ void LLLogChat::saveHistory(const std::string& filename, return; } + std::string altered_line = line; + + // avoid costly regex calls + if (line.find("/mention") != std::string::npos) + { + static const boost::regex mention_regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/mention", boost::regex::perl | boost::regex::icase); + + // replace mention URL with [@username](URL) + altered_line = boost::regex_replace(line, mention_regex, [](const boost::smatch& match) -> std::string + { + std::string url = match[0].str(); + std::string username = LLUrlAction::getURLLabel(url); + return "[" + username + "](" + url + ")"; + }); + } + LLSD item; if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) item["time"] = LLLogChat::timestamp2LogString(0, gSavedPerAccountSettings.getBOOL("LogTimestampDate")); item["from_id"] = from_id; - item["message"] = line; + item["message"] = altered_line; //adding "Second Life:" for all system messages to make chat log history parsing more reliable if (from.empty() && from_id.isNull()) @@ -472,6 +490,19 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m std::string line(remove_utf8_bom(buffer)); + + // fast heuristic test for a mention URL in a string + // this is used to avoid costly regex calls + if (line.find("/mention)") != std::string::npos) + { + // restore original mention URL from [@username](URL) format + static const boost::regex altered_mention_regex("\\[@([^\\]]+)\\]\\((" APP_HEADER_REGEX "/agent/[\\da-f-]+/mention)\\)", + boost::regex::perl | boost::regex::icase); + + // $2 captures the URL part + line = boost::regex_replace(line, altered_mention_regex, "$2"); + } + //updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message if (' ' == line[0]) { diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 57acf51e26..07d68fc3ec 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2380,7 +2380,13 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); if (volume->unpackVolumeFaces(data, data_size)) { - if (volume->getNumFaces() > 0) + // Use LLVolume::getNumVolumeFaces() here and not LLVolume::getNumFaces(), + // because setMeshAssetLoaded() has not yet been called for this volume + // (it is set later in LLMeshRepository::notifyMeshLoaded()), and + // getNumFaces() would return the number of faces in the LLProfile + // instead. HB + S32 num_faces = volume->getNumVolumeFaces(); + if (num_faces > 0) { // if we have a valid SkinInfo, cache per-joint bounding boxes for this LOD LLPointer<LLMeshSkinInfo> skin_info = nullptr; @@ -2394,7 +2400,7 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p } if (skin_info.notNull() && isAgentAvatarValid()) { - for (S32 i = 0; i < volume->getNumFaces(); ++i) + for (S32 i = 0; i < num_faces; ++i) { // NOTE: no need to lock gAgentAvatarp as the state being checked is not changed after initialization LLVolumeFace& face = volume->getVolumeFace(i); 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 2b2b5ea696..cb2a6191fa 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -34,11 +34,13 @@ #include "llaccordionctrl.h" #include "llaccordionctrltab.h" #include "llagentwearables.h" +#include "llaisapi.h" #include "llappearancemgr.h" #include "llappviewer.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" #include "llinspecttexture.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llmenubutton.h" @@ -247,12 +249,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 4909c11bae..514d772340 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2205,7 +2205,7 @@ void LLPanelFace::refreshMedia() // check if all faces have media(or, all dont have media) - LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue(&func, bool_has_media); + bool identical_has_media_info = selected_objects->getSelectedTEValue(&func, bool_has_media); const LLMediaEntry default_media_data; @@ -2227,7 +2227,8 @@ void LLPanelFace::refreshMedia() } func_media_data(default_media_data); LLMediaEntry media_data_get; - LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get)); + bool multiple_media = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get)); + bool multiple_valid_media = false; std::string multi_media_info_str = LLTrans::getString("Multiple Media"); std::string media_title = ""; @@ -2236,12 +2237,12 @@ void LLPanelFace::refreshMedia() mAddMedia->setEnabled(editable); // IF all the faces have media (or all dont have media) - if (LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo) + if (identical_has_media_info) { // TODO: get media title and set it. mTitleMediaText->clear(); // if identical is set, all faces are same (whether all empty or has the same media) - if (!(LLFloaterMediaSettings::getInstance()->mMultipleMedia)) + if (!multiple_media) { // Media data is valid if (media_data_get != default_media_data) @@ -2262,9 +2263,9 @@ void LLPanelFace::refreshMedia() else // not all face has media but at least one does. { // seleted faces have not identical value - LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data); + multiple_valid_media = selected_objects->isMultipleTEValue(&func_media_data, default_media_data); - if (LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + if (multiple_valid_media) { media_title = multi_media_info_str; } @@ -2301,7 +2302,7 @@ void LLPanelFace::refreshMedia() // load values for media settings updateMediaSettings(); - LLFloaterMediaSettings::initValues(mMediaSettings, editable); + LLFloaterMediaSettings::initValues(mMediaSettings, editable, identical_has_media_info, multiple_media, multiple_valid_media); } void LLPanelFace::unloadMedia() @@ -3374,6 +3375,7 @@ void LLPanelFace::onSelectNormalTexture(const LLSD& data) // TODO: test if there is media on the item and only allow editing if present void LLPanelFace::onClickBtnEditMedia() { + LLFloaterMediaSettings::getInstance(); // make sure floater we are about to open exists before refreshMedia refreshMedia(); LLFloaterReg::showInstance("media_settings"); } @@ -3392,6 +3394,7 @@ void LLPanelFace::onClickBtnAddMedia() // check if multiple faces are selected if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected()) { + LLFloaterMediaSettings::getInstance(); // make sure floater we are about to open exists before refreshMedia refreshMedia(); LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), multipleFacesSelectedConfirm); } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index ed80c8b732..59aa375457 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -184,7 +184,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, mCallback(callback), mCallbackData(cb_data), mListener(new LLPanelLoginListener(this)), - mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")), mUsernameLength(0), mPasswordLength(0), mLocationLength(0), @@ -203,14 +202,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, login_holder->addChild(this); } - if (mFirstLoginThisInstall) - { - buildFromFile( "panel_login_first.xml"); - } - else - { - buildFromFile( "panel_login.xml"); - } + buildFromFile("panel_login.xml"); reshape(rect.getWidth(), rect.getHeight()); @@ -224,38 +216,36 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, sendChildToBack(getChildView("sign_up_text")); std::string current_grid = LLGridManager::getInstance()->getGrid(); - if (!mFirstLoginThisInstall) - { - LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); - updateLocationSelectorsVisibility(); // separate so that it can be called from preferences - favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); - favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); + LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); + updateLocationSelectorsVisibility(); // separate so that it can be called from preferences + favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); + favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); + + LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); - // Load all of the grids, sorted, and then add a bar and the current grid at the top - server_choice_combo->removeall(); + // Load all of the grids, sorted, and then add a bar and the current grid at the top + server_choice_combo->removeall(); - std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); - for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); - grid_choice != known_grids.end(); - grid_choice++) + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); + for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) + { + if (!grid_choice->first.empty() && current_grid != grid_choice->first) { - if (!grid_choice->first.empty() && current_grid != grid_choice->first) - { - LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; - server_choice_combo->add(grid_choice->second, grid_choice->first); - } + LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; + server_choice_combo->add(grid_choice->second, grid_choice->first); } - server_choice_combo->sortByName(); - - LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; - server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), - current_grid, - ADD_TOP); - server_choice_combo->selectFirstItem(); } + server_choice_combo->sortByName(); + + LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + current_grid, + ADD_TOP); + server_choice_combo->selectFirstItem(); LLSLURL start_slurl(LLStartUp::getStartSLURL()); // The StartSLURL might have been set either by an explicit command-line @@ -331,15 +321,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, void LLPanelLogin::addFavoritesToStartLocation() { - if (mFirstLoginThisInstall) - { - // first login panel has no favorites, just update name length and buttons - std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); - mUsernameLength = static_cast<unsigned int>(user_defined_name.length()); - updateLoginButtons(); - return; - } - // Clear the combo. LLComboBox* combo = getChild<LLComboBox>("start_location_combo"); if (!combo) return; @@ -559,16 +540,9 @@ void LLPanelLogin::resetFields() // function is used to reset list in case of changes by external sources return; } - if (sInstance->mFirstLoginThisInstall) - { - // no list to populate - LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL; - } - else - { - LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - sInstance->populateUserList(cred); - } + + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(cred); } // static @@ -586,7 +560,6 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential) if(identifier.has("type") && (std::string)identifier["type"] == "agent") { - // not nessesary for panel_login.xml, needed for panel_login_first.xml std::string firstname = identifier["first_name"].asString(); std::string lastname = identifier["last_name"].asString(); std::string login_id = firstname; @@ -1081,8 +1054,7 @@ void LLPanelLogin::onRememberUserCheck(void*) LLComboBox* user_combo(sInstance->getChild<LLComboBox>("username_combo")); bool remember = remember_name->getValue().asBoolean(); - if (!sInstance->mFirstLoginThisInstall - && user_combo->getCurrentIndex() != -1 + if (user_combo->getCurrentIndex() != -1 && !remember) { remember = true; @@ -1197,17 +1169,14 @@ void LLPanelLogin::updateLoginButtons() login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0); - if (!mFirstLoginThisInstall) + LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + if (user_combo->getCurrentIndex() != -1) { - LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); - LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); - if (user_combo->getCurrentIndex() != -1) - { - remember_name->setValue(true); - LLCheckBoxCtrl* remember_pass = getChild<LLCheckBoxCtrl>("remember_password"); - remember_pass->setEnabled(true); - } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user - } + remember_name->setValue(true); + LLCheckBoxCtrl* remember_pass = getChild<LLCheckBoxCtrl>("remember_password"); + remember_pass->setEnabled(true); + } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user } void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential) diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index a1bf25fb05..1259bf26d6 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -119,7 +119,6 @@ private: static LLPanelLogin* sInstance; static bool sCapslockDidNotification; - bool mFirstLoginThisInstall; static bool sCredentialSet; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 01541968de..42c40fe404 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -846,7 +846,7 @@ void LLPanelPeople::updateNearbyList() mNearbyList->setDirty(); #ifdef LL_DISCORD if (gSavedSettings.getBOOL("EnableDiscord")) - LLAppViewer::updateDiscordPartyMaxSize(mNearbyList->getIDs().size()); + LLAppViewer::updateDiscordPartyMaxSize((S32)mNearbyList->getIDs().size()); #endif DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 6966cb38ab..794ae4ad44 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -155,11 +155,15 @@ void PeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata) { + std::string item = userdata.asString(); if(gAgent.getID() == mUUIDs.front()) { + if (item == std::string("can_zoom_in")) + { + return true; + } return false; } - std::string item = userdata.asString(); // Note: can_block and can_delete is used only for one person selected menu // so we don't need to go over all uuids. diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 1948bba4be..00c219fdda 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2249,6 +2249,7 @@ void LLSelectMgr::selectionRevertGLTFMaterials() { // Restore base material LLUUID asset_id = nodep->mSavedGLTFMaterialIds[te]; + LLUUID old_asset_id = objectp->getRenderMaterialID(te); // Update material locally objectp->setRenderMaterialID(te, asset_id, false /*wait for LLGLTFMaterialList update*/); @@ -2259,18 +2260,29 @@ void LLSelectMgr::selectionRevertGLTFMaterials() objectp->setTEGLTFMaterialOverride(te, material); } - // Enqueue update to server - if (asset_id.notNull() && material) + if (asset_id.isNull() || !material) + { + //blank override out + LLGLTFMaterialList::queueApply(objectp, te, asset_id); + } + if (old_asset_id != asset_id) { // Restore overrides and base material + // Note: might not work reliably if asset is already there, might + // have a server sided problem where servers applies override + // first then resets it by adding asset, in which case need + // to create a server ticket and chain asset then override + // application. LLGLTFMaterialList::queueApply(objectp, te, asset_id, material); } else { - //blank override out - LLGLTFMaterialList::queueApply(objectp, te, asset_id); + // Enqueue override update to server + // Note: this is suboptimal, better to send asset id as well + // but there seems to be a server problem with queueApply + // that ignores override in some cases + LLGLTFMaterialList::queueModify(objectp, te, material); } - } return true; } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 12a9d5e9b7..b49c0119ed 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -1028,7 +1028,7 @@ void LLLocalSpeakerMgr::updateSpeakerList() LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); #ifdef LL_DISCORD if (gSavedSettings.getBOOL("EnableDiscord")) - LLAppViewer::updateDiscordPartyCurrentSize(avatar_ids.size()); + LLAppViewer::updateDiscordPartyCurrentSize((S32)avatar_ids.size()); #endif for(U32 i=0; i<avatar_ids.size(); i++) { diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index bda75c16e7..bf4ec14487 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -115,6 +115,8 @@ LLStatusBar::LLStatusBar(const LLRect& rect) mBtnVolume(NULL), mBoxBalance(NULL), mBalance(0), + mBalanceClicked(false), + mObscureBalance(false), mHealth(100), mSquareMetersCredit(0), mSquareMetersCommitted(0), @@ -126,8 +128,6 @@ LLStatusBar::LLStatusBar(const LLRect& rect) // status bar can possible overlay menus? setMouseOpaque(false); - mBalanceTimer = new LLFrameTimer(); - mHealthTimer = new LLFrameTimer(); mFpsUpdateTimer = new LLFrameTimer(); buildFromFile("panel_status_bar.xml"); @@ -135,12 +135,6 @@ LLStatusBar::LLStatusBar(const LLRect& rect) LLStatusBar::~LLStatusBar() { - delete mBalanceTimer; - mBalanceTimer = NULL; - - delete mHealthTimer; - mHealthTimer = NULL; - // LLView destructor cleans up children } @@ -176,7 +170,8 @@ bool LLStatusBar::postBuild() getChild<LLUICtrl>("goShop")->setCommitCallback(boost::bind(&LLWeb::loadURL, gSavedSettings.getString("MarketplaceURL"), LLStringUtil::null, LLStringUtil::null)); mBoxBalance = getChild<LLTextBox>("balance"); - mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this ); + mBoxBalance->setClickedCallback(&LLStatusBar::onClickRefreshBalance, this); + mBoxBalance->setDoubleClickCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onClickToggleBalance(); }); mIconPresetsCamera = getChild<LLIconCtrl>( "presets_icon_camera" ); mIconPresetsCamera->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresetsCamera, this)); @@ -196,12 +191,14 @@ bool LLStatusBar::postBuild() gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&LLStatusBar::onVolumeChanged, this, _2)); gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLStatusBar::onVoiceChanged, this, _2)); + gSavedSettings.getControl("ObscureBalanceInStatusBar")->getSignal()->connect(boost::bind(&LLStatusBar::onObscureBalanceChanged, this, _2)); if (!gSavedSettings.getBOOL("EnableVoiceChat") && LLAppViewer::instance()->isSecondInstance()) { // Indicate that second instance started without sound mBtnVolume->setImageUnselected(LLUI::getUIImage("VoiceMute_Off")); } + mObscureBalance = gSavedSettings.getBOOL("ObscureBalanceInStatusBar"); // Adding Net Stat Graph S32 x = getRect().getWidth() - 2; @@ -334,6 +331,12 @@ void LLStatusBar::refresh() mTextTime->setToolTip (dtStr); } + if (mBalanceClicked && mBalanceClickTimer.getElapsedTimeF32() > 1.f) + { + mBalanceClicked = false; + sendMoneyBalanceRequest(); + } + LLRect r; const S32 MENU_RIGHT = gMenuBarView->getRightmostMenuEdge(); @@ -399,9 +402,17 @@ void LLStatusBar::setBalance(S32 balance) std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance ); LLStringUtil::format_map_t string_args; - string_args["[AMT]"] = llformat("%s", money_str.c_str()); + if (mObscureBalance) + { + string_args["[AMT]"] = "****"; + } + else + { + string_args["[AMT]"] = llformat("%s", money_str.c_str()); + } std::string label_str = getString("buycurrencylabel", string_args); mBoxBalance->setValue(label_str); + mBoxBalance->setToolTipArg(LLStringExplicit("[AMT]"), llformat("%s", money_str.c_str())); updateBalancePanelPosition(); @@ -421,8 +432,6 @@ void LLStatusBar::setBalance(S32 balance) if( balance != mBalance ) { - mBalanceTimer->reset(); - mBalanceTimer->setTimerExpirySec( ICON_TIMER_EXPIRY ); mBalance = balance; } } @@ -474,9 +483,6 @@ void LLStatusBar::setHealth(S32 health) } } } - - mHealthTimer->reset(); - mHealthTimer->setTimerExpirySec( ICON_TIMER_EXPIRY ); } mHealth = health; @@ -636,13 +642,27 @@ static void onClickVolume(void* data) } //static -void LLStatusBar::onClickBalance(void* ) +void LLStatusBar::onClickRefreshBalance(void* data) { - // Force a balance request message: - LLStatusBar::sendMoneyBalanceRequest(); + LLStatusBar* status_bar = (LLStatusBar*)data; + + if (!status_bar->mBalanceClicked) + { + // Schedule a balance request message: + status_bar->mBalanceClicked = true; + status_bar->mBalanceClickTimer.reset(); + } // The refresh of the display (call to setBalance()) will be done by process_money_balance_reply() } +void LLStatusBar::onClickToggleBalance() +{ + mObscureBalance = !mObscureBalance; + gSavedSettings.setBOOL("ObscureBalanceInStatusBar", mObscureBalance); + setBalance(mBalance); + mBalanceClicked = false; // supress click +} + //static void LLStatusBar::onClickMediaToggle(void* data) { @@ -678,6 +698,12 @@ void LLStatusBar::onVoiceChanged(const LLSD& newvalue) refresh(); } +void LLStatusBar::onObscureBalanceChanged(const LLSD& newvalue) +{ + mObscureBalance = newvalue.asBoolean(); + setBalance(mBalance); +} + void LLStatusBar::onUpdateFilterTerm() { LLWString searchValue = utf8str_to_wstring( mFilterEdit->getValue() ); diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 86c1ccd051..f1225a22f8 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -72,7 +72,8 @@ public: void debitBalance(S32 debit); void creditBalance(S32 credit); - // Request the latest currency balance from the server + // Request the latest currency balance from the server. + // Reply at process_money_balance_reply() static void sendMoneyBalanceRequest(); void setHealth(S32 percent); @@ -102,6 +103,7 @@ private: void onClickBuyCurrency(); void onVolumeChanged(const LLSD& newvalue); void onVoiceChanged(const LLSD& newvalue); + void onObscureBalanceChanged(const LLSD& newvalue); void onMouseEnterPresetsCamera(); void onMouseEnterPresets(); @@ -109,7 +111,8 @@ private: void onMouseEnterNearbyMedia(); static void onClickMediaToggle(void* data); - static void onClickBalance(void* data); + static void onClickRefreshBalance(void* data); + void onClickToggleBalance(); static void onClickFps(void* data); @@ -139,11 +142,12 @@ private: LLFrameTimer *mFpsUpdateTimer; S32 mBalance; + bool mBalanceClicked; + bool mObscureBalance; + LLTimer mBalanceClickTimer; S32 mHealth; S32 mSquareMetersCredit; S32 mSquareMetersCommitted; - LLFrameTimer* mBalanceTimer; - LLFrameTimer* mHealthTimer; LLPanelPresetsCameraPulldown* mPanelPresetsCameraPulldown; LLPanelPresetsPulldown* mPanelPresetsPulldown; LLPanelVolumePulldown* mPanelVolumePulldown; diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 3665ff5e87..b4a5955be3 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1125,28 +1125,33 @@ void set_texture_to_material(LLViewerObject* hit_obj, case LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR: default: { - material->setBaseColorId(asset_id); + material->setBaseColorId(asset_id, true); } break; case LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS: { - material->setOcclusionRoughnessMetallicId(asset_id); + material->setOcclusionRoughnessMetallicId(asset_id, true); } break; case LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE: { - material->setEmissiveId(asset_id); + material->setEmissiveId(asset_id, true); } break; case LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL: { - material->setNormalId(asset_id); + material->setNormalId(asset_id, true); } break; } + // Update viewer side, needed for updating mSavedGLTFOverrideMaterials. + // Also for parity, we are immediately setting textures and materials, + // so we should immediate set overrides to. + hit_obj->setTEGLTFMaterialOverride(hit_face, material); + // update server LLGLTFMaterialList::queueModify(hit_obj, hit_face, material); } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 5f61aeaf13..6155058f14 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -761,18 +761,23 @@ void LLViewerInventoryCategory::exportLLSD(LLSD & cat_data) const cat_data[INV_VERSION] = mVersion; } -bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data) +bool LLViewerInventoryCategory::importLLSD(const std::string& label, const LLSD& value) { - LLInventoryCategory::importLLSD(cat_data); - if (cat_data.has(INV_OWNER_ID)) + if (LLInventoryCategory::importLLSD(label, value)) { - mOwnerID = cat_data[INV_OWNER_ID].asUUID(); + return true; } - if (cat_data.has(INV_VERSION)) + else if (label == INV_OWNER_ID) { - setVersion(cat_data[INV_VERSION].asInteger()); + mOwnerID = value.asUUID(); + return true; } - return true; + else if (label == INV_VERSION) + { + setVersion(value.asInteger()); + return true; + } + return false; } bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item) diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 5cd31353f8..0dfbf0cced 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -233,7 +233,7 @@ public: S32 getViewerDescendentCount() const; virtual void exportLLSD(LLSD &sd) const; - virtual bool importLLSD(const LLSD& cat_data); + virtual bool importLLSD(const std::string& label, const LLSD& value); void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp index 21f5ba64d7..959de38364 100644 --- a/indra/newview/llviewermedia_streamingaudio.cpp +++ b/indra/newview/llviewermedia_streamingaudio.cpp @@ -61,13 +61,26 @@ void LLStreamingAudio_MediaPlugins::start(const std::string& url) if(!mMediaPlugin) return; - if (!url.empty()) { + if (!url.empty()) + { LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; - mURL = url; - mMediaPlugin->loadURI ( url ); + + mURL = url; // keep original url here for comparison purposes + std::string snt_url = url; + LLStringUtil::trim(snt_url); + size_t pos = snt_url.find(' '); + if (pos != std::string::npos) + { + // fmod permited having names after the url and people were using it. + // People label their streams this way, ignore the 'label'. + snt_url = snt_url.substr(0, pos); + } + mMediaPlugin->loadURI(snt_url); mMediaPlugin->start(); LL_INFOS() << "Playing stream..." << LL_ENDL; - } else { + } + else + { LL_INFOS() << "setting stream to NULL"<< LL_ENDL; mURL.clear(); mMediaPlugin->stop(); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d9d20611b4..3695478061 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -69,6 +69,7 @@ #include "llviewerassetupload.h" // linden libraries +#include "llfilesystem.h" #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llsdutil.h" @@ -550,16 +551,9 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k) if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec)) { bool resource_upload = false; - if (asset_type == LLAssetType::AT_TEXTURE && allow_2k) + if (asset_type == LLAssetType::AT_TEXTURE) { - LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec); - if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename)) - { - S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height); - resource_upload = true; - } + resource_upload = true; } else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost)) { @@ -568,23 +562,115 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k) if (resource_upload) { - LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo( - filename, - asset_name, - asset_name, 0, - LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - expected_upload_cost); - - if (!allow_2k) + if (asset_type == LLAssetType::AT_TEXTURE) { - info_p->setMaxImageSize(1024); - } - LLResourceUploadInfo::ptr_t uploadInfo(info_p); + std::string exten = gDirUtilp->getExtension(filename); + U32 codec = LLImageBase::getCodecFromExtension(exten); + + // Load the image + LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); + if (image.isNull()) + { + LL_WARNS() << "Failed to create image container for " << filename << LL_ENDL; + continue; + } + if (!image->load(filename)) + { + LL_WARNS() << "Failed to load image: " << filename << LL_ENDL; + continue; + } + // Decompress or expand it in a raw image structure + LLPointer<LLImageRaw> raw_image = new LLImageRaw; + if (!image->decode(raw_image, 0.0f)) + { + LL_WARNS() << "Failed to decode image: " << filename << LL_ENDL; + continue; + } + // Check the image constraints + if ((image->getComponents() != 3) && (image->getComponents() != 4)) + { + LL_WARNS() << "Attempted to upload a texture that has " << image->getComponents() + << " components, but only 3 (RGB) or 4 (RGBA) are allowed." << LL_ENDL; + continue; + } + // Downscale images to fit the max_texture_dimensions_*, or 1024 if allow_2k is false + S32 max_width = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024; + S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024; + + S32 orig_width = raw_image->getWidth(); + S32 orig_height = raw_image->getHeight(); + + if (orig_width > max_width || orig_height > max_height) + { + // Calculate scale factors + F32 width_scale = (F32)max_width / (F32)orig_width; + F32 height_scale = (F32)max_height / (F32)orig_height; + F32 scale = llmin(width_scale, height_scale); + + // Calculate new dimensions, preserving aspect ratio + S32 new_width = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width)); + S32 new_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height)); + + if (!raw_image->scale(new_width, new_height)) + { + LL_WARNS() << "Failed to scale image from " << orig_width << "x" << orig_height << " to " << new_width << "x" + << new_height << LL_ENDL; + continue; + } + + // Inform the resident about the resized image + LLSD subs; + subs["[ORIGINAL_WIDTH]"] = orig_width; + subs["[ORIGINAL_HEIGHT]"] = orig_height; + subs["[NEW_WIDTH]"] = new_width; + subs["[NEW_HEIGHT]"] = new_height; + subs["[MAX_WIDTH]"] = max_width; + subs["[MAX_HEIGHT]"] = max_height; + LLNotificationsUtil::add("ImageUploadResized", subs); + } + + raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + + LLTransactionID tid; + tid.generate(); + LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - upload_new_resource(uploadInfo); + LLPointer<LLImageJ2C> formatted = new LLImageJ2C; + + if (formatted->encode(raw_image, 0.0f)) + { + LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE); + fmt_file.write(formatted->getData(), formatted->getDataSize()); + + LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo( + tid, LLAssetType::AT_TEXTURE, + asset_name, + asset_name, 0, + LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + LLAgentBenefitsMgr::current().getTextureUploadCost(raw_image->getWidth(), raw_image->getHeight()) + )); + + upload_new_resource(assetUploadInfo); + } + } + else + { + LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo( + filename, + asset_name, + asset_name, 0, + LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost); + LLResourceUploadInfo::ptr_t uploadInfo(info_p); + + upload_new_resource(uploadInfo); + } } } @@ -653,8 +739,31 @@ bool get_bulk_upload_expected_cost( LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec); if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename)) { - S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); - S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + S32 biased_width, biased_height; + + S32 max_width = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024; + S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024; + + S32 orig_width = image_frmted->getWidth(); + S32 orig_height = image_frmted->getHeight(); + + if (orig_width > max_width || orig_height > max_height) + { + // Calculate scale factors + F32 width_scale = (F32)max_width / (F32)orig_width; + F32 height_scale = (F32)max_height / (F32)orig_height; + F32 scale = llmin(width_scale, height_scale); + + // Calculate new dimensions, preserving aspect ratio + biased_width = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width)); + biased_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height)); + } + else + { + biased_width = LLImageRaw::biasedDimToPowerOfTwo(orig_width, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + biased_height = LLImageRaw::biasedDimToPowerOfTwo(orig_height, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + } + total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height); S32 area = biased_width * biased_height; if (area >= LLAgentBenefits::MIN_2K_TEXTURE_AREA) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 86bd11d1eb..0cd4a739ee 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3214,6 +3214,7 @@ void send_agent_update(bool force_send, bool send_reliable) static F64 last_send_time = 0.0; static U32 last_control_flags = 0; + static bool control_flags_follow_up = false; static U8 last_render_state = 0; static U8 last_flags = AU_FLAGS_NONE; static LLQuaternion last_body_rot, @@ -3291,6 +3292,20 @@ void send_agent_update(bool force_send, bool send_reliable) break; } + // example: + // user taps crouch (control_flags 4128), viewer sends 4128 then immediately 0 + // server starts crouching motion but does not stop it, only once viewer sends 0 + // second time will server stop the motion. follow_up exists to make sure all + // states like 'crouch' motion are properly cleared server side. + // + // P.S. Server probably shouldn't require a reminder to stop a motion, + // but at the moment it does. + if (control_flags_follow_up) + { + send_update = true; + break; + } + // check translation constexpr F32 TRANSLATE_THRESHOLD = 0.01f; if ((last_camera_pos_agent - camera_pos_agent).magVec() > TRANSLATE_THRESHOLD) @@ -3424,6 +3439,7 @@ void send_agent_update(bool force_send, bool send_reliable) // remember last update data last_send_time = now; + control_flags_follow_up = last_control_flags != control_flags; last_control_flags = control_flags; last_render_state = render_state; last_flags = flags; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 80ede12b8a..e317ba262a 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -679,6 +679,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), @@ -934,12 +935,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; @@ -986,30 +987,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++; + } + } } } } @@ -1026,7 +1042,7 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status) switch (rez_status) { case 0: - return "cloud"; + return "missing parts"; case 1: return "gray"; case 2: @@ -3505,7 +3521,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) { @@ -8255,7 +8271,7 @@ bool LLVOAvatar::isVisible() const } // Determine if we have enough avatar data to render -bool LLVOAvatar::getIsCloud() const +bool LLVOAvatar::getHasMissingParts() const { if (mIsDummy) { @@ -8462,8 +8478,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) @@ -11830,16 +11850,24 @@ void LLVOAvatar::readProfileQuery(S32 retries) } else - { // wait until next frame - LLUUID id = getID(); + { + // wait until next frame + const LLUUID id = getID(); - LL::WorkQueue::getInstance("mainloop")->post([id, retries] { - LLVOAvatar* avatar = (LLVOAvatar*) gObjectList.findObject(id); - if(avatar) + LL::WorkQueue::getInstance("mainloop")->post([id, retries] + { + LLViewerObject* object = gObjectList.findObject(id); + if (object + && !object->isDead() + && object->isAvatar()) // probably excessive, pcode isn't supposed to change { - avatar->readProfileQuery(retries); + LLVOAvatar* avatar = (LLVOAvatar*)object; + if (avatar) + { + avatar->readProfileQuery(retries); + } } - }); + }); } } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 8e5b95ef25..1e563c4869 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -401,7 +401,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 = waiting for attachments, 4 = full. @@ -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..653c7e82eb 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; @@ -2826,6 +2830,12 @@ void LLVOAvatarSelf::setHoverOffset(const LLVector3& hover_offset, bool send_upd //------------------------------------------------------------------------ bool LLVOAvatarSelf::needsRenderBeam() { + static LLCachedControl<bool> enable_selection_hints(gSavedSettings, "EnableSelectionHints", true); + if (!enable_selection_hints) + { + return false; + } + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); bool is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing()); 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/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index facda1d876..e9c765f9de 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -336,35 +336,37 @@ void LLWebRTCVoiceClient::updateSettings() LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE; setVoiceEnabled(LLVoiceClient::getInstance()->voiceEnabled()); - static LLCachedControl<S32> sVoiceEarLocation(gSavedSettings, "VoiceEarLocation"); - setEarLocation(sVoiceEarLocation); - - static LLCachedControl<std::string> sInputDevice(gSavedSettings, "VoiceInputAudioDevice"); - setCaptureDevice(sInputDevice); + if (mVoiceEnabled) + { + static LLCachedControl<S32> sVoiceEarLocation(gSavedSettings, "VoiceEarLocation"); + setEarLocation(sVoiceEarLocation); - static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice"); - setRenderDevice(sOutputDevice); + static LLCachedControl<std::string> sInputDevice(gSavedSettings, "VoiceInputAudioDevice"); + setCaptureDevice(sInputDevice); - LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL; + static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice"); + setRenderDevice(sOutputDevice); - static LLCachedControl<F32> sMicLevel(gSavedSettings, "AudioLevelMic"); - setMicGain(sMicLevel); + LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL; - llwebrtc::LLWebRTCDeviceInterface::AudioConfig config; + static LLCachedControl<F32> sMicLevel(gSavedSettings, "AudioLevelMic"); + setMicGain(sMicLevel); - static LLCachedControl<bool> sEchoCancellation(gSavedSettings, "VoiceEchoCancellation", true); - config.mEchoCancellation = sEchoCancellation; + llwebrtc::LLWebRTCDeviceInterface::AudioConfig config; - static LLCachedControl<bool> sAGC(gSavedSettings, "VoiceAutomaticGainControl", true); - config.mAGC = sAGC; + static LLCachedControl<bool> sEchoCancellation(gSavedSettings, "VoiceEchoCancellation", true); + config.mEchoCancellation = sEchoCancellation; - static LLCachedControl<U32> sNoiseSuppressionLevel(gSavedSettings, - "VoiceNoiseSuppressionLevel", - llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel::NOISE_SUPPRESSION_LEVEL_VERY_HIGH); - config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel) (U32)sNoiseSuppressionLevel; + static LLCachedControl<bool> sAGC(gSavedSettings, "VoiceAutomaticGainControl", true); + config.mAGC = sAGC; - mWebRTCDeviceInterface->setAudioConfig(config); + static LLCachedControl<U32> sNoiseSuppressionLevel(gSavedSettings, + "VoiceNoiseSuppressionLevel", + llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel::NOISE_SUPPRESSION_LEVEL_VERY_HIGH); + config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel)(U32)sNoiseSuppressionLevel; + mWebRTCDeviceInterface->setAudioConfig(config); + } } // Observers diff --git a/indra/newview/res/ll_icon_small.ico b/indra/newview/res/ll_icon_small.ico Binary files differnew file mode 100644 index 0000000000..a3f6877935 --- /dev/null +++ b/indra/newview/res/ll_icon_small.ico diff --git a/indra/newview/res/resource.h b/indra/newview/res/resource.h index e904f4a1a8..1d3289d784 100644 --- a/indra/newview/res/resource.h +++ b/indra/newview/res/resource.h @@ -30,6 +30,7 @@ #define IDREMOVE 3 #define IDI_LL_ICON 103 #define IDC_GRABHAND 104 +#define IDI_LL_ICON_SMALL 105 #define IDC_CURSOR1 134 #define IDC_CURSOR2 136 #define IDC_CURSOR3 147 diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index b01f5e700d..08e381ebc5 100755 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -56,6 +56,7 @@ END // remains consistent on all systems. IDI_LL_ICON ICON "ll_icon.ico" IDI_LCD_LL_ICON ICON "icon1.ico" +IDI_LL_ICON_SMALL ICON "ll_icon_small.ico" ///////////////////////////////////////////////////////////////////////////// // diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 94c8119d4d..654810e210 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -659,7 +659,6 @@ with the same filename but different name <texture name="login_mp_logo" file_name="windows/login_mp_logo.png" preload="true" /> <texture name="login_mp_logo_small" file_name="windows/login_mp_logo_small.png" preload="true" /> - <texture name="first_login_image" file_name="windows/first_login_image.jpg" preload="true" /> <texture name="Stepper_Down_Off" file_name="widgets/Stepper_Down_Off.png" preload="false" /> <texture name="Stepper_Down_Press" file_name="widgets/Stepper_Down_Press.png" preload="false" /> diff --git a/indra/newview/skins/default/textures/windows/first_login_image.jpg b/indra/newview/skins/default/textures/windows/first_login_image.jpg Binary files differdeleted file mode 100644 index 58c417081a..0000000000 --- a/indra/newview/skins/default/textures/windows/first_login_image.jpg +++ /dev/null diff --git a/indra/newview/skins/default/xui/de/panel_login_first.xml b/indra/newview/skins/default/xui/de/panel_login_first.xml deleted file mode 100644 index 038001157e..0000000000 --- a/indra/newview/skins/default/xui/de/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php?lang=de - </panel.string> - <panel.string name="sign_up_url"> - https://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Benutzername" name="username_combo" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/> - <line_editor label="Kennwort" name="password_edit"/> - <button label="Anmelden" name="connect_btn"/> - <check_box label="Details speichern" name="remember_check"/> - <text name="forgot_password_text"> - Kennwort vergessen - </text> - <text name="sign_up_text"> - Registrieren - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Ihr erster Schritt ist Learning Island. Suchen Sie die Pforte! - </text> - <text name="image_caption_right"> - Erkunden Sie dann Social Island und lernen Sie andere Einwohner kennen! - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/en/floater_test_slapp.xml b/indra/newview/skins/default/xui/en/floater_test_slapp.xml index dd2720816a..5a13a0147e 100644 --- a/indra/newview/skins/default/xui/en/floater_test_slapp.xml +++ b/indra/newview/skins/default/xui/en/floater_test_slapp.xml @@ -8,7 +8,7 @@ width="500"> <floater.string name="remove_folder_slapp"> - secondlife://app/remove_folder/?folder_id= + secondlife:///app/remove_folder/?folder_id= </floater.string> <text type="string" @@ -42,7 +42,7 @@ width="450" layout="topleft" left="16"> - secondlife://app/wear_folder/?folder_name=Daisy + secondlife:///app/wear_folder/?folder_name=Daisy </text> <text type="string" @@ -63,7 +63,7 @@ width="450" layout="topleft" left="16"> - secondlife://app/add_folder/?folder_name=Cardboard%20Boxbot + secondlife:///app/add_folder/?folder_name=Cardboard%20Boxbot </text> <text type="string" @@ -73,7 +73,7 @@ height="16" width="450" layout="topleft"> - secondlife://app/add_folder/?folder_id=59219db2-c260-87d3-213d-bb3bc298a3d8 + secondlife:///app/add_folder/?folder_id=59219db2-c260-87d3-213d-bb3bc298a3d8 </text> <text type="string" @@ -118,6 +118,6 @@ name="remove_folder_txt" layout="topleft" left="16"> - secondlife://app/remove_folder/?folder_id= + secondlife:///app/remove_folder/?folder_id= </text> </floater> diff --git a/indra/newview/skins/default/xui/en/menu_url_parcel.xml b/indra/newview/skins/default/xui/en/menu_url_parcel.xml index e0f1fcf9c3..95752dab66 100644 --- a/indra/newview/skins/default/xui/en/menu_url_parcel.xml +++ b/indra/newview/skins/default/xui/en/menu_url_parcel.xml @@ -16,7 +16,7 @@ layout="topleft" name="show_on_map"> <menu_item_call.on_click - function="Url.ShowOnMap" /> + function="Url.ShowParcelOnMap" /> </menu_item_call> <menu_item_separator layout="topleft" /> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a318093d7c..10c9efffd1 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12674,4 +12674,15 @@ Select the "use as favorite folder" from a folder's menu to set it as the favori Unable to apply material to the water exclusion surface. <tag>fail</tag> </notification> + + <notification + icon="notify.tga" + name="ImageUploadResized" + type="alertmodal"> + The texture you are uploading has been resized from [ORIGINAL_WIDTH]x[ORIGINAL_HEIGHT] to [NEW_WIDTH]x[NEW_HEIGHT] in order to to fit the maximum size of [MAX_WIDTH]x[MAX_HEIGHT] pixels. + <usetemplate + ignoretext="Image Upload Resized" + name="okignore" + yestext="OK"/> + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml deleted file mode 100644 index 0a8ae48b02..0000000000 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ /dev/null @@ -1,262 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<panel - follows="all" - height="768" - layout="topleft" - name="panel_login" - focus_root="true" - background_visible="true" - bg_opaque_color="0.0 0.0 0.0 1" - background_opaque="true" - width="1024"> - <panel.string - name="forgot_password_url"> - http://secondlife.com/account/request.php - </panel.string> - <panel.string - name="sign_up_url"> - https://join.secondlife.com/ - </panel.string> - <layout_stack - follows="left|right|top|bottom" - width="1024" - height="768" - left="0" - name="logo_stack" - orientation="vertical" - top="0"> - <layout_panel - height="18" - auto_resize="false" - name="page_top" - width="1024" /> - <!-- start of logo stack --> - <layout_panel - height="130" - min_height="10" - auto_resize="false" - name="parent_panel" - width="1024"> - <layout_stack - follows="left|right|top|bottom" - height="100" - left="0" - name="logo_stack" - orientation="horizontal" - top="0" - width="1024"> - <layout_panel - height="110" - min_height="10" - auto_resize="true" - name="logo_left" - width="300" /> - <layout_panel - auto_resize="false" - follows="left|right|top" - name="logo_container" - width="225" - left="0" - top="0" - height="105"> - <icon - height="94" - image_name="login_mp_logo" - left="0" - name="sl_logo" - top="0" /> - </layout_panel> - <layout_panel - height="100" - name="logo_right" - auto_resize="true" - width="300" /> - </layout_stack> - </layout_panel> - <!-- end of logo stack --> - <!-- start of widget stack --> - <layout_panel - height="100" - min_height="10" - auto_resize="false" - name="parent_panel2" - width="1024"> - <layout_stack - follows="left|right|top|bottom" - height="80" - left="0" - name="widget_stack" - orientation="horizontal" - top="0" - width="1024"> - <layout_panel - height="80" - min_height="10" - auto_resize="true" - name="widget_left" - width="200" /> - <layout_panel - auto_resize="false" - follows="left|right|top" - name="widget_container" - width="730" - left="0" - top="0" - height="80"> - <combo_box - allow_text_entry="true" - follows="left|bottom" - height="32" - left="42" - label="Username" - combo_editor.font="SansSerifLarge" - max_chars="128" - top="0" - combo_editor.prevalidator="ascii" - tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine" - name="username_combo" - width="232"> - <combo_box.combo_editor - text_pad_left="8" /> - <combo_box.combo_button - visible ="false"/> - <combo_box.drop_down_button - visible ="false"/> - </combo_box> - <line_editor - follows="left|top" - width="200" - height="32" - left="262" - max_length_chars="16" - name="password_edit" - label="Password" - text_pad_left="8" - font="SansSerifLarge" - is_password="true" - select_on_focus="true" - commit_on_focus_lost="false" - top="0" /> - <button - follows="left|top" - image_unselected="PushButton_Login" - image_pressed="PushButton_Login_Pressed" - image_hover_unselected="PushButton_Login_Over" - label="Log In" - label_color="White" - font="SansSerifLarge" - name="connect_btn" - left_pad="15" - width="120" - height="32" - top="0" /> - <text - follows="left|top" - font="SansSerifLarge" - font.style="BOLD" - text_color="EmphasisColor" - height="34" - name="sign_up_text" - left_pad="10" - top="0" - width="200" - valign="center"> - Sign up - </text> - <check_box - follows="left|top" - font="SansSerifLarge" - left="42" - top="32" - height="24" - label="Remember me" - word_wrap="down" - check_button.bottom="3" - name="remember_name" - tool_tip="Already remembered user can be forgotten from Me > Preferences > Advanced > Remembered Usernames." - width="198" /> - <check_box - control_name="RememberPassword" - follows="left|top" - font="SansSerifLarge" - height="24" - left="262" - bottom_delta="0" - label="Remember password" - word_wrap="down" - check_button.bottom="3" - name="remember_password" - width="198" /> - <text - follows="left|top" - font="SansSerifLarge" - text_color="EmphasisColor" - height="16" - name="forgot_password_text" - left="492" - top="34" - width="200"> - Forgotten password - </text> - </layout_panel> - <layout_panel - height="100" - name="widget_right" - auto_resize="true" - width="200" /> - </layout_stack> - </layout_panel> - <!-- end of widget stack --> - <!-- start of images stack --> - <layout_panel - height="500" - min_height="10" - auto_resize="false" - name="parent_panel3" - width="1024"> - <layout_stack - follows="left|right|top|bottom" - height="500" - left="0" - name="images_stack" - orientation="horizontal" - top="0" - width="1024"> - <layout_panel - height="500" - min_height="10" - auto_resize="true" - name="images_left" - width="96" /> - <layout_panel - auto_resize="false" - follows="left|right|top" - name="images_container" - width="675" - left="0" - top="0" - height="500"> - <icon - height="450" - width="675" - image_name="first_login_image" - left="0" - name="image_left" - top="0" /> - </layout_panel> - <layout_panel - height="100" - name="images_right" - auto_resize="true" - width="96" /> - </layout_stack> - </layout_panel> - <!-- end of images stack --> - <layout_panel - height="400" - min_height="10" - auto_resize="true" - name="page_bottom" - width="1024" /> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index c38af9d4fa..54105a7d4e 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -32,15 +32,15 @@ height="23" increment="64" initial_value="1024" - label="Cache size (256 - 9984MB)" + label="Cache size (896 - 32768MB)" label_width="150" layout="topleft" left="80" - max_val="9984" - min_val="256" + max_val="32768" + min_val="896" top_pad="10" name="cachesizespinner" - width="200" /> + width="210" /> <text type="string" length="1" @@ -59,7 +59,7 @@ label="Clear Cache" label_selected="Clear Cache" layout="topleft" - left_pad="30" + left_pad="20" name="clear_cache" top_delta="0" width="100"> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml index 809c001904..8ab7b48d19 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml @@ -90,7 +90,7 @@ name="online_visibility" top_pad="15" width="350" /> - + <check_box enabled_control="EnableVoiceChat" control_name="AutoDisengageMic" @@ -101,6 +101,37 @@ name="auto_disengage_mic_check" top_pad="10" width="350" /> + <check_box + control_name="EnableLookAtTarget" + height="16" + label="Enable LookAt" + tool_tip="Enable tracking cursor position with avatar head's rotation" + layout="topleft" + left="30" + name="enable_lookat_target" + top_pad="10" + width="350" /> + <check_box + enabled_control="EnableLookAtTarget" + control_name="LimitLookAtTarget" + height="16" + label="Limit LookAt Distance" + tool_tip="Limit the look at target's distance by restricting it around the avatar's head" + layout="topleft" + left="50" + name="limit_lookat_distance" + top_pad="10" + width="350" /> + <check_box + control_name="EnableSelectionHints" + height="16" + label="Enable Selection Hints" + tool_tip="Enable reporting and tracking current selection using 'beam' particles and character animations" + layout="topleft" + left="30" + name="enable_selection_hints" + top_pad="10" + width="350" /> <button follows="left|top" height="23" diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 5e05eb2837..e53a25ff6b 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -86,7 +86,7 @@ height="18" left="0" name="balance" - tool_tip="Click to refresh your L$ balance" + tool_tip="L$ [AMT] Click to refresh your L$ balance. Double-click to display or hide your L$ balance." v_pad="4" top="0" wrap="false" diff --git a/indra/newview/skins/default/xui/es/panel_login_first.xml b/indra/newview/skins/default/xui/es/panel_login_first.xml deleted file mode 100644 index ccb6858351..0000000000 --- a/indra/newview/skins/default/xui/es/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php?lang=es - </panel.string> - <panel.string name="sign_up_url"> - https://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Nombre de usuario" name="username_combo" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/> - <line_editor label="Contraseña" name="password_edit"/> - <button label="Iniciar sesión" name="connect_btn"/> - <check_box label="Recordarme" name="remember_check"/> - <text name="forgot_password_text"> - Contraseña olvidada - </text> - <text name="sign_up_text"> - Regístrate - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Tu primer destino es la Isla de aprendizaje. ¡Encuentra el portal de salida! - </text> - <text name="image_caption_right"> - A continuación, puedes explorar la Isla social y hablar con otros residentes nuevos. - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/fr/panel_login_first.xml b/indra/newview/skins/default/xui/fr/panel_login_first.xml deleted file mode 100644 index 8f40d0230c..0000000000 --- a/indra/newview/skins/default/xui/fr/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php?lang=fr - </panel.string> - <panel.string name="sign_up_url"> - https://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Nom d'utilisateur" name="username_combo" tool_tip="Nom d'utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/> - <line_editor label="Mot de passe" name="password_edit"/> - <button label="Connexion" name="connect_btn"/> - <check_box font="SansSerifSmall" label="Mémoriser mes informations" name="remember_check"/> - <text name="forgot_password_text"> - Mot de passe oublié - </text> - <text name="sign_up_text"> - S'inscrire - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Votre première étape est Learning Island. Trouvez le portail de sortie. - </text> - <text name="image_caption_right"> - Puis explorez Social Island et faites la connaissance d'autres résidents. - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/it/panel_login_first.xml b/indra/newview/skins/default/xui/it/panel_login_first.xml deleted file mode 100644 index 5b04fd411a..0000000000 --- a/indra/newview/skins/default/xui/it/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php?lang=it - </panel.string> - <panel.string name="sign_up_url"> - http://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Nome utente" name="username_combo" tool_tip="Il nome utente che hai scelto durante la registrazione, come roby12 o Stella Solare"/> - <line_editor label="Password" name="password_edit"/> - <button label="Accedi" name="connect_btn"/> - <check_box label="Ricordami" name="remember_check"/> - <text name="forgot_password_text"> - Password dimenticata - </text> - <text name="sign_up_text"> - Registrati - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Il primo passo è a Learning Island. Trova il portale di uscita! - </text> - <text name="image_caption_right"> - Quindi esplora Social Island e incontra altri nuovi residenti. - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/ja/panel_login_first.xml b/indra/newview/skins/default/xui/ja/panel_login_first.xml deleted file mode 100644 index 0f987fc816..0000000000 --- a/indra/newview/skins/default/xui/ja/panel_login_first.xml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - https://secondlife.com/my/account/request.php?lang=ja-JP - </panel.string> - <panel.string name="sign_up_url"> - https://join.secondlife.com/?lang=ja - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="page_top"/> - <layout_panel name="parent_panel"> - <layout_stack name="logo_stack"> - <layout_panel name="logo_left"/> - <layout_panel name="logo_container"> - <icon name="sl_logo"/> - </layout_panel> - <layout_panel auto_resize="true"/> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_left"/> - <layout_panel name="widget_container"> - <combo_box label="ユーザ名" tool_tip="登録時に自分で選んだユーザー名(例:bobsmith12、Steller Sunshineなど)" name="username_combo"> - <combo_box.combo_editor/> - <combo_box.combo_button/> - <combo_box.drop_down_button/> - </combo_box> - <line_editor name="password_edit" label="パスワード"/> - <button label="ログイン" name="connect_btn"/> - <text name="sign_up_text" valign="center"> - サインアップ - </text> - <check_box label="ユーザ名を記憶" name="remember_name" tool_tip="すでに記憶されているユーザーは、「私」>「初期設定」>「詳細設定」>「記憶されたユーザー名」から削除できます。"/> - <check_box label="パスワード記憶" name="remember_password"/> - <text name="forgot_password_text"> - パスワードを忘れましたか? - </text> - </layout_panel> - <layout_panel name="widget_right"/> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_left"/> - <layout_panel name="images_container"> - <icon name="image_left"/> - </layout_panel> - <layout_panel name="images_right"/> - </layout_stack> - </layout_panel> - <layout_panel name="page_bottom"/> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/pl/panel_login_first.xml b/indra/newview/skins/default/xui/pl/panel_login_first.xml deleted file mode 100644 index 0604ecbcff..0000000000 --- a/indra/newview/skins/default/xui/pl/panel_login_first.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel name="panel_login"> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Użytkownik" tool_tip="Nazwa użytkownika wybrana przy rejestracji, np. bobsmith12 lub Steller Sunshine" name="username_combo" /> - <line_editor name="password_edit" label="Hasło" /> - <button label="Zaloguj" name="connect_btn" /> - <check_box label="Zapamiętaj mnie" name="remember_check" /> - <text name="forgot_password_text"> - Zapomniałem/am hasła - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Wyspa Nauki to Twój pierwszy krok. Znajdź portal z wyjściem! - </text> - <text name="image_caption_right"> - Potem zwiedź Wyspę Towarzyską i poznaj innych nowych rezydentów! - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/pt/panel_login_first.xml b/indra/newview/skins/default/xui/pt/panel_login_first.xml deleted file mode 100644 index 86c61163bc..0000000000 --- a/indra/newview/skins/default/xui/pt/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php?lang=pt - </panel.string> - <panel.string name="sign_up_url"> - https://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Nome de usuário" name="username_combo" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 ou Magia Solar"/> - <line_editor label="Senha" name="password_edit"/> - <button label="Login" name="connect_btn"/> - <check_box label="Lembrar-me" name="remember_check"/> - <text name="forgot_password_text"> - Senha esquecida - </text> - <text name="sign_up_text"> - Cadastre-se - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Sua primeira parada é a Ilha da Educação. Encontre o portal de saída! - </text> - <text name="image_caption_right"> - Em seguida, explore a Ilha Social e encontre novos residentes! - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/ru/panel_login_first.xml b/indra/newview/skins/default/xui/ru/panel_login_first.xml deleted file mode 100644 index 5db81ea7ca..0000000000 --- a/indra/newview/skins/default/xui/ru/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php - </panel.string> - <panel.string name="sign_up_url"> - https://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Имя пользователя" name="username_combo" tool_tip="Имя пользователя, которое вы выбрали при регистрации, например, «bobsmith12» или «Steller Sunshine»"/> - <line_editor label="Пароль" name="password_edit"/> - <button label="Войти" name="connect_btn"/> - <check_box label="Запомнить меня" name="remember_check"/> - <text name="forgot_password_text"> - Забытый пароль - </text> - <text name="sign_up_text"> - Регистрация - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Ваш первый шаг – Учебный остров. Найдите портал выхода! - </text> - <text name="image_caption_right"> - Затем исследуйте Социальный остров и познакомьтесь с другими новичками! - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/tr/panel_login_first.xml b/indra/newview/skins/default/xui/tr/panel_login_first.xml deleted file mode 100644 index 1fc80c2b97..0000000000 --- a/indra/newview/skins/default/xui/tr/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php - </panel.string> - <panel.string name="sign_up_url"> - https://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="Kullanıcı Adı" name="username_combo" tool_tip="Kaydolduğunuzda seçtiğiniz kullanıcı adı, örn. mustafayalcin12 veya Faruk Gungoren"/> - <line_editor label="Parola" name="password_edit"/> - <button label="Oturum Aç" name="connect_btn"/> - <check_box label="Beni hatırla" name="remember_check"/> - <text name="forgot_password_text"> - Parolamı unuttum - </text> - <text name="sign_up_text"> - Kaydol - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - Başlangıç yeriniz Eğitim Adası. Haydi çıkış portalını bulun! - </text> - <text name="image_caption_right"> - Sonra da Sosyal Ada'yı keşfe çıkın ve diğer LS sakinleriyle tanışın! - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> diff --git a/indra/newview/skins/default/xui/zh/panel_login_first.xml b/indra/newview/skins/default/xui/zh/panel_login_first.xml deleted file mode 100644 index 4d72fcdd03..0000000000 --- a/indra/newview/skins/default/xui/zh/panel_login_first.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<panel name="panel_login"> - <panel.string name="forgot_password_url"> - http://secondlife.com/account/request.php - </panel.string> - <panel.string name="sign_up_url"> - http://join.secondlife.com/ - </panel.string> - <layout_stack name="logo_stack"> - <layout_panel name="parent_panel2"> - <layout_stack name="widget_stack"> - <layout_panel name="widget_container"> - <combo_box label="使用者名稱" name="username_combo" tool_tip="使用者名稱是你註冊時所挑選的,例如 bobsmith12 或 Steller Sunshine"/> - <line_editor label="密碼" name="password_edit"/> - <button label="登入" name="connect_btn"/> - <check_box label="記得我" name="remember_check"/> - <text name="forgot_password_text"> - 忘記密碼 - </text> - <text name="sign_up_text"> - 註冊 - </text> - </layout_panel> - </layout_stack> - </layout_panel> - <layout_panel name="parent_panel3"> - <layout_stack name="images_stack"> - <layout_panel name="images_container"> - <text name="image_caption_left"> - 你在「學習島」的第一步。 找到離開的傳送門! - </text> - <text name="image_caption_right"> - 接著,到「社交島」探索,認識新的居民朋友! - </text> - </layout_panel> - </layout_stack> - </layout_panel> - </layout_stack> -</panel> 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 diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c778f1e838..ceb05980a5 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -151,7 +151,6 @@ class ViewerManifest(LLManifest): with self.prefix(src_dst="skins"): # include the entire textures directory recursively with self.prefix(src_dst="*/textures"): - self.path("*/*.jpg") self.path("*/*.png") self.path("*.tga") self.path("*.j2c") @@ -559,6 +558,9 @@ class Windows_x86_64_Manifest(ViewerManifest): ): self.path(libfile) + if self.args['discord'] == 'ON': + self.path("discord_partner_sdk.dll") + if self.args['openal'] == 'ON': # Get openal dll self.path("OpenAL32.dll") @@ -1021,6 +1023,13 @@ class Darwin_x86_64_Manifest(ViewerManifest): ): self.path2basename(relpkgdir, libfile) + # Discord social SDK + if self.args['discord'] == 'ON': + for libfile in ( + "libdiscord_partner_sdk.dylib", + ): + self.path2basename(relpkgdir, libfile) + # OpenAL dylibs if self.args['openal'] == 'ON': for libfile in ( @@ -1825,6 +1834,7 @@ if __name__ == "__main__": extra_arguments = [ dict(name='bugsplat', description="""BugSplat database to which to post crashes, if BugSplat crash reporting is desired""", default=''), + dict(name='discord', description="""Indication discord social sdk libraries are needed""", default='OFF'), dict(name='openal', description="""Indication openal libraries are needed""", default='OFF'), dict(name='tracy', description="""Indication tracy profiler is enabled""", default='OFF'), ] |