diff options
126 files changed, 2007 insertions, 917 deletions
diff --git a/BuildParams b/BuildParams index 27ae40767a..63c2d7321b 100644 --- a/BuildParams +++ b/BuildParams @@ -36,6 +36,7 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks" ################################################################ viewer_channel = "Second Life Test" + ################################################################ # Special packaging parameters. # These parameters can be used to create additional packages diff --git a/autobuild.xml b/autobuild.xml index bb7cc27233..8166a44525 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -800,9 +800,9 @@ <key>archive</key> <map> <key>hash</key> - <string>d5528538e67c710387ae0c061a90cb23</string> + <string>c36808a58384a52672d81593de61f7ff</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76868/730756/fmodstudio-2.01.07.555883-darwin64-555883.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89681/818422/fmodstudio-2.02.03.565082-darwin64-565082.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -812,9 +812,9 @@ <key>archive</key> <map> <key>hash</key> - <string>5283050c22d31877cd9e0afbe6feb9fc</string> + <string>24b86630ccdfb5b3221f90ca7a9704f6</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65398/612630/fmodstudio-2.00.11.546392-linux-546392.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89682/818423/fmodstudio-2.02.03.565082-linux-565082.tar.bz2</string> </map> <key>name</key> <string>linux</string> @@ -824,9 +824,9 @@ <key>archive</key> <map> <key>hash</key> - <string>5a3c78f4a77ae6477986e33836725e8b</string> + <string>24b86630ccdfb5b3221f90ca7a9704f6</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/65399/612631/fmodstudio-2.00.11.546392-linux64-546392.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89682/818423/fmodstudio-2.02.03.565082-linux-565082.tar.bz2</string> </map> <key>name</key> <string>linux64</string> @@ -836,9 +836,9 @@ <key>archive</key> <map> <key>hash</key> - <string>a2bb6eaf51f933993b26a5fe7503a761</string> + <string>96853d91ce4da14e14ea322122629551</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76869/730763/fmodstudio-2.01.07.555883-windows-555883.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89683/818438/fmodstudio-2.02.03.565082-windows-565082.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -848,16 +848,16 @@ <key>archive</key> <map> <key>hash</key> - <string>138d07dd516a9ad5b9787192fe6134dd</string> + <string>58d0cc28a1d90bacefbda48fcd8d379c</string> <key>url</key> - <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/76867/730751/fmodstudio-2.01.07.555883-windows64-555883.tar.bz2</string> + <string>https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/89684/818439/fmodstudio-2.02.03.565082-windows64-565082.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>2.01.07.555883</string> + <string>2.02.03.565082</string> </map> <key>fontconfig</key> <map> diff --git a/doc/contributions.txt b/doc/contributions.txt index e029c29a18..38bdecc557 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -1114,6 +1114,7 @@ Nicky Dasmijn SL-11072 SL-13141 SL-13642 + SL-16438 Nicky Perian OPEN-1 STORM-1087 @@ -1266,6 +1267,8 @@ Robin Cornelius VWR-12763 VWR-12995 VWR-20911 +Rohacan Hirons + SL-14717 Rosco Teardrop Rose Evans Rudee Voom diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 70b3a08473..b0c87b0208 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -661,7 +661,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) return false; } - if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + if (!gDirUtilp->fileExists(filename)) { // File not found, abort. return false; diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp index 08d19209aa..1ad29a3f59 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -63,7 +63,8 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : mSystem(system), mCurrentInternetStreamp(NULL), mFMODInternetStreamChannelp(NULL), -mGain(1.0f) +mGain(1.0f), +mRetryCount(0) { // Number of milliseconds of audio to buffer for the audio card. // Must be larger than the usual Second Life frame stutter time. @@ -83,9 +84,64 @@ mGain(1.0f) LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() { - // nothing interesting/safe to do. + if (mCurrentInternetStreamp) + { + // Isn't supposed to hapen, stream should be clear by now, + // and if it does, we are likely going to crash. + LL_WARNS("FMOD") << "mCurrentInternetStreamp not null on shutdown!" << LL_ENDL; + stop(); + } + + // Kill dead internet streams, if possible + killDeadStreams(); + + if (!mDeadStreams.empty()) + { + // LLStreamingAudio_FMODSTUDIO was inited on startup + // and should be destroyed on shutdown, it should + // wait for streams to die to not cause crashes or + // leaks. + // Ideally we need to wait on some kind of callback + // to release() streams correctly, but 200 ms should + // be enough and we can't wait forever. + LL_INFOS("FMOD") << "Waiting for " << (S32)mDeadStreams.size() << " streams to stop" << LL_ENDL; + for (S32 i = 0; i < 20; i++) + { + const U32 ms_delay = 10; + ms_sleep(ms_delay); // rude, but not many options here + killDeadStreams(); + if (mDeadStreams.empty()) + { + LL_INFOS("FMOD") << "All streams stopped after " << (S32)((i + 1) * ms_delay) << "ms" << LL_ENDL; + break; + } + } + } + + if (!mDeadStreams.empty()) + { + LL_WARNS("FMOD") << "Failed to kill some audio streams" << LL_ENDL; + } } +void LLStreamingAudio_FMODSTUDIO::killDeadStreams() +{ + std::list<LLAudioStreamManagerFMODSTUDIO *>::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMODSTUDIO *streamp = *iter; + if (streamp->stopStream()) + { + LL_INFOS("FMOD") << "Closed dead stream" << LL_ENDL; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } +} void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) { @@ -100,36 +156,24 @@ void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) if (!url.empty()) { - LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; + LL_INFOS("FMOD") << "Starting internet stream: " << url << LL_ENDL; mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); mURL = url; } else { - LL_INFOS() << "Set internet stream to null" << LL_ENDL; + LL_INFOS("FMOD") << "Set internet stream to null" << LL_ENDL; mURL.clear(); } + + mRetryCount = 0; } void LLStreamingAudio_FMODSTUDIO::update() { // Kill dead internet streams, if possible - std::list<LLAudioStreamManagerFMODSTUDIO *>::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMODSTUDIO *streamp = *iter; - if (streamp->stopStream()) - { - LL_INFOS() << "Closed dead stream" << LL_ENDL; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } - } + killDeadStreams(); // Don't do anything if there are no streams playing if (!mCurrentInternetStreamp) @@ -154,10 +198,33 @@ void LLStreamingAudio_FMODSTUDIO::update() setGain(getGain()); mFMODInternetStreamChannelp->setPaused(false); } + mRetryCount = 0; } else if (open_state == FMOD_OPENSTATE_ERROR) { - stop(); + LL_INFOS("FMOD") << "State: FMOD_OPENSTATE_ERROR" + << " Progress: " << U32(progress) + << " Starving: " << S32(starving) + << " Diskbusy: " << S32(diskbusy) << LL_ENDL; + if (mRetryCount < 2) + { + // Retry + std::string url = mURL; + stop(); // might drop mURL, drops mCurrentInternetStreamp + + mRetryCount++; + + if (!url.empty()) + { + LL_INFOS("FMOD") << "Restarting internet stream: " << url << ", attempt " << (mRetryCount + 1) << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); + mURL = url; + } + } + else + { + stop(); + } return; } @@ -181,7 +248,7 @@ void LLStreamingAudio_FMODSTUDIO::update() { if (!strcmp(tag.name, "Sample Rate Change")) { - LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; + LL_INFOS("FMOD") << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); } continue; @@ -195,9 +262,9 @@ void LLStreamingAudio_FMODSTUDIO::update() mFMODInternetStreamChannelp->getPaused(&paused); if (!paused) { - LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; - LL_INFOS() << " (diskbusy=" << diskbusy << ")" << LL_ENDL; - LL_INFOS() << " (progress=" << progress << ")" << LL_ENDL; + LL_INFOS("FMOD") << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; + LL_INFOS("FMOD") << " (diskbusy=" << diskbusy << ")" << LL_ENDL; + LL_INFOS("FMOD") << " (progress=" << progress << ")" << LL_ENDL; mFMODInternetStreamChannelp->setPaused(true); } } @@ -220,14 +287,14 @@ void LLStreamingAudio_FMODSTUDIO::stop() if (mCurrentInternetStreamp) { - LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + LL_INFOS("FMOD") << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; if (mCurrentInternetStreamp->stopStream()) { delete mCurrentInternetStreamp; } else { - LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + LL_WARNS("FMOD") << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; mDeadStreams.push_back(mCurrentInternetStreamp); } mCurrentInternetStreamp = NULL; @@ -246,6 +313,7 @@ void LLStreamingAudio_FMODSTUDIO::pause(int pauseopt) { if (mCurrentInternetStreamp) { + LL_INFOS("FMOD") << "Pausing internet stream" << LL_ENDL; stop(); } } @@ -314,7 +382,7 @@ mReady(false) if (result != FMOD_OK) { - LL_WARNS() << "Couldn't open fmod stream, error " + LL_WARNS("FMOD") << "Couldn't open fmod stream, error " << FMOD_ErrorString(result) << LL_ENDL; mReady = false; @@ -329,7 +397,7 @@ FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() // We need a live and opened stream before we try and play it. if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) { - LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; + LL_WARNS("FMOD") << "No internet stream to start playing!" << LL_ENDL; return NULL; } diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h index 1fc3c54d79..35a7b1226e 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.h +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -59,6 +59,8 @@ public: /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); private: + void killDeadStreams(); + FMOD::System *mSystem; LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; @@ -67,6 +69,7 @@ private: std::string mURL; F32 mGain; + S32 mRetryCount; }; diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index d640556090..9a927ede9a 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -115,6 +115,15 @@ public: else return LLJoint::LOW_PRIORITY; } + virtual S32 getNumJointMotions() + { + if (mJointMotionList) + { + return mJointMotionList->getNumJointMotions(); + } + return 0; + } + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } // called to determine when a motion should be activated/deactivated based on avatar pixel coverage diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index 2dfc3afc7f..aaa9a146d7 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -129,6 +129,9 @@ public: // motions must report their priority level virtual LLJoint::JointPriority getPriority() = 0; + // amount of affected joints + virtual S32 getNumJointMotions() { return 0; }; + // motions must report their blend type virtual LLMotionBlendType getBlendType() = 0; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 3fe8ce5f0e..55a06f8326 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -539,8 +539,6 @@ namespace protected: Globals(); public: - std::ostringstream messageStream; - bool messageStreamInUse; std::string mFatalMessage; void addCallSite(LLError::CallSite&); @@ -557,8 +555,7 @@ namespace }; Globals::Globals() - : messageStream(), - messageStreamInUse(false), + : callSites(), mSettingsConfig(new SettingsConfig()) { @@ -1434,7 +1431,10 @@ namespace LLError if (site.mLevel == LEVEL_ERROR) { g->mFatalMessage = message; - s->mCrashFunction(message); + if (s->mCrashFunction) + { + s->mCrashFunction(message); + } } } } diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 2ca15a31c6..8df818559d 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -107,7 +107,7 @@ LLOSInfo::LLOSInfo() : #if LL_WINDOWS - if (IsWindowsVersionOrGreater(10, 0, 0)) + if (IsWindows10OrGreater()) { mMajorVer = 10; mMinorVer = 0; @@ -240,6 +240,21 @@ LLOSInfo::LLOSInfo() : ubr = data; } } + + if (mBuild >= 22000) + { + // At release Windows 11 version was 10.0.22000.194 + // Windows 10 version was 10.0.19043.1266 + // There is no warranty that Win10 build won't increase, + // so until better solution is found or Microsoft updates + // SDK with IsWindows11OrGreater(), indicate "10/11" + // + // Current alternatives: + // Query WMI's Win32_OperatingSystem for OS string. Slow + // and likely to return 'compatibility' string. + // Check presence of dlls/libs or may be their version. + mOSStringSimple = "Microsoft Windows 10/11"; + } } mOSString = mOSStringSimple; @@ -1222,7 +1237,12 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) LLFILE *dst = NULL; S32 bytes = 0; tmpfile = dstfile + ".t"; - src = gzopen(srcfile.c_str(), "rb"); +#ifdef LL_WINDOWS + llutf16string utf16filename = utf8str_to_utf16str(srcfile); + src = gzopen_w(utf16filename.c_str(), "rb"); +#else + src = gzopen(srcfile.c_str(), "rb"); +#endif if (! src) goto err; dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ if (! dst) goto err; @@ -1256,7 +1276,14 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile) LLFILE *src = NULL; S32 bytes = 0; tmpfile = dstfile + ".t"; - dst = gzopen(tmpfile.c_str(), "wb"); /* Flawfinder: ignore */ + +#ifdef LL_WINDOWS + llutf16string utf16filename = utf8str_to_utf16str(tmpfile); + dst = gzopen_w(utf16filename.c_str(), "wb"); +#else + dst = gzopen(tmpfile.c_str(), "wb"); +#endif + if (! dst) goto err; src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ if (! src) goto err; diff --git a/indra/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp index 7241b3c0c2..675da65af2 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -37,15 +37,22 @@ struct FolderEntry : public LLDictionaryEntry { FolderEntry(const std::string &type_name, // 8 character limit! - bool is_protected) // can the viewer change categories of this type? + bool is_protected, // can the viewer change categories of this type? + bool is_automatic, // always made before first login? + bool is_singleton // should exist as a unique copy under root + ) : LLDictionaryEntry(type_name), - mIsProtected(is_protected) + mIsProtected(is_protected), + mIsAutomatic(is_automatic), + mIsSingleton(is_singleton) { llassert(type_name.length() <= 8); } const bool mIsProtected; + const bool mIsAutomatic; + const bool mIsSingleton; }; class LLFolderDictionary : public LLSingleton<LLFolderDictionary>, @@ -59,50 +66,64 @@ protected: } }; +// Folder types +// +// PROTECTED means that folders of this type can't be moved, deleted +// or otherwise modified by the viewer. +// +// SINGLETON means that there should always be exactly one folder of +// this type, and it should be the root or a child of the root. This +// is true for most types of folders. +// +// AUTOMATIC means that a copy of this folder should be created under +// the root before the user ever logs in, and should never be created +// from the viewer. A missing AUTOMATIC folder should be treated as a +// fatal error by the viewer, since it indicates either corrupted +// inventory or a failure in the inventory services. +// LLFolderDictionary::LLFolderDictionary() { - // TYPE NAME PROTECTED - // |-----------|---------| - addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE)); - addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE)); - addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE)); - addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE)); - addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE)); - addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE)); - addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE)); - addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE)); - addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE)); - addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE)); - addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE)); - addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE)); - addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE)); - addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE)); - addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE)); - addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE)); + // TYPE NAME, PROTECTED, AUTOMATIC, SINGLETON + addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE, TRUE, FALSE)); + addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE, FALSE, FALSE)); + addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE, FALSE, TRUE)); + addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE, FALSE, TRUE)); for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++) { - addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE)); + addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE, FALSE, FALSE)); // Not used } - addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE)); - addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE)); - addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE)); + addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE, FALSE, TRUE)); + addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE, FALSE, FALSE)); + addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE, FALSE, TRUE)); - addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE)); + addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE, FALSE, FALSE)); // Not used? - addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE)); - addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE)); + addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE, FALSE, TRUE)); + addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE, FALSE, FALSE)); - addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE)); + addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE, FALSE, FALSE)); - addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE)); - addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new FolderEntry("stock", FALSE)); - addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE)); + addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE, FALSE, FALSE)); + addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new FolderEntry("stock", FALSE, FALSE, FALSE)); + addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE, FALSE, FALSE)); - addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE)); + addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE, FALSE, TRUE)); - addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE)); + addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE, FALSE, FALSE)); }; // static @@ -126,8 +147,8 @@ const std::string &LLFolderType::lookup(LLFolderType::EType folder_type) } // static -// Only ensembles and plain folders aren't protected. "Protected" means -// you can't change certain properties such as their type. +// Only plain folders and a few other types aren't protected. "Protected" means +// you can't move, deleted, or change certain properties such as their type. bool LLFolderType::lookupIsProtectedType(EType folder_type) { const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); @@ -138,6 +159,32 @@ bool LLFolderType::lookupIsProtectedType(EType folder_type) } return true; } + +// static +// Is this folder type automatically created outside the viewer? +bool LLFolderType::lookupIsAutomaticType(EType folder_type) +{ + const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); + const FolderEntry *entry = dict->lookup(folder_type); + if (entry) + { + return entry->mIsAutomatic; + } + return true; +} + +// static +// Should this folder always exist as a single copy under (or as) the root? +bool LLFolderType::lookupIsSingletonType(EType folder_type) +{ + const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); + const FolderEntry *entry = dict->lookup(folder_type); + if (entry) + { + return entry->mIsSingleton; + } + return true; +} // static bool LLFolderType::lookupIsEnsembleType(EType folder_type) diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h index 85b86f9ce5..1f174520da 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -102,6 +102,8 @@ public: static const std::string& lookup(EType folder_type); static bool lookupIsProtectedType(EType folder_type); + static bool lookupIsAutomaticType(EType folder_type); + static bool lookupIsSingletonType(EType folder_type); static bool lookupIsEnsembleType(EType folder_type); static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index e085fa6ada..62b39d29a4 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2414,7 +2414,14 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) //copy out indices - face.resizeIndices(idx.size()/2); + S32 num_indices = idx.size() / 2; + face.resizeIndices(num_indices); + + if (num_indices > 2 && !face.mIndices) + { + LL_WARNS() << "Failed to allocate " << num_indices << " indices for face index: " << i << " Total: " << face_count << LL_ENDL; + continue; + } if (idx.empty() || face.mNumIndices < 3) { //why is there an empty index list? @@ -2433,6 +2440,13 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) U32 num_verts = pos.size()/(3*2); face.resizeVertices(num_verts); + if (num_verts > 0 && !face.mPositions) + { + LL_WARNS() << "Failed to allocate " << num_verts << " vertices for face index: " << i << " Total: " << face_count << LL_ENDL; + face.resizeIndices(0); + continue; + } + LLVector3 minp; LLVector3 maxp; LLVector2 min_tc; @@ -2534,6 +2548,13 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) if (mdl[i].has("Weights")) { face.allocateWeights(num_verts); + if (!face.mWeights && num_verts) + { + LL_WARNS() << "Failed to allocate " << num_verts << " weights for face index: " << i << " Total: " << face_count << LL_ENDL; + face.resizeIndices(0); + face.resizeVertices(0); + continue; + } LLSD::Binary weights = mdl[i]["Weights"]; @@ -6342,8 +6363,18 @@ void LLVolumeFace::resizeVertices(S32 num_verts) mTexCoords = NULL; } - mNumVertices = num_verts; - mNumAllocatedVertices = num_verts; + + if (mPositions) + { + mNumVertices = num_verts; + mNumAllocatedVertices = num_verts; + } + else + { + // Either num_verts is zero or allocation failure + mNumVertices = 0; + mNumAllocatedVertices = 0; + } // Force update mJointRiggingInfoTab.clear(); @@ -6444,7 +6475,15 @@ void LLVolumeFace::resizeIndices(S32 num_indices) mIndices = NULL; } - mNumIndices = num_indices; + if (mIndices) + { + mNumIndices = num_indices; + } + else + { + // Either num_indices is zero or allocation failure + mNumIndices = 0; + } } void LLVolumeFace::pushIndex(const U16& idx) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index dfa29fb539..33e90555fa 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -198,6 +198,17 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa } LLVolumeFace::VertexMapData::PointMap point_map; + + if (idx_stride <= 0 + || (pos_source && pos_offset >= idx_stride) + || (tc_source && tc_offset >= idx_stride) + || (norm_source && norm_offset >= idx_stride)) + { + // Looks like these offsets should fit inside idx_stride + // Might be good idea to also check idx.getCount()%idx_stride != 0 + LL_WARNS() << "Invalid pos_offset " << pos_offset << ", tc_offset " << tc_offset << " or norm_offset " << norm_offset << LL_ENDL; + return LLModel::BAD_ELEMENT; + } for (U32 i = 0; i < idx.getCount(); i += idx_stride) { diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 622c9edba7..54fdee6901 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -257,6 +257,8 @@ LLFolderView::LLFolderView(const Params& p) mPopupMenuHandle = menu->getHandle(); mViewModelItem->openItem(); + + mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited. } // Destroys the object diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 285bf9f484..eba93beed9 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -132,7 +132,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mCutGeneration(0), mLabelStyle( LLFontGL::NORMAL ), mHasVisibleChildren(FALSE), - mIsFolderComplete(true), mLocalIndentation(p.folder_indentation), mIndentation(0), mItemHeight(p.item_height), @@ -1003,11 +1002,11 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ): mCurHeight(0.f), mTargetHeight(0.f), mAutoOpenCountdown(0.f), + mIsFolderComplete(false), // folder might have children that are not loaded yet. + mAreChildrenInited(false), // folder might have children that are not built yet. mLastArrangeGeneration( -1 ), mLastCalculatedWidth(0) { - // folder might have children that are not loaded yet. Mark it as incomplete until chance to check it. - mIsFolderComplete = false; } void LLFolderViewFolder::updateLabelRotation() @@ -1063,13 +1062,16 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) { // Sort before laying out contents // Note that we sort from the root (CHUI-849) - getRoot()->getFolderViewModel()->sort(this); + if (mAreChildrenInited) + { + getRoot()->getFolderViewModel()->sort(this); + } LL_RECORD_BLOCK_TIME(FTM_ARRANGE); // evaluate mHasVisibleChildren mHasVisibleChildren = false; - if (getViewModelItem()->descendantsPassedFilter()) + if (mAreChildrenInited && getViewModelItem()->descendantsPassedFilter()) { // We have to verify that there's at least one child that's not filtered out bool found = false; @@ -1095,7 +1097,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) mHasVisibleChildren = found; } - if (!mIsFolderComplete) + if (!mIsFolderComplete && mAreChildrenInited) { mIsFolderComplete = getFolderViewModel()->isFolderComplete(this); } diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 616d2e7d86..ee20d048fd 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -116,7 +116,6 @@ protected: F32 mControlLabelRotation; LLFolderView* mRoot; bool mHasVisibleChildren, - mIsFolderComplete, // indicates that some children were not loaded/added yet mIsCurSelection, mDragAndDropTarget, mIsMouseOverTitle, @@ -219,7 +218,10 @@ public: BOOL hasVisibleChildren() { return mHasVisibleChildren; } // true if object can't have children - BOOL isFolderComplete() { return mIsFolderComplete; } + virtual bool isFolderComplete() { return true; } + // true if object can't have children + virtual bool areChildrenInited() { return true; } + virtual void setChildrenInited(bool inited) { } // Call through to the viewed object and return true if it can be // removed. Returns true if it's removed. @@ -334,6 +336,8 @@ protected: S32 mLastArrangeGeneration; S32 mLastCalculatedWidth; bool mNeedsSort; + bool mIsFolderComplete; // indicates that some children were not loaded/added yet + bool mAreChildrenInited; // indicates that no children were initialized public: typedef enum e_recurse_type @@ -385,6 +389,13 @@ public: // destroys this folder, and all children virtual void destroyView(); + // whether known children are fully loaded (arrange sets to true) + virtual bool isFolderComplete() { return mIsFolderComplete; } + + // whether known children are fully built + virtual bool areChildrenInited() { return mAreChildrenInited; } + virtual void setChildrenInited(bool inited) { mAreChildrenInited = inited; } + // extractItem() removes the specified item from the folder, but // doesn't delete it. virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index de644185fd..a63457bdea 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -336,8 +336,7 @@ LLScrollListCtrl::~LLScrollListCtrl() std::for_each(mItemList.begin(), mItemList.end(), DeletePointer()); mItemList.clear(); - std::for_each(mColumns.begin(), mColumns.end(), DeletePairedPointer()); - mColumns.clear(); + clearColumns(); //clears columns and deletes headers delete mIsFriendSignal; } @@ -3011,6 +3010,8 @@ void LLScrollListCtrl::clearColumns() mSortColumns.clear(); mTotalStaticColumnWidth = 0; mTotalColumnPadding = 0; + + dirtyColumns(); // Clears mColumnsIndexed } void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label) diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index cd8e5800b8..656b23fa1e 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -86,6 +86,9 @@ private: bool mCookiesEnabled; bool mPluginsEnabled; bool mJavascriptEnabled; + bool mProxyEnabled; + std::string mProxyHost; + int mProxyPort; bool mDisableGPU; bool mDisableNetworkService; bool mUseMockKeyChain; @@ -123,6 +126,9 @@ MediaPluginBase(host_send_func, host_user_data) mCookiesEnabled = true; mPluginsEnabled = false; mJavascriptEnabled = true; + mProxyEnabled = false; + mProxyHost = ""; + mProxyPort = 0; mDisableGPU = false; mDisableNetworkService = true; mUseMockKeyChain = true; @@ -517,50 +523,58 @@ void MediaPluginCEF::receiveMessage(const char* message_string) } else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) { - if (message_name == "init") - { - // event callbacks from Dullahan - mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); - mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1)); - mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1)); - mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1)); - mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1)); - mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); - mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2)); - mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2)); - mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1)); - mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2)); - mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); - mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1)); - mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this)); - mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this)); - - dullahan::dullahan_settings settings; + if (message_name == "init") + { + // event callbacks from Dullahan + mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1)); + mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1)); + mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1)); + mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1)); + mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); + mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2)); + mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2)); + mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1)); + mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2)); + mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1)); + mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this)); + mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this)); + + dullahan::dullahan_settings settings; #if LL_WINDOWS - // As of CEF version 83+, for Windows versions, we need to tell CEF - // where the host helper process is since this DLL is not in the same - // dir as the executable that loaded it (SLPlugin.exe). The code in - // Dullahan that tried to figure out the location automatically uses - // the location of the exe which isn't helpful so we tell it explicitly. - char cur_dir_str[MAX_PATH]; - GetCurrentDirectoryA(MAX_PATH, cur_dir_str); - settings.host_process_path = std::string(cur_dir_str); + // As of CEF version 83+, for Windows versions, we need to tell CEF + // where the host helper process is since this DLL is not in the same + // dir as the executable that loaded it (SLPlugin.exe). The code in + // Dullahan that tried to figure out the location automatically uses + // the location of the exe which isn't helpful so we tell it explicitly. + char cur_dir_str[MAX_PATH]; + GetCurrentDirectoryA(MAX_PATH, cur_dir_str); + settings.host_process_path = std::string(cur_dir_str); #endif - settings.accept_language_list = mHostLanguage; - - // SL-15560: Product team overruled my change to set the default - // embedded background color to match the floater background - // and set it to white - settings.background_color = 0xffffffff; // white - - settings.cache_enabled = true; - settings.root_cache_path = mRootCachePath; - settings.cache_path = mCachePath; - settings.context_cache_path = mContextCachePath; - settings.cookies_enabled = mCookiesEnabled; + settings.accept_language_list = mHostLanguage; + + // SL-15560: Product team overruled my change to set the default + // embedded background color to match the floater background + // and set it to white + settings.background_color = 0xffffffff; // white + + settings.cache_enabled = true; + settings.root_cache_path = mRootCachePath; + settings.cache_path = mCachePath; + settings.context_cache_path = mContextCachePath; + settings.cookies_enabled = mCookiesEnabled; + + // configure proxy argument if enabled and valid + if (mProxyEnabled && mProxyHost.length()) + { + std::ostringstream proxy_url; + proxy_url << mProxyHost << ":" << mProxyPort; + settings.proxy_host_port = proxy_url.str(); + } settings.disable_gpu = mDisableGPU; #if LL_DARWIN settings.disable_network_service = mDisableNetworkService; @@ -905,6 +919,12 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mDisableGPU = message_in.getValueBoolean("disable"); } + else if (message_name == "proxy_setup") + { + mProxyEnabled = message_in.getValueBoolean("enable"); + mProxyHost = message_in.getValue("host"); + mProxyPort = message_in.getValueS32("port"); + } else if (message_name == "web_security_disabled") { mDisableWebSecurity = message_in.getValueBoolean("disabled"); diff --git a/indra/newview/SecondLife.xib b/indra/newview/SecondLife.xib index ef25c648a7..fbff8fe307 100644 --- a/indra/newview/SecondLife.xib +++ b/indra/newview/SecondLife.xib @@ -340,7 +340,7 @@ <string key="NSMaxSize">{10000000000000, 10000000000000}</string> <string key="NSFrameAutosaveName">Second Life</string> <int key="NSWindowCollectionBehavior">128</int> - <bool key="NSWindowIsRestorable">YES</bool> + <bool key="NSWindowIsRestorable">NO</bool> </object> <object class="NSWindowTemplate" id="979091056"> <int key="NSWindowStyleMask">31</int> diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml index 4f6deb1f98..1a5157838c 100644 --- a/indra/newview/app_settings/key_bindings.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -126,7 +126,6 @@ <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/> <binding key="" mask="NONE" mouse="MMB" command="toggle_voice"/> - <binding key="" mask="NONE" mouse="LMB" command="walk_to"/> </third_person> <sitting> <binding key="A" mask="ALT" command="spin_around_cw"/> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 12f435f931..a40919c1e9 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8385,7 +8385,18 @@ <key>QAModeMetrics</key> <map> <key>Comment</key> - <string>"Enables QA features (logging, faster cycling) for metrics collector"</string> + <string>Enables QA features (logging, faster cycling) for metrics collector</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>QAModeFakeSystemFolderIssues</key> + <map> + <key>Comment</key> + <string>Simulates system folder issues in inventory</string> <key>Persist</key> <integer>1</integer> <key>Type</key> diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 8838b6d0be..668a8025bd 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -605,6 +605,12 @@ FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function RemoveProgFilesOnInst
+# We do not remove whole pervious install folder on install, since
+# there is a chance that viewer was installed into some important
+# folder by intent or accident
+# RMDir /r $INSTDIR is especially unsafe if user installed somewhere
+# like Program Files
+
# Remove old SecondLife.exe to invalidate any old shortcuts to it that may be in non-standard locations. See MAINT-3575
Delete "$INSTDIR\$INSTEXE"
Delete "$INSTDIR\$VIEWER_EXE"
@@ -612,8 +618,23 @@ Delete "$INSTDIR\$VIEWER_EXE" # Remove old shader files first so fallbacks will work. See DEV-5663
RMDir /r "$INSTDIR\app_settings\shaders"
-# Remove skins folder to clean up files removed during development
+# Remove folders to clean up files removed during development
+RMDir /r "$INSTDIR\app_settings"
RMDir /r "$INSTDIR\skins"
+RMDir /r "$INSTDIR\vmp_icons"
+
+# Remove llplugin, plugins can crash or malfunction if they
+# find modules from different versions
+RMDir /r "$INSTDIR\llplugin"
+
+IfErrors 0 PREINSTALLCLEAN
+ StrCmp $SKIP_DIALOGS "true" PREINSTALLCLEAN
+ MessageBox MB_OKCANCEL $(CloseSecondLifeInstRM) IDOK PREINSTALLCLEAN IDCANCEL PREINSTALLFAIL
+
+PREINSTALLFAIL:
+ Quit
+
+PREINSTALLCLEAN:
# We are no longer including release notes with the viewer, so remove them.
Delete "$SMPROGRAMS\$INSTSHORTCUT\SL Release Notes.lnk"
diff --git a/indra/newview/installers/windows/lang_da.nsi b/indra/newview/installers/windows/lang_da.nsi Binary files differindex f462c82078..0b5ae2b714 100644 --- a/indra/newview/installers/windows/lang_da.nsi +++ b/indra/newview/installers/windows/lang_da.nsi diff --git a/indra/newview/installers/windows/lang_de.nsi b/indra/newview/installers/windows/lang_de.nsi index eebcf027a8..e67bc9e22c 100755 --- a/indra/newview/installers/windows/lang_de.nsi +++ b/indra/newview/installers/windows/lang_de.nsi @@ -64,6 +64,7 @@ LangString MissingSSE2 ${LANG_GERMAN} "Dieses Gerät verfügt möglicherweise ni ; closesecondlife function (install)
LangString CloseSecondLifeInstDP ${LANG_GERMAN} "Warten auf die Beendigung von Second Life ..."
LangString CloseSecondLifeInstMB ${LANG_GERMAN} "Second Life kann nicht installiert oder ersetzt werden, wenn es bereits läuft.$\n$\nBeenden Sie, was Sie gerade tun und klicken Sie OK, um Second Life zu beenden.$\nKlicken Sie CANCEL, um die Installation abzubrechen."
+LangString CloseSecondLifeInstRM ${LANG_GERMAN} "Second Life failed to remove some files from a previous install.$\n$\nSelect OK to continue.$\nSelect CANCEL to cancel installation."
; closesecondlife function (uninstall)
LangString CloseSecondLifeUnInstDP ${LANG_GERMAN} "Warten auf die Beendigung von Second Life ..."
diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi Binary files differindex ea680f08e4..f75ecfaf08 100644 --- a/indra/newview/installers/windows/lang_en-us.nsi +++ b/indra/newview/installers/windows/lang_en-us.nsi diff --git a/indra/newview/installers/windows/lang_es.nsi b/indra/newview/installers/windows/lang_es.nsi Binary files differindex 8a81110069..2b9fa61199 100755 --- a/indra/newview/installers/windows/lang_es.nsi +++ b/indra/newview/installers/windows/lang_es.nsi diff --git a/indra/newview/installers/windows/lang_fr.nsi b/indra/newview/installers/windows/lang_fr.nsi Binary files differindex f038c0e419..4e256a3af9 100755 --- a/indra/newview/installers/windows/lang_fr.nsi +++ b/indra/newview/installers/windows/lang_fr.nsi diff --git a/indra/newview/installers/windows/lang_it.nsi b/indra/newview/installers/windows/lang_it.nsi Binary files differindex bd16d8318f..bf4f51e326 100755 --- a/indra/newview/installers/windows/lang_it.nsi +++ b/indra/newview/installers/windows/lang_it.nsi diff --git a/indra/newview/installers/windows/lang_ja.nsi b/indra/newview/installers/windows/lang_ja.nsi Binary files differindex 71edde1992..02d9ae2b40 100755 --- a/indra/newview/installers/windows/lang_ja.nsi +++ b/indra/newview/installers/windows/lang_ja.nsi diff --git a/indra/newview/installers/windows/lang_pl.nsi b/indra/newview/installers/windows/lang_pl.nsi Binary files differindex 865e8bdeee..4c254b4b2c 100644 --- a/indra/newview/installers/windows/lang_pl.nsi +++ b/indra/newview/installers/windows/lang_pl.nsi diff --git a/indra/newview/installers/windows/lang_pt-br.nsi b/indra/newview/installers/windows/lang_pt-br.nsi Binary files differindex 0e7cbeacda..1e9e0b07d2 100755 --- a/indra/newview/installers/windows/lang_pt-br.nsi +++ b/indra/newview/installers/windows/lang_pt-br.nsi diff --git a/indra/newview/installers/windows/lang_ru.nsi b/indra/newview/installers/windows/lang_ru.nsi Binary files differindex d55aacc971..8ca1fc3d14 100755 --- a/indra/newview/installers/windows/lang_ru.nsi +++ b/indra/newview/installers/windows/lang_ru.nsi diff --git a/indra/newview/installers/windows/lang_tr.nsi b/indra/newview/installers/windows/lang_tr.nsi Binary files differindex 4746f84482..db6f417fc2 100755 --- a/indra/newview/installers/windows/lang_tr.nsi +++ b/indra/newview/installers/windows/lang_tr.nsi diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsi Binary files differindex 397bd0ac81..fad714e83b 100755 --- a/indra/newview/installers/windows/lang_zh.nsi +++ b/indra/newview/installers/windows/lang_zh.nsi diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index ed6c3c307f..e10244aad6 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2501,8 +2501,16 @@ void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick) { // focus on object plus designated offset // which may or may not be same as pick.mPosGlobal + // except for rigged items to prevent wrong focus position + if (objectp->isRiggedMesh()) + { + setFocusGlobal(pick.mPosGlobal, pick.mObjectID); + } + else + { setFocusGlobal(objectp->getPositionGlobal() + LLVector3d(pick.mObjectOffset), pick.mObjectID); } + } else { // focus directly on point where user clicked diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index ef56478106..debf93dccd 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -524,6 +524,11 @@ void LLAppCoreHttp::refreshSettings(bool initial) LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url, const LLCore::HttpHandler::ptr_t &handler, void *appdata) { + if (gDisconnected) + { + return LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT); + } + LLCore::HttpStatus result; try { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c9d852686e..60135cb48a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1821,6 +1821,8 @@ bool LLAppViewer::cleanup() if (gAudiop) { + LL_INFOS() << "Shutting down audio" << LL_ENDL; + // be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it. gAudiop->stopInternetStream(); // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. @@ -4294,120 +4296,6 @@ void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb) void LLAppViewer::loadKeyBindings() { std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); -#if 1 - // Legacy support - // Remove #if-#endif section half a year after DRTVWR-501 releases. - // Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in - // settings.xml. To support legacy viewers that were storing in settings.xml we need to - // transfer old variables to new format. - // Also part of backward compatibility is present in LLKeyConflictHandler to modify - // legacy variables on changes in new system (to make sure we won't enforce - // legacy values again if user dropped to defaults in new system) - if (LLVersionInfo::getInstance()->getChannelAndVersion() != gLastRunVersion - || !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet - { - // copy mouse actions and voice key changes to new file - LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL; - // Load settings from file - LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON); - LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING); - - // Since we are only modifying keybindings if personal file doesn't exist yet, - // it should be safe to just overwrite the value - // If key is already in use somewhere by default, LLKeyConflictHandler should resolve it. - BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot"); - third_person_view.registerControl("walk_to", - 0, - value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second - value = gSavedSettings.getBOOL("ClickToWalk"); - third_person_view.registerControl("walk_to", - index, - value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - value = gSavedSettings.getBOOL("DoubleClickTeleport"); - third_person_view.registerControl("teleport_to", - 0, - value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - // sitting also supports teleport - sitting_view.registerControl("teleport_to", - 0, - value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - std::string key_string = gSavedSettings.getString("PushToTalkButton"); - EMouseClickType mouse = EMouseClickType::CLICK_NONE; - KEY key = KEY_NONE; - if (key_string == "MiddleMouse") - { - mouse = EMouseClickType::CLICK_MIDDLE; - } - else if (key_string == "MouseButton4") - { - mouse = EMouseClickType::CLICK_BUTTON4; - } - else if (key_string == "MouseButton5") - { - mouse = EMouseClickType::CLICK_BUTTON5; - } - else - { - LLKeyboard::keyFromString(key_string, &key); - } - - value = gSavedSettings.getBOOL("PushToTalkToggle"); - std::string control_name = value ? "toggle_voice" : "voice_follow_key"; - third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - - if (third_person_view.hasUnsavedChanges()) - { - // calls loadBindingsXML() - third_person_view.saveToSettings(); - } - - if (sitting_view.hasUnsavedChanges()) - { - // calls loadBindingsXML() - sitting_view.saveToSettings(); - } - - // in case of voice we need to repeat this in other modes - - for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) - { - // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment - if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING) - { - LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i); - - handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - - if (handler.hasUnsavedChanges()) - { - // calls loadBindingsXML() - handler.saveToSettings(); - } - } - } - } - // since something might have gone wrong or there might have been nothing to save - // (and because otherwise following code will have to be encased in else{}), - // load everything one last time -#endif if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) { // Failed to load custom bindings, try default ones diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index 0fd6009074..d43048a8b6 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -99,22 +99,22 @@ void LLAttachmentsMgr::onIdle() return; } - if (LLApp::isExiting()) - { - return; - } + if (LLApp::isExiting()) + { + return; + } requestPendingAttachments(); - linkRecentlyArrivedAttachments(); + linkRecentlyArrivedAttachments(); - expireOldAttachmentRequests(); + expireOldAttachmentRequests(); - expireOldDetachRequests(); + expireOldDetachRequests(); - checkInvalidCOFLinks(); - - spamStatusInfo(); + checkInvalidCOFLinks(); + + spamStatusInfo(); } void LLAttachmentsMgr::requestPendingAttachments() @@ -453,51 +453,55 @@ bool LLAttachmentsMgr::isAttachmentStateComplete() const // void LLAttachmentsMgr::checkInvalidCOFLinks() { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), - cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; i<item_array.size(); i++) - { - const LLViewerInventoryItem* inv_item = item_array.at(i).get(); - const LLUUID& item_id = inv_item->getLinkedUUID(); - if (inv_item->getType() == LLAssetType::AT_OBJECT) - { - LLTimer timer; - bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); - bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); - if (is_wearing_attachment && is_flagged_questionable) - { - LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " - << (is_wearing_attachment ? "attached " : "") - <<"removing flag after " - << timer.getElapsedTimeF32() << " item " - << inv_item->getName() << " id " << item_id << LL_ENDL; - mQuestionableCOFLinks.removeTime(item_id); - } - } - } + if (!gInventory.isInventoryUsable()) + { + return; + } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), + cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; i<item_array.size(); i++) + { + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + const LLUUID& item_id = inv_item->getLinkedUUID(); + if (inv_item->getType() == LLAssetType::AT_OBJECT) + { + LLTimer timer; + bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); + bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); + if (is_wearing_attachment && is_flagged_questionable) + { + LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " + << (is_wearing_attachment ? "attached " : "") + <<"removing flag after " + << timer.getElapsedTimeF32() << " item " + << inv_item->getName() << " id " << item_id << LL_ENDL; + mQuestionableCOFLinks.removeTime(item_id); + } + } + } - for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); - it != mQuestionableCOFLinks.end(); ) - { - LLItemRequestTimes::iterator curr_it = it; - ++it; - const LLUUID& item_id = curr_it->first; - LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); - if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) - { - if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) - { - LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " - << curr_it->second.getElapsedTimeF32() << " seconds for " - << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; - LLAppearanceMgr::instance().removeCOFItemLinks(item_id); - } - mQuestionableCOFLinks.erase(curr_it); - continue; - } - } + for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); + it != mQuestionableCOFLinks.end(); ) + { + LLItemRequestTimes::iterator curr_it = it; + ++it; + const LLUUID& item_id = curr_it->first; + LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); + if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) + { + if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) + { + LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " + << curr_it->second.getElapsedTimeF32() << " seconds for " + << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + LLAppearanceMgr::instance().removeCOFItemLinks(item_id); + } + mQuestionableCOFLinks.erase(curr_it); + continue; + } + } } void LLAttachmentsMgr::spamStatusInfo() diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 65cec68884..fee85d50bd 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -89,6 +89,7 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes mFlashStarted(false) { mFlashTimer = new LLFlashTimer(); + mAreChildrenInited = true; // inventory only } LLConversationViewSession::~LLConversationViewSession() diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 507af56cb0..4fe7e516cc 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -958,7 +958,7 @@ void LLDrawable::updateTexture() BOOL LLDrawable::updateGeometry(BOOL priority) { llassert(mVObjp.notNull()); - BOOL res = mVObjp->updateGeometry(this); + BOOL res = mVObjp && mVObjp->updateGeometry(this); return res; } diff --git a/indra/newview/lleventnotifier.cpp b/indra/newview/lleventnotifier.cpp index e3c17f9877..f1a44a68c9 100644 --- a/indra/newview/lleventnotifier.cpp +++ b/indra/newview/lleventnotifier.cpp @@ -36,6 +36,7 @@ #include "llfloaterevent.h" #include "llagent.h" #include "llcommandhandler.h" // secondlife:///app/... support +#include "lltrans.h" class LLEventHandler : public LLCommandHandler { @@ -218,8 +219,40 @@ void LLEventNotifier::load(const LLSD& event_options) end = event_options.endArray(); resp_it != end; ++resp_it) { LLSD response = *resp_it; - - add(response["event_id"].asInteger(), response["event_date_ut"], response["event_date"].asString(), response["event_name"].asString()); + LLDate date; + bool is_iso8601_date = false; + + if (response["event_date"].isDate()) + { + date = response["event_date"].asDate(); + is_iso8601_date = true; + } + else if (date.fromString(response["event_date"].asString())) + { + is_iso8601_date = true; + } + + if (is_iso8601_date) + { + std::string dateStr; + + dateStr = "[" + LLTrans::getString("LTimeYear") + "]-[" + + LLTrans::getString("LTimeMthNum") + "]-[" + + LLTrans::getString("LTimeDay") + "] [" + + LLTrans::getString("LTimeHour") + "]:[" + + LLTrans::getString("LTimeMin") + "]:[" + + LLTrans::getString("LTimeSec") + "]"; + + LLSD substitution; + substitution["datetime"] = date; + LLStringUtil::format(dateStr, substitution); + + add(response["event_id"].asInteger(), response["event_date_ut"], dateStr, response["event_name"].asString()); + } + else + { + add(response["event_id"].asInteger(), response["event_date_ut"], response["event_date"].asString(), response["event_name"].asString()); + } } } diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index cca6b9ce32..c13b63433c 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1927,9 +1927,17 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) pref_changed |= mRecreateFavoriteStorage; mRecreateFavoriteStorage = false; + // Can get called before inventory is done initializing. + if (!gInventory.isInventoryUsable()) + { + return FALSE; + } + LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if (favorite_folder.isNull()) - return FALSE; + { + return FALSE; + } LLInventoryModel::item_array_t items; LLInventoryModel::cat_array_t cats; diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index e075a311c2..a24d1d1436 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -734,11 +734,14 @@ void LLVolumeImplFlexible::preRebuild() void LLVolumeImplFlexible::doFlexibleRebuild(bool rebuild_volume) { LLVolume* volume = mVO->getVolume(); - if(rebuild_volume) - { - volume->setDirty(); - } - volume->regen(); + if (volume) + { + if (rebuild_volume) + { + volume->setDirty(); + } + volume->regen(); + } mUpdated = TRUE; } diff --git a/indra/newview/llfloatereditenvironmentbase.h b/indra/newview/llfloatereditenvironmentbase.h index 7c7cf5bdcd..d900d7f003 100644 --- a/indra/newview/llfloatereditenvironmentbase.h +++ b/indra/newview/llfloatereditenvironmentbase.h @@ -107,7 +107,7 @@ protected: void onAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settins, S32 status); -private: +protected: LLUUID mExpectingAssetId; // for asset load confirmation }; diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp index 281d4f68f5..eb0cd28190 100644 --- a/indra/newview/llfloatereditextdaycycle.cpp +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -98,6 +98,11 @@ namespace { const std::string TABS_SKYS("sky_tabs"); const std::string TABS_WATER("water_tabs"); + // 'Play' buttons + const std::string BTN_PLAY("play_btn"); + const std::string BTN_SKIP_BACK("skip_back_btn"); + const std::string BTN_SKIP_FORWARD("skip_forward_btn"); + const std::string EVNT_DAYTRACK("DayCycle.Track"); const std::string EVNT_PLAY("DayCycle.PlayActions"); @@ -1205,6 +1210,11 @@ void LLFloaterEditExtDayCycle::updateButtons() mDeleteFrameButton->setEnabled(can_manipulate && isRemovingFrameAllowed()); mLoadFrame->setEnabled(can_manipulate); + BOOL enable_play = mEditDay ? TRUE : FALSE; + childSetEnabled(BTN_PLAY, enable_play); + childSetEnabled(BTN_SKIP_BACK, enable_play); + childSetEnabled(BTN_SKIP_FORWARD, enable_play); + // update track buttons bool extended_env = LLEnvironment::instance().isExtendedEnvironmentEnabled(); for (S32 track = 0; track < LLSettingsDay::TRACK_MAX; ++track) @@ -1575,15 +1585,22 @@ void LLFloaterEditExtDayCycle::onIdlePlay(void* user_data) { LLFloaterEditExtDayCycle* self = (LLFloaterEditExtDayCycle*)user_data; - F32 prcnt_played = self->mPlayTimer.getElapsedTimeF32() / DAY_CYCLE_PLAY_TIME_SECONDS; - F32 new_frame = fmod(self->mPlayStartFrame + prcnt_played, 1.f); + if (self->mSkyBlender == nullptr || self->mWaterBlender == nullptr) + { + self->stopPlay(); + } + else + { + + F32 prcnt_played = self->mPlayTimer.getElapsedTimeF32() / DAY_CYCLE_PLAY_TIME_SECONDS; + F32 new_frame = fmod(self->mPlayStartFrame + prcnt_played, 1.f); - self->mTimeSlider->setCurSliderValue(new_frame); // will do the rounding - self->mSkyBlender->setPosition(new_frame); - self->mWaterBlender->setPosition(new_frame); - self->synchronizeTabs(); - self->updateTimeAndLabel(); - self->updateButtons(); + self->mTimeSlider->setCurSliderValue(new_frame); // will do the rounding + + self->synchronizeTabs(); + self->updateTimeAndLabel(); + self->updateButtons(); + } } } diff --git a/indra/newview/llfloatereditextdaycycle.h b/indra/newview/llfloatereditextdaycycle.h index 9a30fb199f..ab5d12fa36 100644 --- a/indra/newview/llfloatereditextdaycycle.h +++ b/indra/newview/llfloatereditextdaycycle.h @@ -194,8 +194,6 @@ private: std::string mLastFrameSlider; bool mShiftCopyEnabled; - LLUUID mExpectingAssetId; - LLButton* mAddFrameButton; LLButton* mDeleteFrameButton; LLButton* mImportButton; diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 9c84fa1991..6cd1648182 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1686,7 +1686,7 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool /* floater processing */ - if (NULL != session_floater) + if (NULL != session_floater && !session_floater->isDead()) { if (session_id != getSelectedSession()) { @@ -1858,11 +1858,14 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c if (widget) { is_widget_selected = widget->isSelected(); - new_selection = mConversationsRoot->getNextFromChild(widget, FALSE); - if (!new_selection) - { - new_selection = mConversationsRoot->getPreviousFromChild(widget, FALSE); - } + if (mConversationsRoot) + { + new_selection = mConversationsRoot->getNextFromChild(widget, FALSE); + if (!new_selection) + { + new_selection = mConversationsRoot->getPreviousFromChild(widget, FALSE); + } + } // Will destroy views and delete models that are not assigned to any views widget->destroyView(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index da01457126..1fc734ae39 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2945,6 +2945,9 @@ void LLPanelPreferenceControls::populateControlTable() LL_WARNS() << "Unimplemented mode" << LL_ENDL; } + // explicit update to make sure table is ready for llsearchableui + pControlsTable->updateColumns(); + // Searchable columns were removed and readded, mark searchables for an update // Note: at the moment tables/lists lack proper llsearchableui support LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index d40a7234e2..b6d856e31b 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -66,7 +66,7 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder ) { LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SORT); - if (!needsSort(folder->getViewModelItem())) return; + if (!folder->areChildrenInited() || !needsSort(folder->getViewModelItem())) return; LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem()); if (modelp->getUUID().isNull()) return; @@ -132,6 +132,16 @@ bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder) return false; } +//virtual +void LLFolderViewModelItemInventory::addChild(LLFolderViewModelItem* child) +{ + LLFolderViewModelItemInventory* model_child = static_cast<LLFolderViewModelItemInventory*>(child); + mLastAddedChildCreationDate = model_child->getCreationDate(); + + // this will requestSort() + LLFolderViewModelItemCommon::addChild(child); +} + void LLFolderViewModelItemInventory::requestSort() { LLFolderViewModelItemCommon::requestSort(); @@ -140,15 +150,31 @@ void LLFolderViewModelItemInventory::requestSort() { folderp->requestArrange(); } - if (static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter().isByDate()) - { - // sort by date potentially affects parent folders which use a date - // derived from newest item in them - if (mParent) - { - mParent->requestSort(); - } - } + LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); + + // Sort by date potentially affects parent folders which use a date + // derived from newest item in them + if (sorter.isByDate() && mParent) + { + // If this is an item, parent needs to be resorted + // This case shouldn't happen, unless someone calls item->requestSort() + if (!folderp) + { + mParent->requestSort(); + } + // if this is a folder, check sort rules for folder first + else if (sorter.isFoldersByDate()) + { + if (mLastAddedChildCreationDate == -1 // nothing was added, some other reason for resort + || mLastAddedChildCreationDate > getCreationDate()) // newer child + { + LLFolderViewModelItemInventory* model_parent = static_cast<LLFolderViewModelItemInventory*>(mParent); + model_parent->mLastAddedChildCreationDate = mLastAddedChildCreationDate; + mParent->requestSort(); + } + } + } + mLastAddedChildCreationDate = -1; } void LLFolderViewModelItemInventory::setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset, std::string::size_type string_size) @@ -387,6 +413,7 @@ bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a, LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model ) : LLFolderViewModelItemCommon(root_view_model), - mPrevPassedAllFilters(false) + mPrevPassedAllFilters(false), + mLastAddedChildCreationDate(-1) { } diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 51b98339c4..de28091c32 100644 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -47,6 +47,7 @@ public: virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual. virtual BOOL isAgentInventory() const { return FALSE; } virtual BOOL isUpToDate() const = 0; + virtual void addChild(LLFolderViewModelItem* child); virtual bool hasChildren() const = 0; virtual LLInventoryType::EType getInventoryType() const = 0; virtual void performAction(LLInventoryModel* model, std::string action) = 0; @@ -63,6 +64,7 @@ public: virtual LLToolDragAndDrop::ESource getDragSource() const = 0; protected: bool mPrevPassedAllFilters; + time_t mLastAddedChildCreationDate; // -1 if nothing was added }; class LLInventorySort @@ -83,6 +85,8 @@ public: } bool isByDate() const { return mByDate; } + bool isFoldersByName() const { return (!mByDate || mFoldersByName) && !mFoldersByWeight; } + bool isFoldersByDate() const { return mByDate && !mFoldersByName && !mFoldersByWeight; } U32 getSortOrder() const { return mSortOrder; } void toParams(Params& p) { p.order(mSortOrder);} void fromParams(Params& p) diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 12d82d101f..9dca509262 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -372,6 +372,11 @@ void LLGroupActions::show(const LLUUID& group_id) params["open_tab_name"] = "panel_group_info_sidetray"; LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params); + LLFloater *floater = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("people"); + if (!floater->isFrontmost()) + { + floater->setVisibleAndFrontmost(TRUE, params); + } } void LLGroupActions::refresh_notices() diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 81b55c1073..342920630b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1888,7 +1888,8 @@ void LLItemBridge::buildDisplayName() const LLStringUtil::toUpper(mSearchableName); //Name set, so trigger a sort - if(mParent) + LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); + if(mParent && !sorter.isByDate()) { mParent->requestSort(); } @@ -2187,7 +2188,8 @@ void LLFolderBridge::buildDisplayName() const LLStringUtil::toUpper(mSearchableName); //Name set, so trigger a sort - if(mParent) + LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); + if(mParent && sorter.isFoldersByName()) { mParent->requestSort(); } @@ -3420,9 +3422,22 @@ void LLFolderBridge::copyOutfitToClipboard() void LLFolderBridge::openItem() { LL_DEBUGS() << "LLFolderBridge::openItem()" << LL_ENDL; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - if(mUUID.isNull()) return; + + LLInventoryPanel* panel = mInventoryPanel.get(); + if (!panel) + { + return; + } + LLInventoryModel* model = getInventoryModel(); + if (!model) + { + return; + } + if (mUUID.isNull()) + { + return; + } + panel->onFolderOpening(mUUID); bool fetching_inventory = model->fetchDescendentsOf(mUUID); // Only change folder type if we have the folder contents. if (!fetching_inventory) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index ba453471c6..bf07793e8b 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include <typeinfo> +#include <random> #include "llinventorymodel.h" @@ -67,6 +68,9 @@ #include "process.h" #endif +#include <algorithm> +#include <boost/algorithm/string/join.hpp> + // 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 = 2; @@ -129,6 +133,54 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) } ///---------------------------------------------------------------------------- +/// Class LLInventoryValidationInfo +///---------------------------------------------------------------------------- +LLInventoryValidationInfo::LLInventoryValidationInfo(): + mFatalErrorCount(0), + mWarningCount(0), + mInitialized(false) +{ +} + +void LLInventoryValidationInfo::toOstream(std::ostream& os) const +{ + os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount; +} + + +std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v) +{ + v.toOstream(os); + return os; +} + +void LLInventoryValidationInfo::asLLSD(LLSD& sd) const +{ + sd["fatal_error_count"] = mFatalErrorCount; + sd["warning_count"] = mWarningCount; + sd["initialized"] = mInitialized; + sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); + if (mMissingRequiredSystemFolders.size()>0) + { + sd["missing_system_folders"] = LLSD::emptyArray(); + for(auto ft: mMissingRequiredSystemFolders) + { + sd["missing_system_folders"].append(LLFolderType::lookup(ft)); + } + } + sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); + if (mDuplicateRequiredSystemFolders.size()>0) + { + sd["duplicate_system_folders"] = LLSD::emptyArray(); + for(auto ft: mDuplicateRequiredSystemFolders) + { + sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); + } + } + +} + +///---------------------------------------------------------------------------- /// Class LLInventoryModel ///---------------------------------------------------------------------------- @@ -160,7 +212,8 @@ LLInventoryModel::LLInventoryModel() mHttpPriorityFG(0), mHttpPriorityBG(0), mCategoryLock(), - mItemLock() + mItemLock(), + mValidationInfo(new LLInventoryValidationInfo) {} @@ -500,12 +553,18 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( } } - if(rv.isNull() && isInventoryUsable() && create_folder) + if(rv.isNull() && create_folder && root_id.notNull()) { - if(root_id.notNull()) + + if (isInventoryUsable()) { return createNewCategory(root_id, preferred_type, LLStringUtil::null); } + else + { + LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type + << " because inventory is not usable" << LL_ENDL; + } } return rv; } @@ -569,20 +628,30 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, const std::string& pname, inventory_func_type callback) { - LLUUID id; - if(!isInventoryUsable()) + if (!isInventoryUsable()) { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " + << preferred_type << LL_ENDL; + // FIXME failing but still returning an id? return id; } if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) { LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; + // FIXME failing but still returning an id? return id; } + if (preferred_type != LLFolderType::FT_NONE) + { + // Ultimately this should only be done for non-singleton + // types. Requires back-end changes to guarantee that others + // already exist. + LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; + } + id.generate(); std::string name = pname; if(!pname.empty()) @@ -612,7 +681,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, request["message"] = "CreateInventoryCategory"; request["payload"] = body; - LL_DEBUGS(LOG_INV) << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); @@ -624,6 +693,10 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return LLUUID::null; } + // FIXME this UDP code path needs to be removed. Requires + // reworking many of the callers to use callbacks rather than + // assuming instant success. + // Add the category to the internal representation LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); @@ -633,6 +706,8 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, accountForUpdate(update); updateCategory(cat); + LL_DEBUGS(LOG_INV) << "Creating category via UDP message CreateInventoryFolder, type " << preferred_type << LL_ENDL; + // Create the category on the server. We do this to prevent people // from munging their protected folders. LLMessageSystem* msg = gMessageSystem; @@ -1711,7 +1786,20 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) mModifyMask |= mask; } - if (referent.notNull() && (mChangedItemIDs.find(referent) == mChangedItemIDs.end())) + bool needs_update = false; + if (referent.notNull()) + { + if (mIsNotifyObservers) + { + needs_update = mChangedItemIDsBacklog.find(referent) == mChangedItemIDsBacklog.end(); + } + else + { + needs_update = mChangedItemIDs.find(referent) == mChangedItemIDs.end(); + } + } + + if (needs_update) { if (mIsNotifyObservers) { @@ -1722,6 +1810,8 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) mChangedItemIDs.insert(referent); } + // Fix me: From DD-81, probably shouldn't be here, instead + // should be somewhere in an observer update_marketplace_category(referent, false); if (mask & LLInventoryObserver::ADD) @@ -2282,11 +2372,11 @@ bool LLInventoryModel::loadSkeleton( } } - LL_INFOS(LOG_INV) << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << good_link_count << " link items were successfully added. " - << recovered_link_count << " links added in recovery. " - << "The corresponding categories were invalidated." << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << LL_ENDL; } } @@ -2312,7 +2402,10 @@ bool LLInventoryModel::loadSkeleton( cat->setVersion(NO_VERSION); LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; } - LL_INFOS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; + if (invalid_categories.size() > 0) + { + LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; + } // At this point, we need to set the known descendents for each // category which successfully cached so that we do not @@ -2600,10 +2693,22 @@ void LLInventoryModel::buildParentChildMap() } } - // 'My Inventory', - // root of the agent's inv found. - // The inv tree is built. - mIsAgentInvUsable = true; + LLPointer<LLInventoryValidationInfo> validation_info = validate(); + if (validation_info->mFatalErrorCount > 0) + { + // Fatal inventory error. Will not be able to engage in many inventory operations. + // This should be followed by an error dialog leading to logout. + LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " + << "Will not be able to do normal inventory operations in this session." + << LL_ENDL; + mIsAgentInvUsable = false; + } + else + { + mIsAgentInvUsable = true; + } + validation_info->mInitialized = true; + mValidationInfo = validation_info; // notifyObservers() has been moved to // llstartup/idle_startup() after this func completes. @@ -2611,11 +2716,6 @@ void LLInventoryModel::buildParentChildMap() // observers start firing. } } - - if (!gInventory.validate()) - { - LL_WARNS(LOG_INV) << "model failed validity check!" << LL_ENDL; - } } // Would normally do this at construction but that's too early @@ -3740,66 +3840,68 @@ void LLInventoryModel::dumpInventory() const } // Do various integrity checks on model, logging issues found and -// returning an overall good/bad flag. -bool LLInventoryModel::validate() const +// returning an overall good/bad flag. +LLPointer<LLInventoryValidationInfo> LLInventoryModel::validate() const { - const S32 MAX_VERBOSE_ERRORS = 40; // too many errors can cause disconect or freeze - S32 error_count = 0; + LLPointer<LLInventoryValidationInfo> validation_info = new LLInventoryValidationInfo; + S32 fatalities = 0; + S32 warnings = 0; if (getRootFolderID().isNull()) { - LL_WARNS() << "no root folder id" << LL_ENDL; - error_count++; + LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; + fatalities++; } if (getLibraryRootFolderID().isNull()) { - LL_WARNS() << "no root folder id" << LL_ENDL; - error_count++; + LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; + fatalities++; } if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) { // ParentChild should be one larger because of the special entry for null uuid. - LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() - << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; - error_count++; + LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() + << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; + warnings++; } S32 cat_lock = 0; S32 item_lock = 0; S32 desc_unknown_count = 0; S32 version_unknown_count = 0; + + typedef std::map<LLFolderType::EType, S32> ft_count_map; + ft_count_map ft_counts_under_root; + ft_count_map ft_counts_elsewhere; + + // Loop over all categories and check. for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) { const LLUUID& cat_id = cit->first; const LLViewerInventoryCategory *cat = cit->second; if (!cat) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "invalid cat" << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "null cat" << LL_ENDL; + warnings++; continue; } + LLUUID topmost_ancestor_id; + // Will leave as null uuid on failure + getObjectTopmostAncestor(cat_id, topmost_ancestor_id); if (cat_id != cat->getUUID()) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + warnings++; } if (cat->getParentUUID().isNull()) { if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" - << getRootFolderID() << ") or library root (" - << getLibraryRootFolderID() << ")" << LL_ENDL; - } + LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + warnings++; } } cat_array_t* cats; @@ -3807,11 +3909,8 @@ bool LLInventoryModel::validate() const getDirectDescendentsOf(cat_id,cats,items); if (!cats || !items) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; + warnings++; continue; } if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) @@ -3820,25 +3919,29 @@ bool LLInventoryModel::validate() const } else if (cats->size() + items->size() != cat->getDescendentCount()) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() - << "] parent " << cat->getParentUUID() - << " cached " << cat->getDescendentCount() - << " expected " << cats->size() << "+" << items->size() - << "=" << cats->size() + items->size() << LL_ENDL; - } - error_count++; + // In the case of library this is not unexpected, since + // different user accounts may be getting the library + // contents from different inventory hosts. + if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + warnings++; + } } if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) { version_unknown_count++; } - if (mCategoryLock.count(cat_id)) + auto cat_lock_it = mCategoryLock.find(cat_id); + if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) { cat_lock++; } - if (mItemLock.count(cat_id)) + auto item_lock_it = mItemLock.find(cat_id); + if (item_lock_it != mItemLock.end() && item_lock_it->second) { item_lock++; } @@ -3848,11 +3951,8 @@ bool LLInventoryModel::validate() const if (!item) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + warnings++; continue; } @@ -3860,13 +3960,10 @@ bool LLInventoryModel::validate() const if (item->getParentUUID() != cat_id) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "wrong parent for " << item_id << " found " - << item->getParentUUID() << " expected " << cat_id - << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + warnings++; } @@ -3874,24 +3971,17 @@ bool LLInventoryModel::validate() const item_map_t::const_iterator it = mItemMap.find(item_id); if (it == mItemMap.end()) { - - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "item " << item_id << " found as child of " - << cat_id << " but not in top level mItemMap" << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + warnings++; } else { LLViewerInventoryItem *top_item = it->second; if (top_item != item) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "item mismatch, item_id " << item_id - << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; - } + LL_WARNS("Inventory") << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; } } @@ -3900,25 +3990,19 @@ bool LLInventoryModel::validate() const bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); if (!found) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; + warnings++; } else { if (topmost_ancestor_id != getRootFolderID() && topmost_ancestor_id != getLibraryRootFolderID()) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "unrecognized top level ancestor for " << item_id - << " got " << topmost_ancestor_id - << " expected " << getRootFolderID() - << " or " << getLibraryRootFolderID() << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + warnings++; } } } @@ -3932,12 +4016,9 @@ bool LLInventoryModel::validate() const getDirectDescendentsOf(parent_id,cats,items); if (!cats) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + warnings++; } else { @@ -3953,49 +4034,66 @@ bool LLInventoryModel::validate() const } if (!found) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; - } + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } + } + } + + // Update count of preferred types + LLFolderType::EType folder_type = cat->getPreferredType(); + bool cat_is_in_library = false; + LLUUID topmost_id; + if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) && topmost_id == getLibraryRootFolderID()) + { + cat_is_in_library = true; + } + if (!cat_is_in_library) + { + if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) + { + ft_counts_under_root[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + else + { + ft_counts_elsewhere[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; } } } } + // Loop over all items and check for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) { const LLUUID& item_id = iit->first; LLViewerInventoryItem *item = iit->second; if (item->getUUID() != item_id) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; - } - error_count++; + LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + warnings++; } const LLUUID& parent_id = item->getParentUUID(); if (parent_id.isNull()) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; - } + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; } - else if (error_count < MAX_VERBOSE_ERRORS) + else { cat_array_t* cats; item_array_t* items; getDirectDescendentsOf(parent_id,cats,items); if (!items) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "item " << item_id << " name [" << item->getName() - << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; - } + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; } else { @@ -4010,89 +4108,169 @@ bool LLInventoryModel::validate() const } if (!found) { - if (error_count < MAX_VERBOSE_ERRORS) - { - LL_WARNS() << "item " << item_id << " name [" << item->getName() - << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; - } + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; } } } - // Link checking - if (error_count < MAX_VERBOSE_ERRORS) - { - if (item->getIsLinkType()) - { - const LLUUID& link_id = item->getUUID(); - const LLUUID& target_id = item->getLinkedUUID(); - LLViewerInventoryItem *target_item = getItem(target_id); - LLViewerInventoryCategory *target_cat = getCategory(target_id); - // Linked-to UUID should have back reference to this link. - if (!hasBacklinkInfo(link_id, target_id)) - { - LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() - << " missing backlink info at target_id " << target_id - << LL_ENDL; - } - // Links should have referents. - if (item->getActualType() == LLAssetType::AT_LINK && !target_item) - { - LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; - } - else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) - { - LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; - } - if (target_item && target_item->getIsLinkType()) - { - LL_WARNS() << "link " << item->getName() << " references a link item " - << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; - } - - // Links should not have backlinks. - std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); - if (range.first != range.second) - { - LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; - } - } - else - { - // Check the backlinks of a non-link item. - const LLUUID& target_id = item->getUUID(); - std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); - for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) - { - const LLUUID& link_id = it->second; - LLViewerInventoryItem *link_item = getItem(link_id); - if (!link_item || !link_item->getIsLinkType()) - { - LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; - } - } - } - } + if (item->getIsLinkType()) + { + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + LLViewerInventoryItem *target_item = getItem(target_id); + LLViewerInventoryCategory *target_cat = getCategory(target_id); + // Linked-to UUID should have back reference to this link. + if (!hasBacklinkInfo(link_id, target_id)) + { + LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; + } + // Links should have referents. + if (item->getActualType() == LLAssetType::AT_LINK && !target_item) + { + LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) + { + LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + if (target_item && target_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + } + + // Links should not have backlinks. + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); + if (range.first != range.second) + { + LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + } + } + else + { + // Check the backlinks of a non-link item. + const LLUUID& target_id = item->getUUID(); + std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + const LLUUID& link_id = it->second; + LLViewerInventoryItem *link_item = getItem(link_id); + if (!link_item || !link_item->getIsLinkType()) + { + LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + } + } + } } - + + // Check system folders + for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; + } + for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; + } + + static LLCachedControl<bool> fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); + static std::default_random_engine e{}; + static std::uniform_int_distribution<> distrib(0, 1); + for (S32 ft=LLFolderType::FT_TEXTURE; ft<LLFolderType::FT_COUNT; ft++) + { + LLFolderType::EType folder_type = static_cast<LLFolderType::EType>(ft); + if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) + { + continue; + } + bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); + bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); + S32 count_under_root = ft_counts_under_root[folder_type]; + S32 count_elsewhere = ft_counts_elsewhere[folder_type]; + if (fake_system_folder_issues) + { + // Force all counts to be either 0 or 2, thus flagged as an error. + count_under_root = 2*distrib(e); + count_elsewhere = 2*distrib(e); + } + if (is_singleton) + { + if (count_under_root==0) + { + LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; + // Need to create, if allowed. + if (is_automatic) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; + fatalities++; + validation_info->mMissingRequiredSystemFolders.insert(LLFolderType::EType(ft)); + } + else + { + // Can create, and will when needed. + warnings++; + } + } + else if (count_under_root > 1) + { + LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; + validation_info->mDuplicateRequiredSystemFolders.insert(LLFolderType::EType(ft)); + fatalities++; + } + if (count_elsewhere > 0) + { + LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; + warnings++; + } + } + } + + if (cat_lock > 0 || item_lock > 0) { - LL_INFOS() << "Found locks on some categories: sub-cat arrays " + LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " << cat_lock << ", item arrays " << item_lock << LL_ENDL; } if (desc_unknown_count != 0) { - LL_INFOS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; + LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; } if (version_unknown_count != 0) { - LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; } - LL_INFOS() << "Validate done, found " << error_count << " errors" << LL_ENDL; + // FIXME need to fail login and tell user to retry, contact support if problem persists. + bool valid = (fatalities == 0); + LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatalities << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL; - return error_count == 0; + validation_info->mFatalErrorCount = fatalities; + validation_info->mWarningCount = warnings; + + return validation_info; +} + +// Provides a unix-style path from root, like "/My Inventory/Clothing/.../myshirt" +std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const +{ + std::vector<std::string> path_elts; + std::map<LLUUID,bool> visited; + while (obj != NULL && !visited[obj->getUUID()]) + { + path_elts.push_back(obj->getName()); + // avoid infinite loop in the unlikely event of a cycle + visited[obj->getUUID()] = true; + obj = getObject(obj->getParentUUID()); + } + std::stringstream s; + std::string delim("/"); + std::reverse(path_elts.begin(), path_elts.end()); + std::string result = "/" + boost::algorithm::join(path_elts, delim); + return result; } ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 4dcd9332be..403b86e318 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -55,7 +55,26 @@ class LLInventoryCategory; class LLMessageSystem; class LLInventoryCollectFunctor; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +///---------------------------------------------------------------------------- +/// LLInventoryValidationInfo +///---------------------------------------------------------------------------- +class LLInventoryValidationInfo: public LLRefCount +{ +public: + LLInventoryValidationInfo(); + void toOstream(std::ostream& os) const; + void asLLSD(LLSD& sd) const; + + + S32 mFatalErrorCount; + S32 mWarningCount; + bool mInitialized; + std::set<LLFolderType::EType> mMissingRequiredSystemFolders; + std::set<LLFolderType::EType> mDuplicateRequiredSystemFolders; +}; +std::ostream& operator<<(std::ostream& s, const LLInventoryValidationInfo& v); + +///---------------------------------------------------------------------------- // LLInventoryModel // // Represents a collection of inventory, and provides efficient ways to access @@ -63,7 +82,7 @@ class LLInventoryCollectFunctor; // NOTE: This class could in theory be used for any place where you need // inventory, though it optimizes for time efficiency - not space efficiency, // probably making it inappropriate for use on tasks. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +///---------------------------------------------------------------------------- class LLInventoryModel { LOG_CLASS(LLInventoryModel); @@ -660,7 +679,9 @@ private: //-------------------------------------------------------------------- public: void dumpInventory() const; - bool validate() const; + LLPointer<LLInventoryValidationInfo> validate() const; + LLPointer<LLInventoryValidationInfo> mValidationInfo; + std::string getFullPath(const LLInventoryObject *obj) const; /** Miscellaneous ** ** diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 05d9fec701..fe7f2c6a43 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -284,17 +284,18 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this)); mInventory->addObserver(mCompletionObserver); - if (mBuildViewsOnInit) + if (mBuildViewsOnInit && mViewsInitialized == VIEWS_UNINITIALIZED) { // Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle. // Initializing views takes a while so always do it onIdle if viewer already loaded. - if (mInventory->isInventoryUsable() - && mViewsInitialized == VIEWS_UNINITIALIZED + if (mInventory->isInventoryUsable() && LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT) { - initializeViews(); + // Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect + const F64 max_time = 20.f; + initializeViews(max_time); } - else if (mViewsInitialized != VIEWS_INITIALIZING) + else { mViewsInitialized = VIEWS_INITIALIZING; gIdleCallbacks.addFunction(onIdle, (void*)this); @@ -499,6 +500,19 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve view_folder = dynamic_cast<LLFolderViewFolder*>(view_item); } + // if folder is not fully initialized (likely due to delayed load on idle) + // and we are not rebuilding, try updating children + if (view_folder + && !view_folder->areChildrenInited() + && ( (mask & LLInventoryObserver::REBUILD) == 0)) + { + LLInventoryObject const* objectp = mInventory->getObject(item_id); + if (objectp) + { + view_item = buildNewViews(item_id, objectp, view_item, BUILD_ONE_FOLDER); + } + } + ////////////////////////////// // LABEL Operation // Empty out the display name for relabel. @@ -539,7 +553,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve if (objectp) { // providing NULL directly avoids unnessesary getItemByID calls - view_item = buildNewViews(item_id, objectp, NULL); + view_item = buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER); } else { @@ -592,7 +606,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve if (objectp) { // providing NULL directly avoids unnessesary getItemByID calls - buildNewViews(item_id, objectp, NULL); + buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER); } // Select any newly created object that has the auto rename at top of folder root set. @@ -744,12 +758,12 @@ void LLInventoryPanel::onIdle(void *userdata) return; LLInventoryPanel *self = (LLInventoryPanel*)userdata; - // Inventory just initialized, do complete build - if (self->mViewsInitialized != VIEWS_INITIALIZED) + if (self->mViewsInitialized <= VIEWS_INITIALIZING) { - self->initializeViews(); + const F64 max_time = 0.001f; // 1 ms, in this case we need only root folders + self->initializeViews(max_time); // Shedules LLInventoryPanel::idle() } - if (self->mViewsInitialized == VIEWS_INITIALIZED) + if (self->mViewsInitialized >= VIEWS_BUILDING) { gIdleCallbacks.deleteFunction(onIdle, (void*)self); } @@ -784,6 +798,49 @@ void LLInventoryPanel::idle(void* user_data) } + bool in_visible_chain = panel->isInVisibleChain(); + + if (!panel->mBuildViewsQueue.empty()) + { + const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms + F64 curent_time = LLTimer::getTotalSeconds(); + panel->mBuildViewsEndTime = curent_time + max_time; + + // things added last are closer to root thus of higher priority + std::deque<LLUUID> priority_list; + priority_list.swap(panel->mBuildViewsQueue); + + while (curent_time < panel->mBuildViewsEndTime + && !priority_list.empty()) + { + LLUUID item_id = priority_list.back(); + priority_list.pop_back(); + + LLInventoryObject const* objectp = panel->mInventory->getObject(item_id); + if (objectp && panel->typedViewsFilter(item_id, objectp)) + { + LLFolderViewItem* folder_view_item = panel->getItemByID(item_id); + if (!folder_view_item || !folder_view_item->areChildrenInited()) + { + const LLUUID &parent_id = objectp->getParentUUID(); + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)panel->getItemByID(parent_id); + panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT); + } + } + curent_time = LLTimer::getTotalSeconds(); + } + while (!priority_list.empty()) + { + // items in priority_list are of higher priority + panel->mBuildViewsQueue.push_back(priority_list.front()); + priority_list.pop_front(); + } + if (panel->mBuildViewsQueue.empty()) + { + panel->mViewsInitialized = VIEWS_INITIALIZED; + } + } + // Take into account the fact that the root folder might be invalidated if (panel->mFolderRoot.get()) { @@ -814,10 +871,16 @@ void LLInventoryPanel::idle(void* user_data) } -void LLInventoryPanel::initializeViews() +void LLInventoryPanel::initializeViews(F64 max_time) { if (!gInventory.isInventoryUsable()) return; + mViewsInitialized = VIEWS_BUILDING; + + F64 curent_time = LLTimer::getTotalSeconds(); + mBuildViewsEndTime = curent_time + max_time; + + // init everything LLUUID root_id = getRootFolderID(); if (root_id.notNull()) { @@ -825,14 +888,18 @@ void LLInventoryPanel::initializeViews() } else { - // Default case: always add "My Inventory" first, "Library" second + // Default case: always add "My Inventory" root first, "Library" root second + // If we run out of time, this still should create root folders buildNewViews(gInventory.getRootFolderID()); // My Inventory buildNewViews(gInventory.getLibraryRootFolderID()); // Library } - gIdleCallbacks.addFunction(idle, this); + if (mBuildViewsQueue.empty()) + { + mViewsInitialized = VIEWS_INITIALIZED; + } - mViewsInitialized = VIEWS_INITIALIZED; + gIdleCallbacks.addFunction(idle, this); openStartFolderOrMyInventory(); @@ -911,10 +978,13 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO LLFolderViewItem* folder_view_item = getItemByID(id); LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); - return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); + return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT); } -LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item) +LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, + LLInventoryObject const* objectp, + LLFolderViewItem *folder_view_item, + const EBuildModes &mode) { if (!objectp) { @@ -929,14 +999,15 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO const LLUUID &parent_id = objectp->getParentUUID(); LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); - return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); + return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, mode); } LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, const LLUUID& parent_id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item, - LLFolderViewFolder *parent_folder) + LLFolderViewFolder *parent_folder, + const EBuildModes &mode) { // Force the creation of an extra root level folder item if required by the inventory panel (default is "false") bool allow_drop = true; @@ -1037,9 +1108,64 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, } } + bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY; + + if (create_children) + { + switch (mode) + { + case BUILD_TIMELIMIT: + { + F64 curent_time = LLTimer::getTotalSeconds(); + // If function is out of time, we want to shedule it into mBuildViewsQueue + // If we have time, no matter how little, create views for all children + // + // This creates children in 'bulk' to make sure folder has either + // 'empty and incomplete' or 'complete' states with nothing in between. + // Folders are marked as mIsFolderComplete == false by default, + // later arrange() will update mIsFolderComplete by child count + if (mBuildViewsEndTime < curent_time) + { + create_children = false; + // run it again for the sake of creating children + mBuildViewsQueue.push_back(id); + } + else + { + create_children = true; + folder_view_item->setChildrenInited(true); + } + break; + } + case BUILD_NO_CHILDREN: + { + create_children = false; + // run it to create children, current caller is only interested in current view + mBuildViewsQueue.push_back(id); + break; + } + case BUILD_ONE_FOLDER: + { + // This view loads chindren, following ones don't + // Note: Might be better idea to do 'depth' instead, + // It also will help to prioritize root folder's content + create_children = true; + folder_view_item->setChildrenInited(true); + break; + } + case BUILD_NO_LIMIT: + default: + { + // keep working till everything exists + create_children = true; + folder_view_item->setChildrenInited(true); + } + } + } + // If this is a folder, add the children of the folder and recursively add any // child folders. - if (folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY) + if (create_children) { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; @@ -1055,7 +1181,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, ++cat_iter) { const LLViewerInventoryCategory* cat = (*cat_iter); - if (typedViewsFilter(cat->getUUID(), cat)) + if (typedViewsFilter(cat->getUUID(), cat)) { if (has_folders) { @@ -1063,11 +1189,11 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, // each time, especially since content is growing, we can just // iter over copy of mItemMap in some way LLFolderViewItem* view_itemp = getItemByID(cat->getUUID()); - buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp); + buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode)); } else { - buildViewsTree(cat->getUUID(), id, cat, NULL, parentp); + buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode)); } } } @@ -1079,17 +1205,16 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, item_iter != items->end(); ++item_iter) { + // At the moment we have to build folder's items in bulk and ignore mBuildViewsEndTime const LLViewerInventoryItem* item = (*item_iter); if (typedViewsFilter(item->getUUID(), item)) { - // This can be optimized: we don't need to call getItemByID() // each time, especially since content is growing, we can just // iter over copy of mItemMap in some way LLFolderViewItem* view_itemp = getItemByID(item->getUUID()); - buildViewsTree(item->getUUID(), id, item, view_itemp, parentp); + buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode); } - } } mInventory->unlockDirectDescendentArrays(id); @@ -1202,6 +1327,18 @@ void LLInventoryPanel::onFocusReceived() LLPanel::onFocusReceived(); } +void LLInventoryPanel::onFolderOpening(const LLUUID &id) +{ + LLFolderViewItem* folder = getItemByID(id); + if (folder && !folder->areChildrenInited()) + { + // Last item in list will be processed first. + // This might result in dupplicates in list, but it + // isn't critical, views won't be created twice + mBuildViewsQueue.push_back(id); + } +} + bool LLInventoryPanel::addBadge(LLBadge * badge) { bool badge_added = false; @@ -1223,7 +1360,7 @@ void LLInventoryPanel::openAllFolders() void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) { // Don't select objects in COF (e.g. to prevent refocus when items are worn). - const LLInventoryObject *obj = gInventory.getObject(obj_id); + const LLInventoryObject *obj = mInventory->getObject(obj_id); if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF()) { return; @@ -1260,6 +1397,12 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it if (view_model) { LLUUID id = view_model->getUUID(); + if (!(*it)->areChildrenInited()) + { + const F64 max_time = 0.0001f; + mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time; + buildNewViews(id); + } LLViewerInventoryItem* inv_item = mInventory->getItem(id); if (inv_item && !inv_item->isFinished()) @@ -1717,7 +1860,17 @@ LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id) void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL take_keyboard_focus ) { LLFolderViewItem* itemp = getItemByID(obj_id); - if(itemp && itemp->getViewModelItem() && itemp->passedFilter()) + + if (itemp && !itemp->areChildrenInited()) + { + LLInventoryObject const* objectp = mInventory->getObject(obj_id); + if (objectp) + { + buildNewViews(obj_id, objectp, itemp, BUILD_ONE_FOLDER); + } + } + + if(itemp && itemp->getViewModelItem()) { itemp->arrangeAndSet(TRUE, take_keyboard_focus); mSelectThisID.setNull(); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index a019fc2231..552c61b915 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -171,6 +171,7 @@ public: // LLUICtrl methods /*virtual*/ void onFocusLost(); /*virtual*/ void onFocusReceived(); + void onFolderOpening(const LLUUID &id); // LLBadgeHolder methods bool addBadge(LLBadge * badge); @@ -318,12 +319,9 @@ private: //-------------------------------------------------------------------- public: void addHideFolderType(LLFolderType::EType folder_type); - -public: - bool getViewsInitialized() const { return mViewsInitialized == VIEWS_INITIALIZED; } protected: // Builds the UI. Call this once the inventory is usable. - void initializeViews(); + void initializeViews(F64 max_time); // Specific inventory colors static bool sColorSetInitialized; @@ -331,13 +329,25 @@ protected: static LLUIColor sDefaultHighlightColor; static LLUIColor sLibraryColor; static LLUIColor sLinkColor; - + + enum EBuildModes + { + BUILD_NO_LIMIT, + BUILD_TIMELIMIT, // requires mBuildViewsEndTime + BUILD_ONE_FOLDER, + BUILD_NO_CHILDREN, + }; + + // All buildNewViews() use BUILD_TIMELIMIT by default + // and expect time limit mBuildViewsEndTime to be set LLFolderViewItem* buildNewViews(const LLUUID& id); LLFolderViewItem* buildNewViews(const LLUUID& id, LLInventoryObject const* objectp); LLFolderViewItem* buildNewViews(const LLUUID& id, LLInventoryObject const* objectp, - LLFolderViewItem *target_view); + LLFolderViewItem *target_view, + const EBuildModes &mode = BUILD_TIMELIMIT); + // if certain types are not allowed, no reason to create views virtual bool typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp) { return true; } @@ -354,17 +364,21 @@ private: const LLUUID& parent_id, LLInventoryObject const* objectp, LLFolderViewItem *target_view, - LLFolderViewFolder *parent_folder_view); + LLFolderViewFolder *parent_folder_view, + const EBuildModes &mode); typedef enum e_views_initialization_state { VIEWS_UNINITIALIZED = 0, VIEWS_INITIALIZING, + VIEWS_BUILDING, // Root folder exists VIEWS_INITIALIZED, } EViewsInitializationState; bool mBuildViewsOnInit; EViewsInitializationState mViewsInitialized; // Whether views have been generated + F64 mBuildViewsEndTime; // Stop building views past this timestamp + std::deque<LLUUID> mBuildViewsQueue; }; /************************************************************************/ diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index b6107eeedf..b5ac94b1cd 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -619,74 +619,11 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) } } -#if 1 - // Legacy support - // Remove #if-#endif section half a year after DRTVWR-501 releases. - // Update legacy settings in settings.xml - // We only care for third person view since legacy settings can't store - // more than one mode. - // We are saving this even if we are in temporary mode - preferences - // will restore values on cancel - if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges) - { - bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE); - gSavedSettings.setBOOL("DoubleClickAutoPilot", value); - - value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE); - gSavedSettings.setBOOL("ClickToWalk", value); - - // new method can save both toggle and push-to-talk values simultaneously, - // but legacy one can save only one. It also doesn't support mask. - LLKeyData data = getControl("toggle_voice", 0); - bool can_toggle = !data.isEmpty(); - if (!can_toggle) - { - data = getControl("voice_follow_key", 0); - } - - gSavedSettings.setBOOL("PushToTalkToggle", can_toggle); - if (data.isEmpty()) - { - // legacy viewer has a bug that might crash it if NONE value is assigned. - // just reset to default - gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false); - } - else - { - if (data.mKey != KEY_NONE) - { - gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey)); - } - else - { - std::string ctrl_value; - switch (data.mMouse) - { - case CLICK_MIDDLE: - ctrl_value = "MiddleMouse"; - break; - case CLICK_BUTTON4: - ctrl_value = "MouseButton4"; - break; - case CLICK_BUTTON5: - ctrl_value = "MouseButton5"; - break; - default: - ctrl_value = "MiddleMouse"; - break; - } - gSavedSettings.setString("PushToTalkButton", ctrl_value); - } - } - } -#endif - if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges) { // Map floater should react to doubleclick if doubleclick for teleport is set - // Todo: Seems conterintuitive for map floater to share inworld controls - // after these changes release, discuss with UI UX engineer if this should just - // be set to 1 by default (before release this also doubles as legacy support) + // Todo: Seems conterintuitive for map floater to share inworld controls, + // discuss with UI UX engineer if this should just be set to 1 by default bool value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE); gSavedSettings.setBOOL("DoubleClickTeleport", value); } diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 89eb941106..583742f970 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -466,7 +466,7 @@ S32 LLMachineID::init() } } #else - unsigned char * staticPtr = (unsigned char *)(&static_legacy_id[0]); + unsigned char * staticPtr = (unsigned char *)(&static_unique_id[0]); ret_code = LLUUID::getNodeID(staticPtr); has_static_unique_id = true; has_static_legacy_id = false; diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index c63d04cd55..ab32ea3956 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -305,8 +305,11 @@ BOOL LLPanelGroupNotices::postBuild() void LLPanelGroupNotices::activate() { - if(mNoticesList) - mNoticesList->deleteAllItems(); + if (mNoticesList) + { + mNoticesList->deleteAllItems(); + mKnownNoticeIds.clear(); + } mPrevSelectedNotice = LLUUID(); @@ -413,6 +416,7 @@ void LLPanelGroupNotices::onClickSendMessage(void* data) row["columns"][4]["value"] = llformat( "%u", timestamp); self->mNoticesList->addElement(row, ADD_BOTTOM); + self->mKnownNoticeIds.insert(id); self->mCreateMessage->clear(); self->mCreateSubject->clear(); @@ -443,27 +447,13 @@ void LLPanelGroupNotices::onClickNewMessage(void* data) void LLPanelGroupNotices::refreshNotices() { onClickRefreshNotices(this); - /* - LL_DEBUGS() << "LLPanelGroupNotices::onClickGetPastNotices" << LL_ENDL; - - mNoticesList->deleteAllItems(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupNoticesListRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("GroupID",self->mGroupID); - gAgent.sendReliableMessage(); - */ - } void LLPanelGroupNotices::clearNoticeList() { mPrevSelectedNotice = mNoticesList->getStringUUIDSelectedItem(); mNoticesList->deleteAllItems(); + mKnownNoticeIds.clear(); } void LLPanelGroupNotices::onClickRefreshNotices(void* data) @@ -541,13 +531,14 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) return; } - //with some network delays we can receive notice list more then once... - //so add only unique notices - S32 pos = mNoticesList->getItemIndex(id); + // Due to some network delays we can receive notice list more than once... + // So add only unique notices + if (mKnownNoticeIds.find(id) != mKnownNoticeIds.end()) + { + // If items with this ID already in the list - skip it + continue; + } - if(pos!=-1)//if items with this ID already in the list - skip it - continue; - msg->getString("Data","Subject",subj,i); msg->getString("Data","FromName",name,i); msg->getBOOL("Data","HasAttachment",has_attachment,i); @@ -582,6 +573,7 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) row["columns"][4]["value"] = llformat( "%u", timestamp); mNoticesList->addElement(row, ADD_BOTTOM); + mKnownNoticeIds.insert(id); } mNoticesList->setNeedsSort(save_sort); diff --git a/indra/newview/llpanelgroupnotices.h b/indra/newview/llpanelgroupnotices.h index 46c8c241c6..55319cb9ae 100644 --- a/indra/newview/llpanelgroupnotices.h +++ b/indra/newview/llpanelgroupnotices.h @@ -110,6 +110,7 @@ private: LLIconCtrl *mViewInventoryIcon; LLScrollListCtrl *mNoticesList; + std::set<LLUUID> mKnownNoticeIds; // Dupplicate avoidance, to avoid searching and inserting dupplciates into mNoticesList std::string mNoNoticesStr; diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index 880323ce16..834e664723 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -371,6 +371,11 @@ void LLPanelLandmarkInfo::toggleLandmarkEditMode(BOOL enabled) setFocus(TRUE); } +void LLPanelLandmarkInfo::setCanEdit(BOOL enabled) +{ + getChild<LLButton>("edit_btn")->setEnabled(enabled); +} + const std::string& LLPanelLandmarkInfo::getLandmarkTitle() const { return mLandmarkTitleEditor->getText(); diff --git a/indra/newview/llpanellandmarkinfo.h b/indra/newview/llpanellandmarkinfo.h index f727f286b5..46e2a1935b 100644 --- a/indra/newview/llpanellandmarkinfo.h +++ b/indra/newview/llpanellandmarkinfo.h @@ -56,6 +56,7 @@ public: void displayItemInfo(const LLInventoryItem* pItem); void toggleLandmarkEditMode(BOOL enabled); + void setCanEdit(BOOL enabled); const std::string& getLandmarkTitle() const; const std::string getLandmarkNotes() const; diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index e698a61fef..ce17da3076 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -438,8 +438,14 @@ void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list LLPlacesFolderView* root_folder = dynamic_cast<LLPlacesFolderView*>(inventory_list->getRootFolder()); if (root_folder) { - root_folder->setupMenuHandle(LLInventoryType::IT_CATEGORY, mGearFolderMenu->getHandle()); - root_folder->setupMenuHandle(LLInventoryType::IT_LANDMARK, mGearLandmarkMenu->getHandle()); + if (mGearFolderMenu) + { + root_folder->setupMenuHandle(LLInventoryType::IT_CATEGORY, mGearFolderMenu->getHandle()); + } + if (mGearLandmarkMenu) + { + root_folder->setupMenuHandle(LLInventoryType::IT_LANDMARK, mGearLandmarkMenu->getHandle()); + } root_folder->setParentLandmarksPanel(this); } @@ -462,13 +468,23 @@ void LLLandmarksPanel::initListCommandsHandlers() mSortingMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_sorting.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mAddMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mGearLandmarkMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); - mGearFolderMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); + if (mGearLandmarkMenu) + { + mGearLandmarkMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); + // show menus even if all items are disabled + mGearLandmarkMenu->setAlwaysShowMenu(TRUE); + } // Else corrupted files? + + if (mGearFolderMenu) + { + mGearFolderMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2)); + mGearFolderMenu->setAlwaysShowMenu(TRUE); + } - // show menus even if all items are disabled - mGearLandmarkMenu->setAlwaysShowMenu(TRUE); - mGearFolderMenu->setAlwaysShowMenu(TRUE); - mAddMenu->setAlwaysShowMenu(TRUE); + if (mAddMenu) + { + mAddMenu->setAlwaysShowMenu(TRUE); + } } void LLLandmarksPanel::updateMenuVisibility(LLUICtrl* menu) @@ -1054,7 +1070,10 @@ void LLLandmarksPanel::doShowOnMap(LLLandmark* landmark) LLFloaterReg::showInstance("world_map", "center"); } - mGearLandmarkMenu->setItemEnabled("show_on_map", TRUE); + if (mGearLandmarkMenu) + { + mGearLandmarkMenu->setItemEnabled("show_on_map", TRUE); + } } void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark, diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 1a1792fb60..89256b40c4 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -162,7 +162,6 @@ BOOL LLPanelMainInventory::postBuild() recent_items_panel->setSinceLogoff(TRUE); recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - recent_items_panel->setFilterLinks(LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS); LLInventoryFilter& recent_filter = recent_items_panel->getFilter(); recent_filter.setFilterObjectTypes(recent_filter.getFilterObjectTypes() & ~(0x1 << LLInventoryType::IT_CATEGORY)); recent_filter.setEmptyLookupMessage("InventoryNoMatchingRecentItems"); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 9c67ec40fe..69f181e1b3 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -469,10 +469,15 @@ void LLPanelPlaces::onOpen(const LLSD& key) { mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); - LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); + LLUUID id = key["id"].asUUID(); + LLInventoryItem* item = gInventory.getItem(id); if (!item) return; + BOOL is_editable = gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()) + && item->getPermissions().allowModifyBy(gAgent.getID()); + mLandmarkInfo->setCanEdit(is_editable); + setItem(item); } else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index b41aa2be1a..9ac15d1639 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -104,7 +104,7 @@ public: // llview /*virtual*/ void draw(); - void refreshFromItem(); + virtual void refreshFromItem(); // We can't modify Item or description in preview if either in-world Object // or Item itself is unmodifiable diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 12ac9e6fc5..7f01438425 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -35,11 +35,13 @@ #include "llkeyframemotion.h" #include "llfilepicker.h" #include "lllineeditor.h" +#include "lltrans.h" #include "lluictrlfactory.h" #include "lluictrlfactory.h" #include "lldatapacker.h" extern LLAgent gAgent; +const S32 ADVANCED_VPAD = 3; LLPreviewAnim::LLPreviewAnim(const LLSD& key) : LLPreview( key ) @@ -50,20 +52,19 @@ LLPreviewAnim::LLPreviewAnim(const LLSD& key) // virtual BOOL LLPreviewAnim::postBuild() { - const LLInventoryItem* item = getItem(); - if(item) - { - gAgentAvatarp->createMotion(item->getAssetUUID()); // preload the animation - getChild<LLUICtrl>("desc")->setValue(item->getDescription()); - } - childSetCommitCallback("desc", LLPreview::onText, this); getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); + getChild<LLTextBox>("adv_trigger")->setClickedCallback(boost::bind(&LLPreviewAnim::showAdvanced, this)); + pAdvancedStatsTextBox = getChild<LLTextBox>("AdvancedStats"); + + // Assume that advanced stats start visible (for XUI preview tool's purposes) + pAdvancedStatsTextBox->setVisible(FALSE); + LLRect rect = getRect(); + reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); return LLPreview::postBuild(); } -// static // llinventorybridge also calls into here void LLPreviewAnim::play(const LLSD& param) { @@ -161,14 +162,28 @@ void LLPreviewAnim::draw() } // virtual +void LLPreviewAnim::refreshFromItem() +{ + const LLInventoryItem* item = getItem(); + if (!item) + { + return; + } + + // Preload motion + gAgentAvatarp->createMotion(item->getAssetUUID()); + + LLPreview::refreshFromItem(); +} + void LLPreviewAnim::cleanup() { this->mItemID = LLUUID::null; this->mDidStart = false; getChild<LLUICtrl>("Inworld")->setValue(FALSE); getChild<LLUICtrl>("Locally")->setValue(FALSE); - getChild<LLUICtrl>("Inworld")->setEnabled(true); - getChild<LLUICtrl>("Locally")->setEnabled(true); + getChild<LLUICtrl>("Inworld")->setEnabled(TRUE); + getChild<LLUICtrl>("Locally")->setEnabled(TRUE); } // virtual @@ -182,3 +197,41 @@ void LLPreviewAnim::onClose(bool app_quitting) gAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP); } } + +void LLPreviewAnim::showAdvanced() +{ + BOOL was_visible = pAdvancedStatsTextBox->getVisible(); + + if (was_visible) + { + pAdvancedStatsTextBox->setVisible(FALSE); + LLRect rect = getRect(); + reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); + } + else + { + pAdvancedStatsTextBox->setVisible(TRUE); + LLRect rect = getRect(); + reshape(rect.getWidth(), rect.getHeight() + pAdvancedStatsTextBox->getRect().getHeight() + ADVANCED_VPAD, FALSE); + + LLMotion *motion = NULL; + const LLInventoryItem* item = getItem(); + if (item) + { + // if motion exists, will return existing one. + // Needed because viewer can purge motions + motion = gAgentAvatarp->createMotion(item->getAssetUUID()); + } + + // set text + if (motion) + { + pAdvancedStatsTextBox->setTextArg("[PRIORITY]", llformat("%d", motion->getPriority())); + pAdvancedStatsTextBox->setTextArg("[DURATION]", llformat("%.2f", motion->getDuration())); + pAdvancedStatsTextBox->setTextArg("[EASE_IN]", llformat("%.2f", motion->getEaseInDuration())); + pAdvancedStatsTextBox->setTextArg("[EASE_OUT]", llformat("%.2f", motion->getEaseOutDuration())); + pAdvancedStatsTextBox->setTextArg("[IS_LOOP]", (motion->getLoop() ? LLTrans::getString("PermYes") : LLTrans::getString("PermNo"))); + pAdvancedStatsTextBox->setTextArg("[NUM_JOINTS]", llformat("%d", motion->getNumJointMotions())); + } + } +} diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index 8eaed6ca1f..9f4ad4fa69 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -30,21 +30,28 @@ #include "llpreview.h" #include "llcharacter.h" +class LLMotion; +class LLTextBox; + class LLPreviewAnim : public LLPreview { public: LLPreviewAnim(const LLSD& key); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onClose(bool app_quitting); - void draw(); - void cleanup(); + BOOL postBuild() override; + void onClose(bool app_quitting) override; + void draw() override; + void refreshFromItem() override; + + void cleanup(); // cleanup 'playing' state void play(const LLSD& param); - + void showAdvanced(); + protected: - LLUUID mItemID; + LLUUID mItemID; // Not an item id, but a playing asset id bool mDidStart; + LLTextBox* pAdvancedStatsTextBox; }; #endif // LL_LLPREVIEWANIM_H diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index b0a566755f..7ed2d7ef62 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1368,9 +1368,11 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & } break; case SELECT_TYPE_HUD: - case SELECT_TYPE_WORLD: mGridScale = LLVector3(1.f, 1.f, 1.f) * llmin(gSavedSettings.getF32("GridResolution"), 0.5f); break; + case SELECT_TYPE_WORLD: + mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution"); + break; } } llassert(mGridOrigin.isFinite()); diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index 4b36822e9a..74844a80e8 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -96,7 +96,7 @@ BOOL LLSetKeyBindDialog::postBuild() getChild<LLUICtrl>("Cancel")->setFocus(TRUE); pCheckBox = getChild<LLCheckBoxCtrl>("apply_all"); - pDesription = getChild<LLTextBase>("descritption"); + pDescription = getChild<LLTextBase>("description"); gFocusMgr.setKeystrokesOnly(TRUE); @@ -160,8 +160,8 @@ void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* } input += getString("keyboard"); } - pDesription->setText(getString("basic_description")); - pDesription->setTextArg("[INPUT]", input); + pDescription->setText(getString("basic_description")); + pDescription->setTextArg("[INPUT]", input); } // static @@ -257,8 +257,8 @@ bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down) if (LLKeyConflictHandler::isReservedByMenu(key, mask)) { - pDesription->setText(getString("reserved_by_menu")); - pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key)); + pDescription->setText(getString("reserved_by_menu")); + pDescription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key)); mLastMaskKey = 0; return true; } diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h index 24dfa1dbfd..18e2601723 100644 --- a/indra/newview/llsetkeybinddialog.h +++ b/indra/newview/llsetkeybinddialog.h @@ -85,7 +85,7 @@ private: void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes); LLKeyBindResponderInterface *pParent; LLCheckBoxCtrl *pCheckBox; - LLTextBase *pDesription; + LLTextBase *pDescription; U32 mKeyFilterMask; Updater *pUpdater; diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index ea7e649792..a5dcdc41ed 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -653,7 +653,12 @@ bool LLSidepanelInventory::canWearSelected() LLInventoryItem *LLSidepanelInventory::getSelectedItem() { - LLFolderViewItem* current_item = mPanelMainInventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); + LLFolderView* root = mPanelMainInventory->getActivePanel()->getRootFolder(); + if (!root) + { + return NULL; + } + LLFolderViewItem* current_item = root->getCurSelectedItem(); if (!current_item) { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 54f3e6305c..d9ebd73da4 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -309,6 +309,13 @@ void update_texture_fetch() gTextureList.updateImages(0.10f); } +bool finish_force_quit(const LLSD& notification, const LLSD& response) +{ + LLAppViewer::instance()->forceQuit(); + return false; +} + + void set_flags_and_update_appearance() { LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); @@ -1173,6 +1180,10 @@ bool idle_startup() } } + else if (reason_response == "BadType") + { + LLNotificationsUtil::add("LoginFailedToParse", LLSD(), LLSD(), login_alert_done); + } else if (!message.empty()) { // This wasn't a certificate error, so throw up the normal @@ -1819,6 +1830,17 @@ bool idle_startup() // This method MUST be called before gInventory.findCategoryUUIDForType because of // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. gInventory.buildParentChildMap(); + + // If buildParentChildMap succeeded, inventory will now be in + // a usable state and gInventory.isInventoryUsable() will be + // true. + + // if inventory is unusable, we need to bail out. + if (!gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("InventoryUnusable", LLSD(), LLSD(), &finish_force_quit ); + } + gInventory.createCommonSystemCategories(); // It's debatable whether this flag is a good idea - sets all @@ -1851,6 +1873,7 @@ bool idle_startup() display_startup(); LLStartUp::setStartupState( STATE_MISC ); display_startup(); + return FALSE; } @@ -2140,7 +2163,10 @@ bool idle_startup() if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) { - LLNotificationsUtil::add("ClothingLoading"); + if (gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("ClothingLoading"); + } record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); LLStartUp::setStartupState( STATE_CLEANUP ); } diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index f9c327b46e..ba328f27c4 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -343,7 +343,9 @@ BOOL LLToolCompTranslate::handleDoubleClick(S32 x, S32 y, MASK mask) } // Nothing selected means the first mouse click was probably // bad, so try again. - return FALSE; + // This also consumes the event to prevent things like double-click + // teleport from triggering. + return handleMouseDown(x, y, mask); } diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index a00ac10698..71986d21f9 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -73,7 +73,7 @@ BOOL LLToolFace::handleDoubleClick(S32 x, S32 y, MASK mask) BOOL LLToolFace::handleMouseDown(S32 x, S32 y, MASK mask) { - gViewerWindow->pickAsync(x, y, mask, pickCallback); + gViewerWindow->pickAsync(x, y, mask, pickCallback, false, gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick")); return TRUE; } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index 07f46c5fbe..d8cb70dd3c 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -135,7 +135,7 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask) gViewerWindow->hideCursor(); - gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ FALSE, /*BOOL pick_unselectable*/ TRUE); + gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"), /*BOOL pick_unselectable*/ TRUE); return TRUE; } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 54ff7d295e..0ac8d487e4 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -78,6 +78,10 @@ static void handle_click_action_play(); static void handle_click_action_open_media(LLPointer<LLViewerObject> objectp); static ECursorType cursor_from_parcel_media(U8 click_action); +BOOL rigged_hovering_keep_hand = false; +U64 last_rigged_hovering_check_clock_count = 0; +U64 last_rigged_pick_clock_count = 0; + LLToolPie::LLToolPie() : LLTool(std::string("Pie")), mMouseButtonDown( false ), @@ -112,7 +116,7 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mMouseDownX = x; mMouseDownY = y; LLTimer pick_timer; - BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + BOOL pick_rigged = gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); LLPickInfo transparent_pick = gViewerWindow->pickImmediate(x, y, TRUE /*includes transparent*/, pick_rigged); LLPickInfo visible_pick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); LLViewerObject *transp_object = transparent_pick.getObject(); @@ -173,7 +177,9 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mMouseButtonDown = true; - return handleLeftClickPick(); + // If nothing clickable is picked, needs to return + // false for click-to-walk or click-to-teleport to work. + return handleLeftClickPick(); } // Spawn context menus on right mouse down so you can drag over and select @@ -724,7 +730,21 @@ void LLToolPie::selectionPropertiesReceived() BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { - BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + // prevent rigged item hovering causing FPS to drop by faking we're still hovering it for 0.25 seconds + U64 current_clock_count = LLTimer::getCurrentClockCount(); + if (current_clock_count - last_rigged_pick_clock_count < 2500000) { + if(rigged_hovering_keep_hand) gViewerWindow->setCursor(UI_CURSOR_HAND); + return TRUE; + } + rigged_hovering_keep_hand = 0; + + static LLCachedControl<bool> pick_rigged_setting(gSavedSettings, "AnimatedObjectsAllowLeftClick"); + BOOL pick_rigged = pick_rigged_setting; + if (pick_rigged) { + pick_rigged = (current_clock_count - last_rigged_hovering_check_clock_count > 1000000); // only 10 per seconds + if (pick_rigged) last_rigged_hovering_check_clock_count = current_clock_count; + } + mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); @@ -732,6 +752,10 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) if (object) { parent = object->getRootEdit(); + // Update gLastRiggedPickClockCount if we're hovering a rigged item + if (object->isRiggedMesh()) { + last_rigged_pick_clock_count = current_clock_count; + } } // Show screen-space highlight glow effect @@ -797,6 +821,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_HAND); + rigged_hovering_keep_hand = true; LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 0f102411d5..6aa1273174 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -102,10 +102,11 @@ public: /// LLViewerAssetStorage ///---------------------------------------------------------------------------- +S32 LLViewerAssetStorage::sAssetCoroCount = 0; + // Unused? LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, const LLHost &upstream_host) : LLAssetStorage(msg, xfer, upstream_host), - mAssetCoroCount(0), mCountRequests(0), mCountStarted(0), mCountCompleted(0), @@ -117,7 +118,6 @@ LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager * LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer) : LLAssetStorage(msg, xfer), - mAssetCoroCount(0), mCountRequests(0), mCountStarted(0), mCountCompleted(0), @@ -477,8 +477,7 @@ void LLViewerAssetStorage::assetRequestCoro( LLGetAssetCallback callback, void *user_data) { - LLScopedIncrement coro_count_boost(mAssetCoroCount); - mCountStarted++; + LLScopedIncrement coro_count_boost(sAssetCoroCount); // static counter since corotine can outlive LLViewerAssetStorage S32 result_code = LL_ERR_NOERR; LLExtStat ext_status = LLExtStat::NONE; @@ -488,6 +487,9 @@ void LLViewerAssetStorage::assetRequestCoro( LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: asset storage no longer exists" << LL_ENDL; return; } + + mCountStarted++; + if (!gAgent.getRegion()) { LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL; @@ -554,6 +556,18 @@ void LLViewerAssetStorage::assetRequestCoro( result_code = LL_ERR_ASSET_REQUEST_FAILED; ext_status = LLExtStat::NONE; } + else if (!result.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW)) + { + LL_DEBUGS("ViewerAsset") << "request failed, no data returned!" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LLExtStat::NONE; + } + else if (!result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].isBinary()) + { + LL_DEBUGS("ViewerAsset") << "request failed, invalid data format!" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LLExtStat::NONE; + } else { LL_DEBUGS("ViewerAsset") << "request succeeded, url " << url << LL_ENDL; @@ -613,7 +627,7 @@ std::string LLViewerAssetStorage::getAssetURL(const std::string& cap_url, const void LLViewerAssetStorage::logAssetStorageInfo() { LLMemory::logMemoryInfo(true); - LL_INFOS("AssetStorage") << "Active coros " << mAssetCoroCount << LL_ENDL; + LL_INFOS("AssetStorage") << "Active coros " << sAssetCoroCount << LL_ENDL; LL_INFOS("AssetStorage") << "mPendingDownloads size " << mPendingDownloads.size() << LL_ENDL; LL_INFOS("AssetStorage") << "mCountStarted " << mCountStarted << LL_ENDL; LL_INFOS("AssetStorage") << "mCountCompleted " << mCountCompleted << LL_ENDL; diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h index af7fbb5fbf..0965a17ce1 100644 --- a/indra/newview/llviewerassetstorage.h +++ b/indra/newview/llviewerassetstorage.h @@ -122,12 +122,13 @@ protected: wait_list_t mCoroWaitList; std::string mViewerAssetUrl; - S32 mAssetCoroCount; S32 mCountRequests; S32 mCountStarted; S32 mCountCompleted; S32 mCountSucceeded; S64 mTotalBytesFetched; + + static S32 sAssetCoroCount; // coroutine count, static since coroutines can outlive LLViewerAssetStorage }; #endif diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index f97ba0930e..f810e5f4ef 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -83,6 +83,8 @@ void LLViewerAudio::registerIdleListener() void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI) { + LL_DEBUGS("AudioEngine") << "Start with outo fade: " << streamURI << LL_ENDL; + // Old and new stream are identical if (mNextStreamURI == streamURI) { @@ -166,6 +168,7 @@ bool LLViewerAudio::onIdleUpdate() if (gAudiop) { // Clear URI + LL_DEBUGS("AudioEngine") << "Done with audio fade" << LL_ENDL; gAudiop->startInternetStream(LLStringUtil::null); gAudiop->stopInternetStream(); } @@ -176,6 +179,7 @@ bool LLViewerAudio::onIdleUpdate() if (gAudiop) { + LL_DEBUGS("AudioEngine") << "Audio fade in: " << mNextStreamURI << LL_ENDL; LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); if(stream && stream->supportsAdjustableBufferSizes()) stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); @@ -219,6 +223,7 @@ void LLViewerAudio::stopInternetStreamWithAutoFade() if (gAudiop) { + LL_DEBUGS("AudioEngine") << "Stop audio fade" << LL_ENDL; gAudiop->startInternetStream(LLStringUtil::null); gAudiop->stopInternetStream(); } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 54c2099ac9..c99fccc3c6 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1773,6 +1773,10 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ // need to set agent string here before instance created media_source->setBrowserUserAgent(LLViewerMedia::getInstance()->getCurrentUserAgent()); + // configure and pass proxy setup based on debug settings that are + // configured by UI in prefs -> setup + media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); + media_source->setTarget(target); const std::string plugin_dir = gDirUtilp->getLLPluginDir(); @@ -1857,8 +1861,6 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) std::string ca_path = gDirUtilp->getCAFile(); media_source->addCertificateFilePath( ca_path ); - media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); - if(mClearCache) { mClearCache = false; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 01a4bd587d..17bf82e829 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -202,6 +202,7 @@ LLContextMenu* gDetachBodyPartPieMenus[9]; // File Menu void handle_compress_image(void*); +void handle_compress_file_test(void*); // Edit menu @@ -2224,6 +2225,21 @@ class LLAdvancedCompressImage : public view_listener_t }; + +//////////////////////// +// COMPRESS FILE TEST // +//////////////////////// + +class LLAdvancedCompressFileTest : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_compress_file_test(NULL); + return true; + } +}; + + ///////////////////////// // SHOW DEBUG SETTINGS // ///////////////////////// @@ -9341,6 +9357,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); + view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest"); view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 4efc3d1cb3..f5b41d3179 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -773,6 +773,94 @@ void handle_compress_image(void*) } } +// No convinient check in LLFile, and correct way would be something +// like GetFileSizeEx, which is too OS specific for current purpose +// so doing dirty, but OS independent fopen and fseek +size_t get_file_size(std::string &filename) +{ + LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + if (!file) + { + LL_WARNS() << "Error opening " << filename << LL_ENDL; + return 0; + } + + // read in the whole file + fseek(file, 0L, SEEK_END); + size_t file_length = (size_t)ftell(file); + fclose(file); + return file_length; +} + +void handle_compress_file_test(void*) +{ + LLFilePicker& picker = LLFilePicker::instance(); + if (picker.getOpenFile()) + { + std::string infile = picker.getFirstFile(); + if (!infile.empty()) + { + std::string packfile = infile + ".pack_test"; + std::string unpackfile = infile + ".unpack_test"; + + S64Bytes initial_size = S64Bytes(get_file_size(infile)); + + BOOL success; + + F64 total_seconds = LLTimer::getTotalSeconds(); + success = gzip_file(infile, packfile); + F64 result_pack_seconds = LLTimer::getTotalSeconds() - total_seconds; + + if (success) + { + S64Bytes packed_size = S64Bytes(get_file_size(packfile)); + + LL_INFOS() << "Packing complete, time: " << result_pack_seconds << " size: " << packed_size << LL_ENDL; + total_seconds = LLTimer::getTotalSeconds(); + success = gunzip_file(packfile, unpackfile); + F64 result_unpack_seconds = LLTimer::getTotalSeconds() - total_seconds; + + if (success) + { + S64Bytes unpacked_size = S64Bytes(get_file_size(unpackfile)); + + LL_INFOS() << "Unpacking complete, time: " << result_unpack_seconds << " size: " << unpacked_size << LL_ENDL; + + LLSD args; + args["FILE"] = infile; + args["PACK_TIME"] = result_pack_seconds; + args["UNPACK_TIME"] = result_unpack_seconds; + args["SIZE"] = LLSD::Integer(initial_size.valueInUnits<LLUnits::Kilobytes>()); + args["PSIZE"] = LLSD::Integer(packed_size.valueInUnits<LLUnits::Kilobytes>()); + args["USIZE"] = LLSD::Integer(unpacked_size.valueInUnits<LLUnits::Kilobytes>()); + LLNotificationsUtil::add("CompressionTestResults", args); + + LLFile::remove(packfile); + LLFile::remove(unpackfile); + } + else + { + LL_INFOS() << "Failed to uncompress file: " << packfile << LL_ENDL; + LLFile::remove(packfile); + } + + } + else + { + LL_INFOS() << "Failed to compres file: " << infile << LL_ENDL; + } + } + else + { + LL_INFOS() << "Failed to open file" << LL_ENDL; + } + } + else + { + LL_INFOS() << "Failed to open file" << LL_ENDL; + } +} + LLUUID upload_new_resource( const std::string& src_filename, diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 14442c9705..10ffbc7fa7 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3851,7 +3851,12 @@ void process_sound_trigger(LLMessageSystem *msg, void **) } // Don't play sounds from gestures if they are not enabled. - if (object_id == owner_id && !gSavedSettings.getBOOL("EnableGestureSounds")) + // Do play sounds triggered by avatar, since muting your own + // gesture sounds and your own sounds played inworld from + // Inventory can cause confusion. + if (object_id == owner_id + && owner_id != gAgentID + && !gSavedSettings.getBOOL("EnableGestureSounds")) { return; } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 0f409701d1..8986a34e60 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -242,9 +242,9 @@ public: LLVector3 mLastCameraOrigin; U32 mLastCameraUpdate; - void requestBaseCapabilitiesCoro(U64 regionHandle); - void requestBaseCapabilitiesCompleteCoro(U64 regionHandle); - void requestSimulatorFeatureCoro(std::string url, U64 regionHandle); + static void requestBaseCapabilitiesCoro(U64 regionHandle); + static void requestBaseCapabilitiesCompleteCoro(U64 regionHandle); + static void requestSimulatorFeatureCoro(std::string url, U64 regionHandle); }; void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) @@ -272,6 +272,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; return; // this error condition is not recoverable. } + LLViewerRegionImpl* impl = regionp->getRegionImplNC(); LL_DEBUGS("AppInit", "Capabilities") << "requesting seed caps for handle " << regionHandle << " name " << regionp->getName() << LL_ENDL; @@ -286,32 +287,33 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) newRegionEntry(*regionp); // After a few attempts, continue login. But keep trying to get the caps: - if (mSeedCapAttempts >= mSeedCapMaxAttemptsBeforeLogin && + if (impl->mSeedCapAttempts >= impl->mSeedCapMaxAttemptsBeforeLogin && STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED); } - if (mSeedCapAttempts > mSeedCapMaxAttempts) + if (impl->mSeedCapAttempts > impl->mSeedCapMaxAttempts) { // *TODO: Give a user pop-up about this error? - LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << impl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; return; // this error condition is not recoverable. } - S32 id = ++mHttpResponderID; + S32 id = ++(impl->mHttpResponderID); LLSD capabilityNames = LLSD::emptyArray(); - buildCapabilityNames(capabilityNames); + impl->buildCapabilityNames(capabilityNames); LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url << " region name " << regionp->getName() << " region id " << regionp->getRegionID() << " handle " << regionp->getHandle() - << " (attempt #" << mSeedCapAttempts + 1 << ")" << LL_ENDL; + << " (attempt #" << impl->mSeedCapAttempts + 1 << ")" << LL_ENDL; LL_DEBUGS("AppInit", "Capabilities") << "Capabilities requested: " << capabilityNames << LL_ENDL; regionp = NULL; + impl = NULL; result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); if (STATE_WORLD_INIT > LLStartUp::getStartupState()) @@ -325,8 +327,6 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) return; } - ++mSeedCapAttempts; - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { @@ -334,7 +334,11 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) return; // this error condition is not recoverable. } - if (id != mHttpResponderID) // region is no longer referring to this request + impl = regionp->getRegionImplNC(); + + ++impl->mSeedCapAttempts; + + if (id != impl->mHttpResponderID) // region is no longer referring to this request { LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL; // setup for retry. @@ -391,7 +395,6 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) { // *HACK: we're waiting for the ServerReleaseNotes regionp->showReleaseNotes(); } - } @@ -452,6 +455,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; break; // this error condition is not recoverable. } + LLViewerRegionImpl* impl = regionp->getRegionImplNC(); // remove the http_result from the llsd result.erase("http_result"); @@ -464,30 +468,30 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) } #if 0 - log_capabilities(mCapabilities); + log_capabilities(impl->mCapabilities); #endif - if (mCapabilities.size() != mSecondCapabilitiesTracker.size()) + if (impl->mCapabilities.size() != impl->mSecondCapabilitiesTracker.size()) { LL_WARNS("AppInit", "Capabilities") << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " - << "mCapabilities == " << mCapabilities.size() - << " mSecondCapabilitiesTracker == " << mSecondCapabilitiesTracker.size() + << "mCapabilities == " << impl->mCapabilities.size() + << " mSecondCapabilitiesTracker == " << impl->mSecondCapabilitiesTracker.size() << LL_ENDL; #ifdef DEBUG_CAPS_GRANTS LL_WARNS("AppInit", "Capabilities") << "Initial Base capabilities: " << LL_ENDL; - log_capabilities(mCapabilities); + log_capabilities(impl->mCapabilities); LL_WARNS("AppInit", "Capabilities") << "Latest base capabilities: " << LL_ENDL; - log_capabilities(mSecondCapabilitiesTracker); + log_capabilities(impl->mSecondCapabilitiesTracker); #endif - if (mSecondCapabilitiesTracker.size() > mCapabilities.size()) + if (impl->mSecondCapabilitiesTracker.size() > impl->mCapabilities.size()) { // *HACK Since we were granted more base capabilities in this grant request than the initial, replace // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a @@ -495,19 +499,17 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) // inventory api capability grants. // Need to clear a std::map before copying into it because old keys take precedence. - mCapabilities.clear(); - mCapabilities = mSecondCapabilitiesTracker; + impl->mCapabilities.clear(); + impl->mCapabilities = impl->mSecondCapabilitiesTracker; } } else { LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; } - mSecondCapabilitiesTracker.clear(); + impl->mSecondCapabilitiesTracker.clear(); } while (false); - - } void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 regionHandle) @@ -2242,7 +2244,7 @@ void LLViewerRegion::requestSimulatorFeatures() { std::string coroname = LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro", - boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle())); + boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, url, getHandle())); LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << " for region " << getRegionID() << LL_ENDL; } @@ -3060,7 +3062,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) //to the "original" seed cap received and determine why there is problem! std::string coroname = LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro", - boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, mImpl, getHandle())); + boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, getHandle())); return; } @@ -3072,7 +3074,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) std::string coroname = LLCoros::instance().launch("LLViewerRegionImpl::requestBaseCapabilitiesCoro", - boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, mImpl, getHandle())); + boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, getHandle())); LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << " for region " << getRegionID() << LL_ENDL; } diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 6471e89233..0642615c50 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -62,6 +62,7 @@ #include "llsdutil.h" #include "llcorehttputil.h" #include "llvoicevivox.h" +#include "llinventorymodel.h" #include "lluiusage.h" namespace LLStatViewer @@ -575,6 +576,11 @@ void send_viewer_stats(bool include_preferences) fail["invalid"] = (S32) gMessageSystem->mInvalidOnCircuitPackets; fail["missing_updater"] = (S32) LLAppViewer::instance()->isUpdaterMissing(); + LLSD &inventory = body["inventory"]; + inventory["usable"] = gInventory.isInventoryUsable(); + LLSD& validation_info = inventory["validation_info"]; + gInventory.mValidationInfo->asLLSD(validation_info); + body["ui"] = LLUIUsage::instance().asLLSD(); body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read(); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index c7a544f8eb..7a034022ea 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -89,6 +89,7 @@ namespace { // Don't retry connecting to the daemon more frequently than this: const F32 DAEMON_CONNECT_THROTTLE_SECONDS = 1.0f; + const int DAEMON_CONNECT_RETRY_MAX = 3; // Don't send positional updates more frequently than this: const F32 UPDATE_THROTTLE_SECONDS = 0.5f; @@ -705,6 +706,11 @@ void LLVivoxVoiceClient::voiceControlCoro() void LLVivoxVoiceClient::voiceControlStateMachine(S32 &coro_state) { + if (sShuttingDown) + { + return; + } + LL_DEBUGS("Voice") << "starting" << LL_ENDL; mIsCoroutineActive = true; LLCoros::set_consuming(true); @@ -860,6 +866,12 @@ void LLVivoxVoiceClient::voiceControlStateMachine(S32 &coro_state) } } while (coro_state > 0); + if (sShuttingDown) + { + // LLVivoxVoiceClient might be already dead + return; + } + mIsCoroutineActive = false; LL_INFOS("Voice") << "exiting" << LL_ENDL; } @@ -1033,8 +1045,9 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << LL_ENDL; + int retryCount(0); LLVoiceVivoxStats::getInstance()->reset(); - while (!mConnected && !sShuttingDown) + while (!mConnected && !sShuttingDown && retryCount++ <= DAEMON_CONNECT_RETRY_MAX) { LLVoiceVivoxStats::getInstance()->connectionAttemptStart(); LL_DEBUGS("Voice") << "Attempting to connect to vivox daemon: " << mDaemonHost << LL_ENDL; @@ -1160,7 +1173,7 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() { provisioned = true; } - } while (!provisioned && retryCount <= PROVISION_RETRY_MAX && !sShuttingDown); + } while (!provisioned && ++retryCount <= PROVISION_RETRY_MAX && !sShuttingDown); if (sShuttingDown && !provisioned) { @@ -1343,6 +1356,12 @@ bool LLVivoxVoiceClient::loginToVivox() } LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGIN_ATTEMPT_TIMEOUT, timeoutResult); + + if (sShuttingDown) + { + return false; + } + LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("login")) @@ -1405,6 +1424,11 @@ bool LLVivoxVoiceClient::loginToVivox() } while ((!response_ok || !account_login) && !sShuttingDown); + if (sShuttingDown) + { + return false; + } + mRelogRequested = false; mIsLoggedIn = true; notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ca5305b169..77f756a123 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -6089,14 +6089,25 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) LLVOVolume* vobj = drawablep->getVOVolume(); if (debugLoggingEnabled("AnimatedObjectsLinkset")) { - if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) + if (vobj && vobj->isAnimatedObject() && vobj->isRiggedMesh()) { std::string vobj_name = llformat("Vol%p", vobj); F32 est_tris = vobj->getEstTrianglesMax(); - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL; + LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL; } } - if (vobj->isNoLOD()) continue; + + if (!vobj || vobj->isNoLOD()) + { + continue; + } + + LLVolume* volume = vobj->getVolume(); + + if (!volume) + { + continue; + } vobj->preRebuild(); @@ -6105,7 +6116,6 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) vobj->updateRelativeXform(true); } - LLVolume* volume = vobj->getVolume(); for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { LLFace* face = drawablep->getFace(i); diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index bae615232e..4401f61059 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -421,59 +421,109 @@ private: std::string key(XMLRPC_GetValueID(current)); LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL; XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(current); - if (xmlrpc_type_string == type) + switch (type) { - LLSD::String val(XMLRPC_GetValueString(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; - responses.insert(key, val); - } - else if (xmlrpc_type_int == type) - { - LLSD::Integer val(XMLRPC_GetValueInt(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; - responses.insert(key, val); - } - else if (xmlrpc_type_double == type) - { - LLSD::Real val(XMLRPC_GetValueDouble(current)); - LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; - responses.insert(key, val); - } - else if (xmlrpc_type_array == type) - { - // We expect this to be an array of submaps. Walk the array, - // recursively parsing each submap and collecting them. - LLSD array; - int i = 0; // for descriptive purposes - for (XMLRPC_VALUE row = XMLRPC_VectorRewind(current); row; - row = XMLRPC_VectorNext(current), ++i) + case xmlrpc_type_empty: + LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL; + responses.insert(key, LLSD()); + break; + case xmlrpc_type_base64: { - // Recursive call. For the lower-level key_pfx, if 'key' - // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the - // nested call, a subkey "bar" will then be logged as - // "foo[0]:bar", and so forth. - // Parse the scalar subkey/value pairs from this array - // entry into a temp submap. Collect such submaps in 'array'. - array.append(parseValues(status_string, - STRINGIZE(key_pfx << key << '[' << i << "]:"), - row)); + S32 len = XMLRPC_GetValueStringLen(current); + const char* buf = XMLRPC_GetValueBase64(current); + if ((len > 0) && buf) + { + // During implementation this code was not tested + // If you encounter this, please make sure this is correct, + // then remove llassert + llassert(0); + + LLSD::Binary data; + data.resize(len); + memcpy((void*)&data[0], (void*)buf, len); + responses.insert(key, data); + } + else + { + LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key " + << key_pfx << key << LL_ENDL; + responses.insert(key, LLSD()); + } + break; } - // Having collected an 'array' of 'submap's, insert that whole - // 'array' as the value of this 'key'. - responses.insert(key, array); - } - else if (xmlrpc_type_struct == type) - { - LLSD submap = parseValues(status_string, - STRINGIZE(key_pfx << key << ':'), - current); - responses.insert(key, submap); - } - else - { + case xmlrpc_type_boolean: + { + LLSD::Boolean val(XMLRPC_GetValueBoolean(current)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; + responses.insert(key, val); + break; + } + case xmlrpc_type_datetime: + { + std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(current)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL; + responses.insert(key, LLSD::Date(iso8601_date)); + break; + } + case xmlrpc_type_double: + { + LLSD::Real val(XMLRPC_GetValueDouble(current)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; + responses.insert(key, val); + break; + } + case xmlrpc_type_int: + { + LLSD::Integer val(XMLRPC_GetValueInt(current)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; + responses.insert(key, val); + break; + } + case xmlrpc_type_string: + { + LLSD::String val(XMLRPC_GetValueString(current)); + LL_DEBUGS("LLXMLRPCListener") << "val: " << val << LL_ENDL; + responses.insert(key, val); + break; + } + case xmlrpc_type_mixed: + case xmlrpc_type_array: + { + // We expect this to be an array of submaps. Walk the array, + // recursively parsing each submap and collecting them. + LLSD array; + int i = 0; // for descriptive purposes + for (XMLRPC_VALUE row = XMLRPC_VectorRewind(current); row; + row = XMLRPC_VectorNext(current), ++i) + { + // Recursive call. For the lower-level key_pfx, if 'key' + // is "foo", pass "foo[0]:", then "foo[1]:", etc. In the + // nested call, a subkey "bar" will then be logged as + // "foo[0]:bar", and so forth. + // Parse the scalar subkey/value pairs from this array + // entry into a temp submap. Collect such submaps in 'array'. + array.append(parseValues(status_string, + STRINGIZE(key_pfx << key << '[' << i << "]:"), + row)); + } + // Having collected an 'array' of 'submap's, insert that whole + // 'array' as the value of this 'key'. + responses.insert(key, array); + break; + } + case xmlrpc_type_struct: + { + LLSD submap = parseValues(status_string, + STRINGIZE(key_pfx << key << ':'), + current); + responses.insert(key, submap); + break; + } + case xmlrpc_type_none: // Not expected + default: // whoops - unrecognized type LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key " - << key_pfx << key << LL_ENDL; + << key_pfx << key << LL_ENDL; responses.insert(key, STRINGIZE("<bad XMLRPC type " << type << '>')); status_string = "BadType"; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index cd1b9c7c69..2cafd93b83 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7154,6 +7154,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, { if ((j == LLViewerRegion::PARTITION_VOLUME) || (j == LLViewerRegion::PARTITION_BRIDGE) || + (j == LLViewerRegion::PARTITION_AVATAR) || // for attachments (j == LLViewerRegion::PARTITION_CONTROL_AV) || (j == LLViewerRegion::PARTITION_TERRAIN) || (j == LLViewerRegion::PARTITION_TREE) || @@ -7175,6 +7176,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, if (!sPickAvatar) { + pick_rigged = false; //save hit info in case we need to restore //due to attachment override LLVector4a local_normal; diff --git a/indra/newview/skins/default/xui/da/menu_place_add_button.xml b/indra/newview/skins/default/xui/da/menu_place_add_button.xml index 7ad2253550..c43ec6b1b7 100644 --- a/indra/newview/skins/default/xui/da/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/da/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Opret mappe" name="add_folder"/> <menu_item_call label="Tilføj landemærke" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/da/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/da/menu_teleport_history_item.xml index dbaec62087..825ab056d9 100644 --- a/indra/newview/skins/default/xui/da/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/da/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Teleportér" name="Teleport"/> <menu_item_call label="Mere information" name="More Information"/> <menu_item_call label="Kopiér til udklipsholder" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/de/menu_place_add_button.xml b/indra/newview/skins/default/xui/de/menu_place_add_button.xml index 7c0ff4a46a..975e5b4497 100644 --- a/indra/newview/skins/default/xui/de/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/de/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Ordner hinzufügen" name="add_folder"/> <menu_item_call label="Landmarke hinzufügen" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/de/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/de/menu_teleport_history_item.xml index 1d7e3059c0..8f3bf84151 100644 --- a/indra/newview/skins/default/xui/de/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/de/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Teleportieren" name="Teleport"/> <menu_item_call label="Weitere Informationen" name="More Information"/> <menu_item_call label="SLurl kopieren" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml index c609e3bd3a..31c524c38a 100644 --- a/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml +++ b/indra/newview/skins/default/xui/en/floater_edit_ext_day_cycle.xml @@ -342,6 +342,7 @@ width="25"> <button name="skip_back_btn" + enabled="false" follows="top" image_overlay="SkipBackward_Off" image_disabled="PushButton_Disabled" @@ -373,6 +374,7 @@ width="25"> <button name="play_btn" + enabled="false" follows="top" image_overlay="Play_Off" image_disabled="PushButton_Disabled" @@ -434,6 +436,7 @@ width="25"> <button name="skip_forward_btn" + enabled="false" follows="top" image_overlay="SkipForward_Off" image_disabled="PushButton_Disabled" diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 7f863756eb..f4cf2cb512 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1624,7 +1624,7 @@ Analysed: wrap="true" width="462" visible="true"> - You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. + You don't have rights to upload mesh models. [[VURL] Find out how] to get certified. </text> <text text_color="Yellow" diff --git a/indra/newview/skins/default/xui/en/floater_preview_animation.xml b/indra/newview/skins/default/xui/en/floater_preview_animation.xml index 3ea5f54f2c..d1f8da55be 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_animation.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_animation.xml @@ -1,66 +1,126 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater legacy_header_height="18" - height="85" + height="241" layout="topleft" name="preview_anim" help_topic="preview_anim" - width="280"> + width="320"> <floater.string name="Title"> Animation: [NAME] </floater.string> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="19" - layout="topleft" - left="10" - name="desc txt" - top="25" - width="80"> - Description: - </text> - <line_editor - border_style="line" - border_thickness="1" - follows="left|top|right" - font="SansSerifSmall" - height="19" - layout="topleft" - left_delta="95" - max_length_bytes="127" - name="desc" - top="19" - width="170" /> <button height="20" label="Play Inworld" label_selected="Stop" + follows="left|top" layout="topleft" left="10" name="Inworld" tool_tip="Play this animation so that others can see it" - top="47" + top="25" width="125"> <button.commit_callback function="PreviewAnim.Play" parameter="Inworld" /> </button> + <text + type="string" + length="1" + follows="left|top" + font="SansSerif" + height="19" + layout="topleft" + left_pad="10" + name="desc inworld" + top_delta="3" + width="160"> + Other people can see + </text> <button height="20" label="Play Locally" label_selected="Stop" + follows="left|top" layout="topleft" - left_pad="5" + left="10" name="Locally" tool_tip="Play this animation so that only you can see it" - top_delta="0" + top_pad="5" width="125"> <button.commit_callback function="PreviewAnim.Play" parameter="Locally" /> </button> + <text + type="string" + length="1" + follows="left|top" + font="SansSerif" + height="19" + layout="topleft" + left_pad="10" + name="desc local" + top_delta="3" + width="160"> + Only you can see + </text> + <text + type="string" + length="1" + follows="left|top" + font="SansSerif" + height="19" + layout="topleft" + left="10" + name="desc txt" + top_pad="7" + width="80"> + Description: + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|top|right" + font="SansSerifSmall" + height="19" + layout="topleft" + left="10" + right="-10" + max_length_bytes="127" + name="desc" + top_pad="0" /> + <text + type="string" + length="1" + follows="left|top" + font="SansSerif" + height="19" + layout="topleft" + left="10" + name="adv_trigger" + top_pad="7" + width="100" + text_color="EmphasisColor"> + Advanced + </text> + <text + type="string" + length="1" + follows="left|top" + font="SansSerif" + height="91" + layout="topleft" + left="10" + name="AdvancedStats" + top_pad="3" + width="200"> +Priority: [PRIORITY] +Duration: [DURATION]s +Ease In: [EASE_IN]s +Ease Out: [EASE_OUT]s +Loop: [IS_LOOP] +Joints: [NUM_JOINTS] + </text> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index 48d9eee4cd..998948fca1 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -33,7 +33,7 @@ Combination [KEYSTR] is reserved by menu. height="30" layout="topleft" left="30" - name="descritption" + name="description" top="25" word_wrap="true" width="212"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 24d06722b9..2a5f885395 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3900,6 +3900,12 @@ function="World.EnvPreset" <menu_item_call.on_click function="Advanced.CompressImage" /> </menu_item_call> + <menu_item_call + label="Compress File Test" + name="Compress File Test"> + <menu_item_call.on_click + function="Advanced.CompressFileTest" /> + </menu_item_call> <menu_item_call label="Enable Visual Leak Detector" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d4f71fb370..756bb52e3e 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -214,6 +214,19 @@ Make sure your Internet connection is working properly. <notification icon="alertmodal.tga" + name="LoginFailedToParse" + type="alertmodal"> + <tag>fail</tag> +Viewer received malformed response from server. Please, make sure your Internet connection is working properly and try again later. + +If you feel this is in error, please contact Support. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="MessageTemplateNotFound" type="alertmodal"> Message Template [PATH] not found. @@ -2949,6 +2962,17 @@ Darn. You have been logged out of [SECOND_LIFE]. <notification icon="alertmodal.tga" + name="InventoryUnusable" + type="alertmodal"> +There is a problem with your inventory. First, try logging out and logging in again. If you see this message again, contact Support and ask them to correct the problem. + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="Log out"/> + </notification> + + <notification + icon="alertmodal.tga" name="OnlyOfficerCanBuyLand" type="alertmodal"> Unable to buy land for the group: @@ -11777,5 +11801,15 @@ Unable to load the track into [TRACK]. Unable to load the track from [TRACK1] into [TRACK2]. <tag>fail</tag> </notification> + + <notification + icon="alertmodal.tga" + name="CompressionTestResults" + type="alertmodal"> +Test result for gzip level 6 file compression with [FILE] of size [SIZE] KB: +Packing: [PACK_TIME]s [PSIZE]KB +Unpacking: [UNPACK_TIME]s [USIZE]KB + <tag>fail</tag> + </notification> </notifications> diff --git a/indra/newview/skins/default/xui/en/panel_group_creation_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_creation_sidetray.xml index c0265c2fa2..466fb91dd0 100644 --- a/indra/newview/skins/default/xui/en/panel_group_creation_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_group_creation_sidetray.xml @@ -307,7 +307,7 @@ background_visible="true" top_pad="8" word_wrap="true" halign="center"> - Note: After 7 days, a group with no members (other than the creator) is deleted + Note: Any group that has less than two members for 48 hours is automatically disbanded </text> </layout_panel> </layout_stack> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index dff6f6e600..5e41ba4ae1 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -227,23 +227,25 @@ height="10" layout="topleft" left="30" - name="Proxy Settings 1" - mouse_opaque="false" - top_pad="10" - width="300"> - Proxy Settings: - </text> - <text - type="string" - length="1" - follows="left|top" - height="10" - layout="topleft" - left="80" - name="Proxy Settings 2" + name="Proxy Settings:" mouse_opaque="false" top_pad="5" width="300"> - Your system's existing proxy settings will be used + Proxy Settings: </text> + <button + label="Adjust proxy settings" + follows="left|top" + height="23" + width="140" + label_selected="Browse" + layout="topleft" + left_delta="50" + name="set_proxy" + top_pad="5" + > + <button.commit_callback + function="Pref.Proxy" /> + </button> </panel> + diff --git a/indra/newview/skins/default/xui/es/floater_buy_contents.xml b/indra/newview/skins/default/xui/es/floater_buy_contents.xml index 3563d4bd0f..d078868db2 100644 --- a/indra/newview/skins/default/xui/es/floater_buy_contents.xml +++ b/indra/newview/skins/default/xui/es/floater_buy_contents.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <floater name="floater_buy_contents" title="COMPRAR LOS CONTENIDOS"> <text name="contains_text"> - <nolink>[NOMBRE]</nolink> contiene: + <nolink>[NAME]</nolink> contiene: </text> <text name="buy_text"> ¿Comprar por [AMOUNT] L$ a [NAME]? diff --git a/indra/newview/skins/default/xui/es/floater_import_collada.xml b/indra/newview/skins/default/xui/es/floater_import_collada.xml index 7e9a00797a..24df8e41a3 100644 --- a/indra/newview/skins/default/xui/es/floater_import_collada.xml +++ b/indra/newview/skins/default/xui/es/floater_import_collada.xml @@ -1,13 +1,13 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <floater name="Import Collada" title="Importar escena"> <text name="mesh count"> - Redes: [RECUENTO] + Redes: [COUNT] </text> <text name="texture count"> - Texturas: [RECUENTO] + Texturas: [COUNT] </text> <text name="status"> - Estado: [ESTADO] + Estado: [STATUS] </text> <button label="Cancelar" name="cancel"/> <button label="OK" name="ok"/> @@ -15,9 +15,9 @@ Inactivo </string> <string name="status_uploading"> - Cargando [NOMBRE] + Cargando [NAME] </string> <string name="status_creating"> - Creando objeto [NOMBRE] + Creando objeto [NAME] </string> </floater> diff --git a/indra/newview/skins/default/xui/es/menu_place_add_button.xml b/indra/newview/skins/default/xui/es/menu_place_add_button.xml index 4b2f908a06..2032b9add9 100644 --- a/indra/newview/skins/default/xui/es/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/es/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Añadir una carpeta" name="add_folder"/> <menu_item_call label="Añadir este hito" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/es/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/es/menu_teleport_history_item.xml index 1ff555b727..d54cd65478 100644 --- a/indra/newview/skins/default/xui/es/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/es/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Teleportar" name="Teleport"/> <menu_item_call label="Más información" name="More Information"/> <menu_item_call label="Copiar la SLurl" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index c7750320d5..54707116d4 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -3389,15 +3389,15 @@ Con los siguientes Residentes: Error de transferencia a grupo. </notification> <notification name="ReleaseLandThrottled"> - La parcela [NOMBRE_PARCELA] no se puede abandonar en este momento. + La parcela [PARCEL_NAME] no se puede abandonar en este momento. </notification> <notification name="ReleasedLandWithReclaim"> - Ya está disponible la parcela [NOMBRE_PARCELA] de [ÁREA] m². + Ya está disponible la parcela [PARCEL_NAME] de [AREA] m². -Dispondrás de [PERÍODO_DE_RECLAMACIÓN] horas para reclamar la cantidad de 0 L$ antes de que se ponga en venta. +Dispondrás de [RECLAIM_PERIOD] horas para reclamar la cantidad de 0 L$ antes de que se ponga en venta. </notification> <notification name="ReleasedLandNoReclaim"> - Ya está disponible la parcela [NOMBRE_PARCELA] de [ÁREA] m². + Ya está disponible la parcela [PARCEL_NAME] de [AREA] m². Ya está en venta. </notification> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index ebb4ceaa7e..e5598978ce 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -204,10 +204,10 @@ Si deseas obtener más información, consulta las preguntas frecuentes que apare http://secondlife.com/viewer-access-faq </string> <string name="LoginIntermediateOptionalUpdateAvailable"> - Actualización opcional del visor disponible: [VERSIÓN] + Actualización opcional del visor disponible: [VERSION] </string> <string name="LoginFailedRequiredUpdate"> - Actualización necesaria del visor: [VERSIÓN] + Actualización necesaria del visor: [VERSION] </string> <string name="LoginFailedAlreadyLoggedIn"> El agente ya ha iniciado sesión. @@ -248,7 +248,7 @@ support@secondlife.com. </string> <string name="LoginFailedAcountSuspended"> No se podrá acceder a tu cuenta hasta las -[HORA] (horario de la costa del Pacífico). +[TIME] (horario de la costa del Pacífico). </string> <string name="LoginFailedAccountDisabled"> En este momento no podemos completar la solicitud. @@ -261,7 +261,7 @@ Ponte en contacto con support@secondlife.com. <string name="LoginFailedAccountMaintenance"> Se están realizando tareas rutinarias de mantenimiento en tu cuenta. No se podrá acceder a tu cuenta hasta las -[HORA] (horario de la costa del Pacífico). +[TIME] (horario de la costa del Pacífico). Si crees que se trata de un error, ponte en contacto con support@secondlife.com. </string> <string name="LoginFailedPendingLogoutFault"> @@ -279,7 +279,7 @@ Por favor, aguarda un momento antes de intentar conectarte nuevamente. </string> <string name="LoginFailedRestrictedHours"> Tu cuenta solo puede acceder a Second Life -entre las [INICIO] y las [FIN] (horario de la costa del Pacífico). +entre las [START] y las [END] (horario de la costa del Pacífico). Inténtalo de nuevo durante ese horario. Si crees que se trata de un error, ponte en contacto con support@secondlife.com. </string> diff --git a/indra/newview/skins/default/xui/fr/menu_place_add_button.xml b/indra/newview/skins/default/xui/fr/menu_place_add_button.xml index 92f9e7719d..4bae34beaa 100644 --- a/indra/newview/skins/default/xui/fr/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/fr/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Ajouter un dossier" name="add_folder"/> <menu_item_call label="Ajouter un repère" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/fr/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/fr/menu_teleport_history_item.xml index ba8ed9b3f8..ef864029ba 100644 --- a/indra/newview/skins/default/xui/fr/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/fr/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Téléporter" name="Teleport"/> <menu_item_call label="Plus d'informations" name="More Information"/> <menu_item_call label="Copier la SLurl" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/it/menu_place_add_button.xml b/indra/newview/skins/default/xui/it/menu_place_add_button.xml index 0e783c0000..abdc0ea794 100644 --- a/indra/newview/skins/default/xui/it/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/it/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Aggiungi cartella" name="add_folder"/> <menu_item_call label="Aggiungi punto di riferimento" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/it/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/it/menu_teleport_history_item.xml index 31236895fa..f7da322006 100644 --- a/indra/newview/skins/default/xui/it/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/it/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Teleport" name="Teleport"/> <menu_item_call label="Maggiori informazioni" name="More Information"/> <menu_item_call label="Copia SLurl" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ja/menu_place_add_button.xml b/indra/newview/skins/default/xui/ja/menu_place_add_button.xml index d5ce88b055..d19bc44451 100644 --- a/indra/newview/skins/default/xui/ja/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/ja/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="フォルダを追加" name="add_folder"/> <menu_item_call label="ランドマークを追加" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ja/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/ja/menu_teleport_history_item.xml index 61642048b8..1cc230e5b6 100644 --- a/indra/newview/skins/default/xui/ja/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/ja/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="テレポート" name="Teleport"/> <menu_item_call label="もっと詳しく" name="More Information"/> <menu_item_call label="SLurl をコピー" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pl/menu_place_add_button.xml b/indra/newview/skins/default/xui/pl/menu_place_add_button.xml index ff19f32ba8..107d4fae3a 100644 --- a/indra/newview/skins/default/xui/pl/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/pl/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Dodaj folder" name="add_folder" /> <menu_item_call label="Dodaj do Landmarków" name="add_landmark" /> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pl/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/pl/menu_teleport_history_item.xml index 7d8519324f..0ed1d510eb 100644 --- a/indra/newview/skins/default/xui/pl/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/pl/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Teleportuj" name="Teleport" /> <menu_item_call label="Więcej szczegółów" name="More Information" /> <menu_item_call label="Kopiuj SLurl do schowka" name="CopyToClipboard" /> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pt/menu_place_add_button.xml b/indra/newview/skins/default/xui/pt/menu_place_add_button.xml index d099d04f8d..89a634d12f 100644 --- a/indra/newview/skins/default/xui/pt/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/pt/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Adicionar pasta" name="add_folder"/> <menu_item_call label="Adicionar marco" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/pt/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/pt/menu_teleport_history_item.xml index 3a2b3a8847..db759cb4e3 100644 --- a/indra/newview/skins/default/xui/pt/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/pt/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Teletransportar" name="Teleport"/> <menu_item_call label="Mais informações" name="More Information"/> <menu_item_call label="Copiar SLurl" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ru/menu_place_add_button.xml b/indra/newview/skins/default/xui/ru/menu_place_add_button.xml index b1a38fb9eb..9298c032d5 100644 --- a/indra/newview/skins/default/xui/ru/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/ru/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Добавить папку" name="add_folder"/> <menu_item_call label="Добавить закладку" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/ru/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/ru/menu_teleport_history_item.xml index f495d27bf3..84a76ae0e0 100644 --- a/indra/newview/skins/default/xui/ru/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/ru/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Телепорт" name="Teleport"/> <menu_item_call label="Информация" name="More Information"/> <menu_item_call label="Копировать URL SL" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/tr/menu_place_add_button.xml b/indra/newview/skins/default/xui/tr/menu_place_add_button.xml index 8e52b3f7f2..69bc265823 100644 --- a/indra/newview/skins/default/xui/tr/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/tr/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="Klasör Ekle" name="add_folder"/> <menu_item_call label="Yer İmi Ekle" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/tr/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/tr/menu_teleport_history_item.xml index d7ff807c3d..59ba134965 100644 --- a/indra/newview/skins/default/xui/tr/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/tr/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="Işınla" name="Teleport"/> <menu_item_call label="Ek Bilgi" name="More Information"/> <menu_item_call label="SLurl'i Kopyala" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/zh/menu_place_add_button.xml b/indra/newview/skins/default/xui/zh/menu_place_add_button.xml index 95f8917234..165e2b6f08 100644 --- a/indra/newview/skins/default/xui/zh/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/zh/menu_place_add_button.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<menu name="menu_folder_gear"> +<toggleable_menu name="menu_create"> <menu_item_call label="添加資料夾" name="add_folder"/> <menu_item_call label="添加地標" name="add_landmark"/> -</menu> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/zh/menu_teleport_history_item.xml b/indra/newview/skins/default/xui/zh/menu_teleport_history_item.xml index bf60983896..200e1904f6 100644 --- a/indra/newview/skins/default/xui/zh/menu_teleport_history_item.xml +++ b/indra/newview/skins/default/xui/zh/menu_teleport_history_item.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<context_menu name="Teleport History Item Context Menu"> +<toggleable_menu name="Teleport History Item Menu"> <menu_item_call label="瞬間傳送" name="Teleport"/> <menu_item_call label="更多資訊" name="More Information"/> <menu_item_call label="覆製 SLurl" name="CopyToClipboard"/> -</context_menu> +</toggleable_menu> diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index d485203fa1..168880dc12 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -284,14 +284,25 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) // If we don't recognize status at all, trouble if (! (status == "CURLError" + || status == "BadType" || status == "XMLRPCError" || status == "OtherError")) { - LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: " - << mAuthResponse << LL_ENDL; + LL_ERRS("LLLogin") << "Unexpected status " << status + << " from " << xmlrpcPump.getName() + << " pump: " << mAuthResponse << LL_ENDL; return; } + if (status == "BadType") + { + // Invalid xmlrpc type + // Dump this response into logs + LL_WARNS("LLLogin") << "Failed to parse response" + << " from " << xmlrpcPump.getName() + << " pump: " << mAuthResponse << LL_ENDL; + } + // Here status IS one of the errors tested above. // Tell caller this didn't work out so well. |