diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000000..a110c018ec --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,93 @@ +name: Build + +on: + workflow_dispatch: + pull_request: + push: + branches: [main, contribute] + tags: ["*"] + +jobs: + build: + strategy: + matrix: + runner: [windows-large] + configuration: [ReleaseOS] + addrsize: [64] + include: + - runner: windows-large + configuration: ReleaseOS + addrsize: 32 + runs-on: ${{ matrix.runner }} + env: + AUTOBUILD_CONFIGURATION: ${{ matrix.configuration }} + AUTOBUILD_ADDRSIZE: ${{ matrix.addrsize }} + AUTOBUILD_INSTALLABLE_CACHE: ${{ github.workspace }}/.autobuild-installables + AUTOBUILD_VARIABLES_FILE: ${{ github.workspace }}/.build-variables/variables + AUTOBUILD_VSVER: "170" # vs2k22 + LOGFAIL: debug # Show details when tests fail + GIT_REF: ${{ github.head_ref || github.ref }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Checkout build variables + uses: actions/checkout@v3 + with: + repository: secondlife/build-variables + ref: viewer + path: .build-variables + + - name: Install autobuild and python dependencies + run: pip3 install autobuild llbase + + - name: Cache autobuild packages + uses: actions/cache@v3 + id: cache-installables + with: + path: .autobuild-installables + key: ${{ runner.os }}-${{ matrix.addrsize }}-${{ matrix.configuration }}-${{ hashFiles('autobuild.xml') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.addrsize }}-${{ matrix.configuration }}- + ${{ runner.os }}-${{ matrix.addrsize }}- + + - name: Install windows dependencies + if: runner.os == 'Windows' + run: choco install nsis-unicode + + - name: Build + id: build + shell: bash + env: + RUNNER_OS: ${{ runner.os }} + run: | + # On windows we need to point the build to the correct python + # as neither CMake's FindPython nor our custom Python.cmake module + # will resolve the correct interpreter location. + if [[ "$RUNNER_OS" == "Windows" ]]; then + export PYTHON="$(cygpath -m "$(which python)")" + echo "Python location: $PYTHON" + fi + + autobuild configure -- -DVIEWER_CHANNEL="Second Life Test ${GIT_REF##*/}" + autobuild build --no-configure + + # Find artifacts + if [[ "$RUNNER_OS" == "Windows" ]]; then + installer_path=$(find ./build-*/newview/ | grep '_Setup\.exe') + installer_name="$(basename $installer_path)" + elif [[ "$RUNNER_OS" == "macOS" ]]; then + installer_path=$(find ./build-*/newview/ | grep '\.dmg') + installer_name="$(basename $installer_path)" + fi + + echo "installer_path=$installer_path" >> $GITHUB_OUTPUT + echo "installer_name=$installer_name" >> $GITHUB_OUTPUT + + - name: Upload installer + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.build.outputs.installer_name }} + path: ${{ steps.build.outputs.installer_path }} diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 0000000000..17c0ace02f --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,18 @@ +name: pre-commit + +on: + pull_request: + push: + branches: [main, contribute] + tags: [v*] + + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index 82a9a968b9..35ac41420c 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -15,8 +15,8 @@ jobs: - uses: actions/stale@v6 id: stale with: - stale-pr-message: This pull request is stale because it has been open 60 days with no activity. Remove stale label or comment or it will be closed in 7 days - days-before-stale: 60 + stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days + days-before-stale: 30 days-before-close: 7 exempt-pr-labels: blocked,must,should,keep stale-pr-label: stale diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d296d7a24..fe7dfbac7a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,8 @@ repos: - - repo: https://bitbucket.org/lindenlab/git-hooks.git - rev: v1.0.0-beta2 + - repo: https://github.com/secondlife/git-hooks.git + rev: v1.0.0 hooks: - id: opensource-license - - id: jira-issue - id: llsd - id: no-trigraphs - id: copyright @@ -11,7 +10,7 @@ repos: files: \.(cpp|c|h|py|glsl|cmake|txt)$ exclude: language.txt - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.5.0 + rev: v4.4.0 hooks: - id: check-xml - id: mixed-line-ending diff --git a/autobuild.xml b/autobuild.xml index b1cfe79275..9785884a40 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1,5 +1,6 @@ - + + installables SDL @@ -2700,9 +2701,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 9e1b5515ab59b4e9cfeef6626d65d03d + 8b091b1f13348eedadf66d7d81cb6bc1 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108609/945996/viewer_manager-3.0.577252-darwin64-577252.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/116621/1003286/viewer_manager-3.0.580913-darwin64-580913.tar.bz2 name darwin64 @@ -2712,9 +2713,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - a3c599595ecc8fb987a5499fca42520a + 647e86470e02509b1cf89829d08dfd46 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108610/946003/viewer_manager-3.0.577252-windows-577252.tar.bz2 + https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/116623/1003293/viewer_manager-3.0.580913-windows-580913.tar.bz2 name windows @@ -2725,7 +2726,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors source_type hg version - 3.0.577252 + 3.0.580913 vlc-bin @@ -3290,7 +3291,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors /t:Build /p:useenv=true /verbosity:minimal - /toolsversion:4.0 /p:VCBuildAdditionalOptions= /incremental @@ -3364,7 +3364,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors /t:Build /p:useenv=true /verbosity:minimal - /toolsversion:4.0 /p:VCBuildAdditionalOptions= /incremental @@ -3401,4 +3400,5 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors autobuild version 1.3 - + + diff --git a/doc/contributions.txt b/doc/contributions.txt index 11a58dfbc5..3de668c1f0 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -594,6 +594,7 @@ Henri Beauchamp VWR-4157 SL-15175 SL-19110 + SL-19159 herina Bode Hikkoshi Sakai VWR-429 @@ -933,6 +934,8 @@ Lexi Frua Lillie Cordeaux Lilly Zenovka Lizzy Macarthur +Logue Takacs + INTL-490 Luban Yiyuan Luc Starsider Luminous Luminos @@ -1189,6 +1192,7 @@ PanteraPolnocy SL-18891 SL-18904 SL-18937 + SL-19207 SL-19681 Parvati Silverweb Patric Mills diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index c848d00710..c708199309 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -61,7 +61,7 @@ if (WINDOWS) # CP changed to only append the flag for 32bit builds - on 64bit builds, # locally at least, the build output is spammed with 1000s of 'D9002' # warnings about this switch being ignored. - if( ADDRESS_SIZE EQUAL 32 ) + if(ADDRESS_SIZE EQUAL 32 AND DEFINED ENV{"TEAMCITY_PROJECT_NAME"}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") endif() # zlib has assembly-language object files incompatible with SAFESEH @@ -171,6 +171,10 @@ if (DARWIN) ## Really?? On developer machines too? ##set(ENABLE_SIGNING TRUE) ##set(SIGNING_IDENTITY "Developer ID Application: Linden Research, Inc.") + + # required for clang-15/xcode-15 since our boost package still uses deprecated std::unary_function/binary_function + # see https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#C++-Standard-Library + add_compile_definitions(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION) endif (DARWIN) if (LINUX OR DARWIN) diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index dbf5033ce5..f9259f6c2b 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -2,7 +2,11 @@ set(PYTHONINTERP_FOUND) -if (WINDOWS) +if (DEFINED ENV{PYTHON}) + # Allow python executable to be explicitly set + set(python "$ENV{PYTHON}") + set(PYTHONINTERP_FOUND ON) +elseif (WINDOWS) # On Windows, explicitly avoid Cygwin Python. # if the user has their own version of Python installed, prefer that @@ -43,7 +47,7 @@ else() if (python) set(PYTHONINTERP_FOUND ON) endif (python) -endif (WINDOWS) +endif (DEFINED ENV{PYTHON}) if (NOT python) message(FATAL_ERROR "No Python interpreter found") diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index 875c2932f1..d86db236a3 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -32,7 +32,6 @@ #include "llsaleinfo.h" #include "llwearabletype.h" -class LLMD5; class LLVisualParam; class LLTexGlobalColorInfo; class LLTexGlobalColor; @@ -110,9 +109,6 @@ public: // Something happened that requires the wearable to be updated (e.g. worn/unworn). virtual void setUpdated() const = 0; - // Update the baked texture hash. - virtual void addToBakedTextureHash(LLMD5& hash) const = 0; - typedef std::map visual_param_index_map_t; visual_param_index_map_t mVisualParamIndexMap; diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 0eaeedb6ee..9fbbc57c87 100644 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -31,7 +31,6 @@ #include "llavatarappearance.h" #include "llavatarappearancedefines.h" #include "lldriverparam.h" -#include "llmd5.h" LLWearableData::LLWearableData() : mAvatarAppearance(NULL) @@ -343,42 +342,3 @@ U32 LLWearableData::getWearableCount(const U32 tex_index) const const LLWearableType::EType wearable_type = LLAvatarAppearance::getDictionary()->getTEWearableType((LLAvatarAppearanceDefines::ETextureIndex)tex_index); return getWearableCount(wearable_type); } - -LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index, - BOOL generate_valid_hash) // Set to false if you want to upload the baked texture w/o putting it in the cache -{ - LLUUID hash_id; - bool hash_computed = false; - LLMD5 hash; - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearance::getDictionary()->getBakedTexture(baked_index); - - for (U8 i=0; i < baked_dict->mWearables.size(); i++) - { - const LLWearableType::EType baked_type = baked_dict->mWearables[i]; - const U32 num_wearables = getWearableCount(baked_type); - for (U32 index = 0; index < num_wearables; ++index) - { - const LLWearable* wearable = getWearable(baked_type,index); - if (wearable) - { - wearable->addToBakedTextureHash(hash); - hash_computed = true; - } - } - } - if (hash_computed) - { - hash.update((const unsigned char*)baked_dict->mWearablesHashID.mData, UUID_BYTES); - - if (!generate_valid_hash) - { - invalidateBakedTextureHash(hash); - } - hash.finalize(); - hash.raw_digest(hash_id.mData); - } - - return hash_id; -} - - diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h index a0c446ea9e..b8e0bf8bd1 100644 --- a/indra/llappearance/llwearabledata.h +++ b/indra/llappearance/llwearabledata.h @@ -85,15 +85,6 @@ protected: private: void pullCrossWearableValues(const LLWearableType::EType type); - //-------------------------------------------------------------------- - // Server Communication - //-------------------------------------------------------------------- -public: - LLUUID computeBakedTextureHash(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index, - BOOL generate_valid_hash = TRUE); -protected: - virtual void invalidateBakedTextureHash(LLMD5& hash) const {} - //-------------------------------------------------------------------- // Member variables //-------------------------------------------------------------------- diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index ddc508455f..a387bb23cd 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -204,7 +204,8 @@ std::string LLAudioEngine::getInternetStreamURL() { if (mStreamingAudioImpl) return mStreamingAudioImpl->getURL(); - else return std::string(); + + return std::string(); } @@ -345,42 +346,43 @@ void LLAudioEngine::idle() } continue; } - else + + // Check to see if the current sound is done playing. + if (!channelp->isPlaying()) { - // Check to see if the current sound is done playing, or looped. - if (!channelp->isPlaying()) + sourcep->mCurrentDatap = sourcep->mQueuedDatap; + sourcep->mQueuedDatap = NULL; + + // Reset the timer so the source doesn't die. + sourcep->mAgeTimer.reset(); + + // Make sure we have the buffer set up if we just decoded the data + if (sourcep->mCurrentDatap) + { + updateBufferForData(sourcep->mCurrentDatap); + } + + // Actually play the associated data. + sourcep->setupChannel(); + channelp->updateBuffer(); + sourcep->getChannel()->play(); + continue; + } + + // Check to see if the current sound is looped. + if (sourcep->isLoop()) + { + // It's a loop, we need to check and see if we're done with it. + if (channelp->mLoopedThisFrame) { sourcep->mCurrentDatap = sourcep->mQueuedDatap; sourcep->mQueuedDatap = NULL; - // Reset the timer so the source doesn't die. - sourcep->mAgeTimer.reset(); - - // Make sure we have the buffer set up if we just decoded the data - if (sourcep->mCurrentDatap) - { - updateBufferForData(sourcep->mCurrentDatap); - } - - // Actually play the associated data. + // Actually, should do a time sync so if we're a loop master/slave + // we don't drift away. sourcep->setupChannel(); - channelp->updateBuffer(); sourcep->getChannel()->play(); } - else if (sourcep->isLoop()) - { - // It's a loop, we need to check and see if we're done with it. - if (channelp->mLoopedThisFrame) - { - sourcep->mCurrentDatap = sourcep->mQueuedDatap; - sourcep->mQueuedDatap = NULL; - - // Actually, should do a time sync so if we're a loop master/slave - // we don't drift away. - sourcep->setupChannel(); - sourcep->getChannel()->play(); - } - } } } @@ -396,18 +398,11 @@ void LLAudioEngine::idle() for (source_map::value_type& src_pair : mAllSources) { LLAudioSource *sourcep = src_pair.second; - if (sourcep->isMuted()) + if (sourcep->isMuted() && sourcep->isSyncMaster() && sourcep->getPriority() > max_sm_priority) { - continue; - } - if (sourcep->isSyncMaster()) - { - if (sourcep->getPriority() > max_sm_priority) - { - sync_masterp = sourcep; - master_channelp = sync_masterp->getChannel(); - max_sm_priority = sourcep->getPriority(); - } + sync_masterp = sourcep; + master_channelp = sync_masterp->getChannel(); + max_sm_priority = sourcep->getPriority(); } } @@ -737,7 +732,7 @@ F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec) } return (gain); -} +} F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec) @@ -964,11 +959,10 @@ void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp) else { LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <getID() << ")" << LL_ENDL; - if (sourcep == mCurrentSourcep) - { - // Don't reallocate the channel, this will make FMOD goofy. - //LL_INFOS() << "Calling setSource with same source!" << LL_ENDL; + if (sourcep == mCurrentSourcep) + { + // Don't reallocate the channel, this will make FMOD goofy. + //LL_INFOS() << "Calling setSource with same source!" << LL_ENDL; + } + + mCurrentSourcep = sourcep; + + updateBuffer(); + update3DPosition(); } - - mCurrentSourcep = sourcep; - - updateBuffer(); - update3DPosition(); } -} - bool LLAudioChannel::updateBuffer() { diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index 0fe8b3d756..a133898969 100755 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -90,6 +90,7 @@ public: // initialization/startup/shutdown virtual bool init(void *userdata, const std::string &app_title); virtual std::string getDriverName(bool verbose) = 0; + virtual LLStreamingAudioInterface *createDefaultStreamingAudioImpl() const = 0; virtual void shutdown(); // Used by the mechanics of the engine @@ -468,13 +469,13 @@ struct SoundData const LLUUID& owner_id, const F32 gain, const S32 type = LLAudioEngine::AUDIO_TYPE_NONE, - const LLVector3d &pos_global = LLVector3d::zero) + const LLVector3d &pos_global = LLVector3d::zero) : + audio_uuid(audio_uuid), + owner_id(owner_id), + gain(gain), + type(type), + pos_global(pos_global) { - this->audio_uuid = audio_uuid; - this->owner_id = owner_id; - this->gain = gain; - this->type = type; - this->pos_global = pos_global; } }; diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index ba743020b5..c6313ea289 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -208,10 +208,6 @@ bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title } #endif - // set up our favourite FMOD-native streaming audio implementation if none has already been added - if (!getStreamingAudioImpl()) // no existing implementation added - setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem)); - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; int r_numbuffers, r_samplerate, r_channels; @@ -253,6 +249,13 @@ std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose) } +// create our favourite FMOD-native streaming audio implementation +LLStreamingAudioInterface *LLAudioEngine_FMODSTUDIO::createDefaultStreamingAudioImpl() const +{ + return new LLStreamingAudio_FMODSTUDIO(mSystem); +} + + void LLAudioEngine_FMODSTUDIO::allocateListener(void) { mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h index d3d6d69685..29e7bc6bf0 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.h +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -53,6 +53,7 @@ public: // initialization/startup/shutdown virtual bool init(void *user_data, const std::string &app_title); virtual std::string getDriverName(bool verbose); + virtual LLStreamingAudioInterface* createDefaultStreamingAudioImpl() const; virtual void allocateListener(); virtual void shutdown(); diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 117d408b21..5b1b28bf4f 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -1352,7 +1352,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp) dp.packS32(joint->mNumRotKeys, "num_rot_keys"); LLQuaternion::Order order = bvhStringToOrder( joint->mOrder ); - S32 outcount = 0; S32 frame = 0; for (Key& key : joint->mKeys) { @@ -1418,7 +1417,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp) dp.packU16(x, "rot_angle_x"); dp.packU16(y, "rot_angle_y"); dp.packU16(z, "rot_angle_z"); - outcount++; frame++; } diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index 3cef382bbf..d95ec159f2 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -497,13 +497,20 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact // request asset mAssetStatus = ASSET_FETCHED; - LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL; - character_id = new LLUUID(mCharacter->getID()); - gAssetStorage->getAssetData(mID, - LLAssetType::AT_ANIMATION, - onLoadComplete, - (void *)character_id, - FALSE); + if (mID.notNull()) + { + LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL; + character_id = new LLUUID(mCharacter->getID()); + gAssetStorage->getAssetData(mID, + LLAssetType::AT_ANIMATION, + onLoadComplete, + (void*)character_id, + FALSE); + } + else + { + LL_INFOS("Animation") << "Attempted to fetch animation " << mName << " with null id for character " << mCharacter->getID() << LL_ENDL; + } return STATUS_HOLD; case ASSET_FETCHED: diff --git a/indra/llcommon/hbxxh.h b/indra/llcommon/hbxxh.h index 236716722a..9c0e9cf172 100644 --- a/indra/llcommon/hbxxh.h +++ b/indra/llcommon/hbxxh.h @@ -96,6 +96,15 @@ public: } } + // Make this class no-copy (it would be possible, with custom copy + // operators, but it is not trivially copyable, because of the mState + // pointer): it does not really make sense to allow copying it anyway, + // since all we care about is the resulting digest (so you should only + // need and care about storing/copying the digest and not a class + // instance). + HBXXH64(const HBXXH64&) noexcept = delete; + HBXXH64& operator=(const HBXXH64&) noexcept = delete; + ~HBXXH64(); void update(const void* buffer, size_t len); @@ -199,6 +208,15 @@ public: } } + // Make this class no-copy (it would be possible, with custom copy + // operators, but it is not trivially copyable, because of the mState + // pointer): it does not really make sense to allow copying it anyway, + // since all we care about is the resulting digest (so you should only + // need and care about storing/copying the digest and not a class + // instance). + HBXXH128(const HBXXH128&) noexcept = delete; + HBXXH128& operator=(const HBXXH128&) noexcept = delete; + ~HBXXH128(); void update(const void* buffer, size_t len); diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 10b98f49aa..679f79039b 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -345,6 +345,7 @@ const U8 CLICK_ACTION_PLAY = 5; const U8 CLICK_ACTION_OPEN_MEDIA = 6; const U8 CLICK_ACTION_ZOOM = 7; const U8 CLICK_ACTION_DISABLED = 8; +const U8 CLICK_ACTION_IGNORE = 9; // DO NOT CHANGE THE SEQUENCE OF THIS LIST!! diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index 5c46f6a796..4e25001fff 100644 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -167,48 +167,34 @@ const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luc // // defined for U16, U32, U64, S16, S32, S64, : // llclampb(a) // clamps a to [0 .. 255] -// +// -template -inline auto llmax(T1 d1, T2 d2) +// recursion tail +template +inline auto llmax(T data) { - return (d1 > d2) ? d1 : d2; + return data; } -template -inline auto llmax(T1 d1, T2 d2, T3 d3) +template +inline auto llmax(T0 d0, T1 d1, Ts... rest) { - auto r = llmax(d1,d2); - return llmax(r, d3); + auto maxrest = llmax(d1, rest...); + return (d0 > maxrest)? d0 : maxrest; } -template -inline auto llmax(T1 d1, T2 d2, T3 d3, T4 d4) +// recursion tail +template +inline auto llmin(T data) { - auto r1 = llmax(d1,d2); - auto r2 = llmax(d3,d4); - return llmax(r1, r2); + return data; } -template -inline auto llmin(T1 d1, T2 d2) +template +inline auto llmin(T0 d0, T1 d1, Ts... rest) { - return (d1 < d2) ? d1 : d2; -} - -template -inline auto llmin(T1 d1, T2 d2, T3 d3) -{ - auto r = llmin(d1,d2); - return (r < d3 ? r : d3); -} - -template -inline auto llmin(T1 d1, T2 d2, T3 d3, T4 d4) -{ - auto r1 = llmin(d1,d2); - auto r2 = llmin(d3,d4); - return llmin(r1, r2); + auto minrest = llmin(d1, rest...); + return (d0 < minrest) ? d0 : minrest; } template diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index c87c0758fe..259f5bc505 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -204,30 +204,35 @@ public: LLSD packet(LLSDMap("pump", pump)("data", data)); std::ostringstream buffer; - buffer << LLSDNotationStreamer(packet); + // SL-18330: for large data blocks, it's much faster to parse binary + // LLSD than notation LLSD. Use serialize(LLSD_BINARY) rather than + // directly calling LLSDBinaryFormatter because, unlike the latter, + // serialize() prepends the relevant header, needed by a general- + // purpose LLSD parser to distinguish binary from notation. + LLSDSerialize::serialize(packet, buffer, LLSDSerialize::LLSD_BINARY, + LLSDFormatter::OPTIONS_NONE); /*==========================================================================*| // DEBUGGING ONLY: don't copy str() if we can avoid it. std::string strdata(buffer.str()); if (std::size_t(buffer.tellp()) != strdata.length()) { - LL_ERRS("LLLeap") << "tellp() -> " << buffer.tellp() << " != " + LL_ERRS("LLLeap") << "tellp() -> " << static_cast(buffer.tellp()) << " != " << "str().length() -> " << strdata.length() << LL_ENDL; } // DEBUGGING ONLY: reading back is terribly inefficient. std::istringstream readback(strdata); LLSD echo; - LLPointer parser(new LLSDNotationParser()); - S32 parse_status(parser->parse(readback, echo, strdata.length())); - if (parse_status == LLSDParser::PARSE_FAILURE) + bool parse_status(LLSDSerialize::deserialize(echo, readback, strdata.length())); + if (! parse_status) { - LL_ERRS("LLLeap") << "LLSDNotationParser() cannot parse output of " - << "LLSDNotationStreamer()" << LL_ENDL; + LL_ERRS("LLLeap") << "LLSDSerialize::deserialize() cannot parse output of " + << "LLSDSerialize::serialize(LLSD_BINARY)" << LL_ENDL; } if (! llsd_equals(echo, packet)) { - LL_ERRS("LLLeap") << "LLSDNotationParser() produced different LLSD " - << "than passed to LLSDNotationStreamer()" << LL_ENDL; + LL_ERRS("LLLeap") << "LLSDSerialize::deserialize() returned different LLSD " + << "than passed to LLSDSerialize::serialize()" << LL_ENDL; } |*==========================================================================*/ @@ -314,9 +319,17 @@ public: LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got " << childout.size() << ", parsing LLSD" << LL_ENDL; LLSD data; +#if 1 + // specifically require notation LLSD from child LLPointer parser(new LLSDNotationParser()); S32 parse_status(parser->parse(childout.get_istream(), data, mExpect)); if (parse_status == LLSDParser::PARSE_FAILURE) +#else + // SL-18330: accept any valid LLSD serialization format from child + // Unfortunately this runs into trouble we have not yet debugged. + bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect)); + if (! parse_status) +#endif { bad_protocol("unparseable LLSD data"); } diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index 9b2a2bab60..0abe817f1d 100644 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -96,7 +96,7 @@ LLMD5::LLMD5() // operation, processing another message block, and updating the // context. -void LLMD5::update (const uint1 *input, const size_t input_length) { +void LLMD5::update (const uint8_t *input, const size_t input_length) { size_t input_index, buffer_index; size_t buffer_space; // how much space is left in buffer @@ -189,7 +189,7 @@ void LLMD5::finalize (){ unsigned char bits[8]; /* Flawfinder: ignore */ size_t index, padLen; - static uint1 PADDING[64]={ + static uint8_t PADDING[64]={ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 @@ -201,8 +201,8 @@ void LLMD5::finalize (){ } // Save number of bits. - // Treat count, a uint64_t, as uint4[2]. - encode (bits, reinterpret_cast(&count), 8); + // Treat count, a uint64_t, as uint32_t[2]. + encode (bits, reinterpret_cast(&count), 8); // Pad out to 56 mod 64. index = size_t((count >> 3) & 0x3f); @@ -412,7 +412,7 @@ Rotation is separate from addition to prevent recomputation. // LLMD5 basic transformation. Transforms state based on block. void LLMD5::transform (const U8 block[64]){ - uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; decode (x, block, 64); @@ -496,38 +496,38 @@ void LLMD5::transform (const U8 block[64]){ state[3] += d; // Zeroize sensitive information. - memset ( (uint1 *) x, 0, sizeof(x)); + memset ( (uint8_t *) x, 0, sizeof(x)); } -// Encodes input (UINT4) into output (unsigned char). Assumes len is +// Encodes input (uint32_t) into output (unsigned char). Assumes len is // a multiple of 4. -void LLMD5::encode (uint1 *output, const uint4 *input, const size_t len) { +void LLMD5::encode (uint8_t *output, const uint32_t *input, const size_t len) { size_t i, j; for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (uint1) (input[i] & 0xff); - output[j+1] = (uint1) ((input[i] >> 8) & 0xff); - output[j+2] = (uint1) ((input[i] >> 16) & 0xff); - output[j+3] = (uint1) ((input[i] >> 24) & 0xff); + output[j] = (uint8_t) (input[i] & 0xff); + output[j+1] = (uint8_t) ((input[i] >> 8) & 0xff); + output[j+2] = (uint8_t) ((input[i] >> 16) & 0xff); + output[j+3] = (uint8_t) ((input[i] >> 24) & 0xff); } } -// Decodes input (unsigned char) into output (UINT4). Assumes len is +// Decodes input (unsigned char) into output (uint32_t). Assumes len is // a multiple of 4. -void LLMD5::decode (uint4 *output, const uint1 *input, const size_t len){ +void LLMD5::decode (uint32_t *output, const uint8_t *input, const size_t len){ size_t i, j; for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | - (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); + output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | + (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); } diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h index 8530dc0389..7d6373c20c 100644 --- a/indra/llcommon/llmd5.h +++ b/indra/llcommon/llmd5.h @@ -67,6 +67,8 @@ documentation and/or software. */ +#include // uint32_t et al. + // use for the raw digest output const int MD5RAW_BYTES = 16; @@ -75,18 +77,13 @@ const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null const int MD5HEX_STR_BYTES = 32; // message system fixed size class LL_COMMON_API LLMD5 { -// first, some types: - typedef unsigned int uint4; // assumes integer is 4 words long - typedef unsigned short int uint2; // assumes short integer is 2 words long - typedef unsigned char uint1; // assumes char is 1 word long - // how many bytes to grab at a time when checking files static const int BLOCK_LEN; public: // methods for controlled operation: LLMD5 (); // simple initializer - void update (const uint1 *input, const size_t input_length); + void update (const uint8_t *input, const size_t input_length); void update (std::istream& stream); void update (FILE *file); void update (const std::string& str); @@ -109,19 +106,19 @@ private: // next, the private data: - uint4 state[4]; + uint32_t state[4]; uint64_t count; // number of *bits*, mod 2^64 - uint1 buffer[64]; // input buffer - uint1 digest[16]; - uint1 finalized; + uint8_t buffer[64]; // input buffer + uint8_t digest[16]; + uint8_t finalized; // last, the private methods, mostly static: void init (); // called by all constructors - void transform (const uint1 *buffer); // does the real update work. Note + void transform (const uint8_t *buffer); // does the real update work. Note // that length is implied to be 64. - static void encode (uint1 *dest, const uint4 *src, const size_t length); - static void decode (uint4 *dest, const uint1 *src, const size_t length); + static void encode (uint8_t *dest, const uint32_t *src, const size_t length); + static void decode (uint32_t *dest, const uint8_t *src, const size_t length); }; diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index b7e316da10..3db456ddb3 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -48,6 +48,7 @@ #endif #include "lldate.h" +#include "llmemorystream.h" #include "llsd.h" #include "llstring.h" #include "lluri.h" @@ -64,6 +65,23 @@ const std::string LLSD_NOTATION_HEADER("llsd/notation"); #define windowBits 15 #define ENABLE_ZLIB_GZIP 32 +// If we published this in llsdserialize.h, we could use it in the +// implementation of LLSDOStreamer's operator<<(). +template +void format_using(const LLSD& data, std::ostream& ostr, + LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY) +{ + LLPointer f{ new Formatter }; + f->format(data, ostr, options); +} + +template +S32 parse_using(std::istream& istr, LLSD& data, size_t max_bytes, S32 max_depth=-1) +{ + LLPointer p{ new Parser }; + return p->parse(istr, data, max_bytes, max_depth); +} + /** * LLSDSerialize */ @@ -86,10 +104,10 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize f = new LLSDXMLFormatter; break; - case LLSD_NOTATION: - str << "\n"; - f = new LLSDNotationFormatter; - break; + case LLSD_NOTATION: + str << "\n"; + f = new LLSDNotationFormatter; + break; default: LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; @@ -104,18 +122,37 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize // static bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes) { - LLPointer p = NULL; char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ - int i; - int inbuf = 0; - bool legacy_no_header = false; bool fail_if_not_legacy = false; - std::string header; - /* - * Get the first line before anything. - */ - str.get(hdr_buf, MAX_HDR_LEN, '\n'); + /* + * Get the first line before anything. Don't read more than max_bytes: + * this get() overload reads no more than (count-1) bytes into the + * specified buffer. In the usual case when max_bytes exceeds + * sizeof(hdr_buf), get() will read no more than sizeof(hdr_buf)-2. + */ + llssize max_hdr_read = MAX_HDR_LEN; + if (max_bytes != LLSDSerialize::SIZE_UNLIMITED) + { + max_hdr_read = llmin(max_bytes + 1, max_hdr_read); + } + str.get(hdr_buf, max_hdr_read, '\n'); + auto inbuf = str.gcount(); + + // https://en.cppreference.com/w/cpp/io/basic_istream/get + // When the get() above sees the specified delimiter '\n', it stops there + // without pulling it from the stream. If it turns out that the stream + // does NOT contain a header, and the content includes meaningful '\n', + // it's important to pull that into hdr_buf too. + if (inbuf < max_bytes && str.get(hdr_buf[inbuf])) + { + // got the delimiting '\n' + ++inbuf; + // None of the following requires that hdr_buf contain a final '\0' + // byte. We could store one if needed, since even the incremented + // inbuf won't exceed sizeof(hdr_buf)-1, but there's no need. + } + std::string header{ hdr_buf, static_cast(inbuf) }; if (str.fail()) { str.clear(); @@ -123,79 +160,97 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes) } if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ - { - legacy_no_header = true; - inbuf = (int)str.gcount(); + { // Create a LLSD XML parser, and parse the first chunk read above. + LLSDXMLParser x; + x.parsePart(hdr_buf, inbuf); // Parse the first part that was already read + auto parsed = x.parse(str, sd, max_bytes - inbuf); // Parse the rest of it + // Formally we should probably check (parsed != PARSE_FAILURE && + // parsed > 0), but since PARSE_FAILURE is -1, this suffices. + return (parsed > 0); } - else + + if (fail_if_not_legacy) { - if (fail_if_not_legacy) - goto fail; - /* - * Remove the newline chars - */ - for (i = 0; i < MAX_HDR_LEN; i++) - { - if (hdr_buf[i] == 0 || hdr_buf[i] == '\r' || - hdr_buf[i] == '\n') - { - hdr_buf[i] = 0; - break; - } - } - header = hdr_buf; + LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL; + return false; + } - std::string::size_type start = std::string::npos; - std::string::size_type end = std::string::npos; - start = header.find_first_not_of(" header syntax + auto start = header.find_first_not_of("parsePart(hdr_buf, inbuf); // Parse the first part that was already read - x->parseLines(str, sd); // Parse the rest of it - delete x; - return true; - } - - if (header == LLSD_BINARY_HEADER) + if (0 == LLStringUtil::compareInsensitive(header, LLSD_BINARY_HEADER)) { - p = new LLSDBinaryParser; + return (parse_using(str, sd, max_bytes-inbuf) > 0); } - else if (header == LLSD_XML_HEADER) + else if (0 == LLStringUtil::compareInsensitive(header, LLSD_XML_HEADER)) { - p = new LLSDXMLParser; + return (parse_using(str, sd, max_bytes-inbuf) > 0); } - else if (header == LLSD_NOTATION_HEADER) + else if (0 == LLStringUtil::compareInsensitive(header, LLSD_NOTATION_HEADER)) { - p = new LLSDNotationParser; + return (parse_using(str, sd, max_bytes-inbuf) > 0); } - else + else // no header we recognize { - LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL; + LLPointer p; + if (inbuf && hdr_buf[0] == '<') + { + // looks like XML + LL_DEBUGS() << "deserialize request with no header, assuming XML" << LL_ENDL; + p = new LLSDXMLParser; + } + else + { + // assume notation + LL_DEBUGS() << "deserialize request with no header, assuming notation" << LL_ENDL; + p = new LLSDNotationParser; + } + // Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that + // data to whatever remains in 'str'. + LLMemoryStreamBuf already(reinterpret_cast(hdr_buf), inbuf); + cat_streambuf prebuff(&already, str.rdbuf()); + std::istream prepend(&prebuff); +#if 1 + return (p->parse(prepend, sd, max_bytes) > 0); +#else + // debugging the reconstituted 'prepend' stream + // allocate a buffer that we hope is big enough for the whole thing + std::vector wholemsg((max_bytes == size_t(SIZE_UNLIMITED))? 1024 : max_bytes); + prepend.read(wholemsg.data(), std::min(max_bytes, wholemsg.size())); + LLMemoryStream replay(reinterpret_cast(wholemsg.data()), prepend.gcount()); + auto success{ p->parse(replay, sd, prepend.gcount()) > 0 }; + { + LL_DEBUGS() << (success? "parsed: $$" : "failed: '") + << std::string(wholemsg.data(), llmin(prepend.gcount(), 100)) << "$$" + << LL_ENDL; + } + return success; +#endif } - - if (p.notNull()) - { - p->parse(str, sd, max_bytes); - return true; - } - -fail: - LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL; - return false; } /** @@ -2193,9 +2248,9 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size) { U8* result = NULL; - U32 cur_size = 0; + llssize cur_size = 0; z_stream strm; - + constexpr U32 CHUNK = 1024 * 512; static thread_local std::unique_ptr out; @@ -2388,7 +2443,7 @@ U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size return result; } -char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size) +char* strip_deprecated_header(char* in, llssize& cur_size, llssize* header_size) { const char* deprecated_header = ""; constexpr size_t deprecated_header_size = 17; diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 2f12c6d1ff..676b7bfd6a 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -873,5 +873,5 @@ LL_COMMON_API std::string zip_llsd(LLSD& data); LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, size_t& outsize,std::istream& is, S32 size); // returns a pointer to the array or past the array if the deprecated header exists -LL_COMMON_API char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size = nullptr); +LL_COMMON_API char* strip_deprecated_header(char* in, llssize& cur_size, llssize* header_size = nullptr); #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llcommon/llstreamtools.cpp b/indra/llcommon/llstreamtools.cpp index 1ff15fcf89..bc32b6fd9e 100644 --- a/indra/llcommon/llstreamtools.cpp +++ b/indra/llcommon/llstreamtools.cpp @@ -513,3 +513,29 @@ std::istream& operator>>(std::istream& str, const char *tocheck) } return str; } + +int cat_streambuf::underflow() +{ + if (gptr() == egptr()) + { + // here because our buffer is empty + std::streamsize size = 0; + // Until we've run out of mInputs, try reading the first of them + // into mBuffer. If that fetches some characters, break the loop. + while (! mInputs.empty() + && ! (size = mInputs.front()->sgetn(mBuffer.data(), mBuffer.size()))) + { + // We tried to read mInputs.front() but got zero characters. + // Discard the first streambuf and try the next one. + mInputs.pop_front(); + } + // Either we ran out of mInputs or we succeeded in reading some + // characters, that is, size != 0. Tell base class what we have. + setg(mBuffer.data(), mBuffer.data(), mBuffer.data() + size); + } + // If we fell out of the above loop with mBuffer still empty, return + // eof(), otherwise return the next character. + return (gptr() == egptr()) + ? std::char_traits::eof() + : std::char_traits::to_int_type(*gptr()); +} diff --git a/indra/llcommon/llstreamtools.h b/indra/llcommon/llstreamtools.h index 1b04bf91d7..bb7bc20327 100644 --- a/indra/llcommon/llstreamtools.h +++ b/indra/llcommon/llstreamtools.h @@ -27,8 +27,10 @@ #ifndef LL_STREAM_TOOLS_H #define LL_STREAM_TOOLS_H +#include #include #include +#include // unless specifed otherwise these all return input_stream.good() @@ -113,6 +115,27 @@ LL_COMMON_API std::streamsize fullread( LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck); +/** + * cat_streambuf is a std::streambuf subclass that accepts a variadic number + * of std::streambuf* (e.g. some_istream.rdbuf()) and virtually concatenates + * their contents. + */ +// derived from https://stackoverflow.com/a/49441066/5533635 +class cat_streambuf: public std::streambuf +{ +private: + std::deque mInputs; + std::vector mBuffer; + +public: + // only valid for std::streambuf* arguments + template + cat_streambuf(Inputs... inputs): + mInputs{inputs...}, + mBuffer(1024) + {} + + int underflow() override; +}; + #endif - - diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index a8dcc5226a..bb3d667a42 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -577,10 +577,12 @@ S32 Recording::getSampleCount( const StatType& stat ) // PeriodicRecording /////////////////////////////////////////////////////////////////////// -PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state) +PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state) : mAutoResize(num_periods == 0), mCurPeriod(0), mNumRecordedPeriods(0), + // This guarantee that mRecordingPeriods cannot be empty is essential for + // code in several methods. mRecordingPeriods(num_periods ? num_periods : 1) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; @@ -596,18 +598,19 @@ PeriodicRecording::~PeriodicRecording() void PeriodicRecording::nextPeriod() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (mAutoResize) { mRecordingPeriods.push_back(Recording()); } Recording& old_recording = getCurRecording(); - mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size(); + inci(mCurPeriod); old_recording.splitTo(getCurRecording()); - mNumRecordedPeriods = mRecordingPeriods.empty()? 0 : - llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1); + // Since mRecordingPeriods always has at least one entry, we can always + // safely subtract 1 from its size(). + mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1); } void PeriodicRecording::appendRecording(Recording& recording) @@ -620,31 +623,29 @@ void PeriodicRecording::appendRecording(Recording& recording) void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (other.mRecordingPeriods.empty()) return; getCurRecording().update(); other.getCurRecording().update(); - - const auto other_recording_slots = other.mRecordingPeriods.size(); + const auto other_num_recordings = other.getNumRecordedPeriods(); const auto other_current_recording_index = other.mCurPeriod; - const auto other_oldest_recording_index = (other_current_recording_index + other_recording_slots - other_num_recordings) % other_recording_slots; + const auto other_oldest_recording_index = other.previ(other_current_recording_index, other_num_recordings); // append first recording into our current slot getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); // from now on, add new recordings for everything after the first - auto other_index = (other_oldest_recording_index + 1) % other_recording_slots; + auto other_index = other.nexti(other_oldest_recording_index); if (mAutoResize) { // push back recordings for everything in the middle - auto other_index = (other_oldest_recording_index + 1) % other_recording_slots; while (other_index != other_current_recording_index) { mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); - other_index = (other_index + 1) % other_recording_slots; + other.inci(other_index); } // add final recording, if it wasn't already added as the first @@ -653,36 +654,25 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]); } - mCurPeriod = mRecordingPeriods.empty()? 0 : mRecordingPeriods.size() - 1; + // mRecordingPeriods is never empty() + mCurPeriod = mRecordingPeriods.size() - 1; mNumRecordedPeriods = mCurPeriod; } else { - S32 num_to_copy = llmin((S32)mRecordingPeriods.size(), (S32)other_num_recordings); - - std::vector::iterator src_it = other.mRecordingPeriods.begin() + other_index ; - std::vector::iterator dest_it = mRecordingPeriods.begin() + mCurPeriod; - + auto num_to_copy = llmin(mRecordingPeriods.size(), other_num_recordings); // already consumed the first recording from other, so start counting at 1 - for(S32 i = 1; i < num_to_copy; i++) + for (size_t n = 1, srci = other_index, dsti = mCurPeriod; + n < num_to_copy; + ++n, other.inci(srci), inci(dsti)) { - *dest_it = *src_it; - - if (++src_it == other.mRecordingPeriods.end()) - { - src_it = other.mRecordingPeriods.begin(); - } - - if (++dest_it == mRecordingPeriods.end()) - { - dest_it = mRecordingPeriods.begin(); - } + mRecordingPeriods[dsti] = other.mRecordingPeriods[srci]; } - + // want argument to % to be positive, otherwise result could be negative and thus out of bounds llassert(num_to_copy >= 1); // advance to last recording period copied, and make that our current period - mCurPeriod = (mCurPeriod + num_to_copy - 1) % mRecordingPeriods.size(); + inci(mCurPeriod, num_to_copy - 1); mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1); } @@ -694,13 +684,11 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) F64Seconds PeriodicRecording::getDuration() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; F64Seconds duration; - auto num_periods = mRecordingPeriods.size(); - for (size_t i = 1; i <= num_periods; i++) + for (size_t n = 0; n < mRecordingPeriods.size(); ++n) { - auto index = (mCurPeriod + num_periods - i) % num_periods; - duration += mRecordingPeriods[index].getDuration(); + duration += mRecordingPeriods[nexti(mCurPeriod, n)].getDuration(); } return duration; } @@ -737,16 +725,14 @@ const Recording& PeriodicRecording::getCurRecording() const Recording& PeriodicRecording::getPrevRecording( size_t offset ) { - auto num_periods = mRecordingPeriods.size(); - offset = llclamp(offset, 0, num_periods - 1); - return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; + // reuse const implementation, but return non-const reference + return const_cast( + const_cast(this)->getPrevRecording(offset)); } const Recording& PeriodicRecording::getPrevRecording( size_t offset ) const { - auto num_periods = mRecordingPeriods.size(); - offset = llclamp(offset, 0, num_periods - 1); - return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; + return mRecordingPeriods[previ(mCurPeriod, offset)]; } void PeriodicRecording::handleStart() @@ -789,14 +775,14 @@ void PeriodicRecording::handleSplitTo(PeriodicRecording& other) getCurRecording().splitTo(other.getCurRecording()); } -F64 PeriodicRecording::getPeriodMin( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodMin( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; F64 min_val = std::numeric_limits::max(); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -811,14 +797,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType& stat, siz : NaN; } -F64 PeriodicRecording::getPeriodMax( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodMax( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; F64 max_val = std::numeric_limits::min(); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -834,7 +820,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType& stat, siz } // calculates means using aggregates per period -F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); @@ -842,7 +828,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, si F64 mean = 0; S32 valid_period_count = 0; - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -857,7 +843,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, si : NaN; } -F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); @@ -866,7 +852,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodMin( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; F64 min_val = std::numeric_limits::max(); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -904,14 +890,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType& stat, si : NaN; } -F64 PeriodicRecording::getPeriodMax(const StatType& stat, size_t num_periods /*= S32_MAX*/) +F64 PeriodicRecording::getPeriodMax(const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; F64 max_val = std::numeric_limits::min(); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -927,7 +913,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType& stat, siz } -F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); @@ -935,7 +921,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, s S32 valid_period_count = 0; F64 mean = 0; - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -950,13 +936,13 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, s : NaN; } -F64 PeriodicRecording::getPeriodMedian( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodMedian( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); std::vector buf; - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.getDuration() > (F32Seconds)0.f) @@ -976,7 +962,7 @@ F64 PeriodicRecording::getPeriodMedian( const StatType& stat, return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); } -F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); @@ -985,7 +971,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64Kilobytes PeriodicRecording::getPeriodMin( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64Kilobytes min_val(std::numeric_limits::max()); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); min_val = llmin(min_val, recording.getMin(stat)); @@ -1022,13 +1008,13 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, size_t n return getPeriodMin(static_cast&>(stat), num_periods); } -F64Kilobytes PeriodicRecording::getPeriodMax(const StatType& stat, size_t num_periods /*= S32_MAX*/) +F64Kilobytes PeriodicRecording::getPeriodMax(const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64Kilobytes max_val(0.0); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); max_val = llmax(max_val, recording.getMax(stat)); @@ -1042,14 +1028,14 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, size_t n return getPeriodMax(static_cast&>(stat), num_periods); } -F64Kilobytes PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64Kilobytes PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64Kilobytes mean(0); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); mean += recording.getMean(stat); @@ -1063,7 +1049,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, size_t return getPeriodMean(static_cast&>(stat), num_periods); } -F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= S32_MAX*/ ) +F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); @@ -1072,7 +1058,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType class LLStopWatchControlsMixinCommon { @@ -330,7 +331,7 @@ namespace LLTrace : public LLStopWatchControlsMixin { public: - PeriodicRecording(S32 num_periods, EPlayState state = STOPPED); + PeriodicRecording(size_t num_periods, EPlayState state = STOPPED); ~PeriodicRecording(); void nextPeriod(); @@ -353,7 +354,7 @@ namespace LLTrace Recording snapshotCurRecording() const; template - auto getSampleCount(const StatType& stat, size_t num_periods = S32_MAX) + auto getSampleCount(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); @@ -373,14 +374,14 @@ namespace LLTrace // catch all for stats that have a defined sum template - typename T::value_t getPeriodMin(const StatType& stat, size_t num_periods = S32_MAX) + typename T::value_t getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; typename T::value_t min_val(std::numeric_limits::max()); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -396,39 +397,39 @@ namespace LLTrace } template - T getPeriodMin(const CountStatHandle& stat, size_t num_periods = S32_MAX) + T getPeriodMin(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast&>(stat), num_periods)); } - F64 getPeriodMin(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - T getPeriodMin(const SampleStatHandle& stat, size_t num_periods = S32_MAX) + T getPeriodMin(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast&>(stat), num_periods)); } - F64 getPeriodMin(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - T getPeriodMin(const EventStatHandle& stat, size_t num_periods = S32_MAX) + T getPeriodMin(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodMin(const StatType& stat, size_t num_periods = S32_MAX); - F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = S32_MAX); + F64Kilobytes getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); template - typename RelatedTypes::fractional_t getPeriodMinPerSec(const StatType& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMinPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes::fractional_t min_val(std::numeric_limits::max()); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); min_val = llmin(min_val, recording.getPerSec(stat)); @@ -437,7 +438,7 @@ namespace LLTrace } template - typename RelatedTypes::fractional_t getPeriodMinPerSec(const CountStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMinPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMinPerSec(static_cast&>(stat), num_periods)); @@ -449,14 +450,14 @@ namespace LLTrace // catch all for stats that have a defined sum template - typename T::value_t getPeriodMax(const StatType& stat, size_t num_periods = S32_MAX) + typename T::value_t getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; typename T::value_t max_val(std::numeric_limits::min()); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.hasValue(stat)) @@ -472,39 +473,39 @@ namespace LLTrace } template - T getPeriodMax(const CountStatHandle& stat, size_t num_periods = S32_MAX) + T getPeriodMax(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast&>(stat), num_periods)); } - F64 getPeriodMax(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - T getPeriodMax(const SampleStatHandle& stat, size_t num_periods = S32_MAX) + T getPeriodMax(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast&>(stat), num_periods)); } - F64 getPeriodMax(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - T getPeriodMax(const EventStatHandle& stat, size_t num_periods = S32_MAX) + T getPeriodMax(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodMax(const StatType& stat, size_t num_periods = S32_MAX); - F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = S32_MAX); + F64Kilobytes getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); template - typename RelatedTypes::fractional_t getPeriodMaxPerSec(const StatType& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMaxPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 max_val = std::numeric_limits::min(); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); max_val = llmax(max_val, recording.getPerSec(stat)); @@ -513,7 +514,7 @@ namespace LLTrace } template - typename RelatedTypes::fractional_t getPeriodMaxPerSec(const CountStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMaxPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMaxPerSec(static_cast&>(stat), num_periods)); @@ -525,14 +526,14 @@ namespace LLTrace // catch all for stats that have a defined sum template - typename RelatedTypes::fractional_t getPeriodMean(const StatType& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes::fractional_t mean(0); - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.getDuration() > (F32Seconds)0.f) @@ -546,39 +547,39 @@ namespace LLTrace } template - typename RelatedTypes::fractional_t getPeriodMean(const CountStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMean(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); } - F64 getPeriodMean(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - typename RelatedTypes::fractional_t getPeriodMean(const SampleStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMean(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); } - F64 getPeriodMean(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - typename RelatedTypes::fractional_t getPeriodMean(const EventStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMean(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodMean(const StatType& stat, size_t num_periods = S32_MAX); - F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = S32_MAX); + F64Kilobytes getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); template - typename RelatedTypes::fractional_t getPeriodMeanPerSec(const StatType& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMeanPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes::fractional_t mean = 0; - for (S32 i = 1; i <= num_periods; i++) + for (size_t i = 1; i <= num_periods; i++) { Recording& recording = getPrevRecording(i); if (recording.getDuration() > (F32Seconds)0.f) @@ -593,64 +594,64 @@ namespace LLTrace } template - typename RelatedTypes::fractional_t getPeriodMeanPerSec(const CountStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodMeanPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodMeanPerSec(static_cast&>(stat), num_periods)); } - F64 getPeriodMedian( const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodMedian( const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - typename RelatedTypes::fractional_t getPeriodMedianPerSec(const StatType& stat, size_t num_periods = S32_MAX) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - std::vector ::fractional_t> buf; - for (S32 i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - buf.push_back(recording.getPerSec(stat)); - } - } - std::sort(buf.begin(), buf.end()); + std::vector ::fractional_t> buf; + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + buf.push_back(recording.getPerSec(stat)); + } + } + std::sort(buf.begin(), buf.end()); - return typename RelatedTypes::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); - } + return typename RelatedTypes::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + } - template - typename RelatedTypes::fractional_t getPeriodMedianPerSec(const CountStatHandle& stat, size_t num_periods = S32_MAX) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMedianPerSec(static_cast&>(stat), num_periods)); - } + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMedianPerSec(static_cast&>(stat), num_periods)); + } // // PERIODIC STANDARD DEVIATION // - F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - typename RelatedTypes::fractional_t getPeriodStandardDeviation(const SampleStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodStandardDeviation(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); } - F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = S32_MAX); + F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); template - typename RelatedTypes::fractional_t getPeriodStandardDeviation(const EventStatHandle& stat, size_t num_periods = S32_MAX) + typename RelatedTypes::fractional_t getPeriodStandardDeviation(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); } - F64Kilobytes getPeriodStandardDeviation(const StatType& stat, size_t num_periods = S32_MAX); - F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = S32_MAX); + F64Kilobytes getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = std::numeric_limits::max()); private: // implementation for LLStopWatchControlsMixin @@ -659,6 +660,35 @@ namespace LLTrace /*virtual*/ void handleReset(); /*virtual*/ void handleSplitTo(PeriodicRecording& other); + // helper methods for wraparound ring-buffer arithmetic + inline + size_t wrapi(size_t i) const + { + return i % mRecordingPeriods.size(); + } + + inline + size_t nexti(size_t i, size_t offset=1) const + { + return wrapi(i + offset); + } + + inline + size_t previ(size_t i, size_t offset=1) const + { + auto num_periods = mRecordingPeriods.size(); + // constrain offset + offset = llclamp(offset, 0, num_periods - 1); + // add size() so expression can't go (unsigned) "negative" + return wrapi(i + num_periods - offset); + } + + inline + void inci(size_t& i, size_t offset=1) const + { + i = nexti(i, offset); + } + private: std::vector mRecordingPeriods; const bool mAutoResize; diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index fc04dca08d..5655e8e2f2 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -884,7 +884,7 @@ U32 LLUUID::getRandomSeed() seed[7]=(unsigned char)(pid); getSystemTime((uuid_time_t *)(&seed[8])); - U64 seed64 = HBXXH64((const void*)seed, 16).digest(); + U64 seed64 = HBXXH64::digest((const void*)seed, 16); return U32(seed64) ^ U32(seed64 >> 32); } diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index c139c4eb4e..80597fa186 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -116,6 +116,14 @@ public: U16 getCRC16() const; U32 getCRC32() const; + // Returns a 64 bits digest of the UUID, by XORing its two 64 bits long + // words. HB + inline U64 getDigest64() const + { + U64* tmp = (U64*)mData; + return tmp[0] ^ tmp[1]; + } + static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. static const LLUUID null; @@ -165,36 +173,22 @@ public: LLAssetID makeAssetID(const LLUUID& session) const; }; -// Generate a hash of an LLUUID object using the boost hash templates. -template <> -struct boost::hash -{ - typedef LLUUID argument_type; - typedef std::size_t result_type; - result_type operator()(argument_type const& s) const - { - result_type seed(0); - - for (S32 i = 0; i < UUID_BYTES; ++i) - { - boost::hash_combine(seed, s.mData[i]); - } - - return seed; - } -}; - -// Adapt boost hash to std hash +// std::hash implementation for LLUUID namespace std { - template<> struct hash - { - std::size_t operator()(LLUUID const& s) const noexcept - { - return boost::hash()(s); - } - }; + template<> struct hash + { + inline size_t operator()(const LLUUID& id) const noexcept + { + return (size_t)id.getDigest64(); + } + }; } -#endif +// For use with boost containers. +inline size_t hash_value(const LLUUID& id) noexcept +{ + return (size_t)id.getDigest64(); +} +#endif // LL_LLUUID_H diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index da8512169c..0b43d7ad4b 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -41,7 +41,7 @@ typedef unsigned int U32; // to express an index that might go negative // (ssize_t is provided by SOME compilers, don't collide) -typedef typename std::make_signed::type llssize; +typedef typename std::make_signed::type llssize; #if LL_WINDOWS // https://docs.microsoft.com/en-us/cpp/build/reference/zc-wchar-t-wchar-t-is-native-type diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 7ee36a9ea6..3ae48a2532 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -109,7 +109,12 @@ namespace tut "import os\n" "import sys\n" "\n" - "from llbase import llsd\n" + "try:\n" + // new freestanding llsd package + " import llsd\n" + "except ImportError:\n" + // older llbase.llsd module + " from llbase import llsd\n" "\n" "class ProtocolError(Exception):\n" " def __init__(self, msg, data):\n" @@ -120,26 +125,26 @@ namespace tut " pass\n" "\n" "def get():\n" - " hdr = ''\n" - " while ':' not in hdr and len(hdr) < 20:\n" - " hdr += sys.stdin.read(1)\n" + " hdr = []\n" + " while b':' not in hdr and len(hdr) < 20:\n" + " hdr.append(sys.stdin.buffer.read(1))\n" " if not hdr:\n" " sys.exit(0)\n" - " if not hdr.endswith(':'):\n" + " if not hdr[-1] == b':':\n" " raise ProtocolError('Expected len:data, got %r' % hdr, hdr)\n" " try:\n" - " length = int(hdr[:-1])\n" + " length = int(b''.join(hdr[:-1]))\n" " except ValueError:\n" " raise ProtocolError('Non-numeric len %r' % hdr[:-1], hdr[:-1])\n" " parts = []\n" " received = 0\n" " while received < length:\n" - " parts.append(sys.stdin.read(length - received))\n" + " parts.append(sys.stdin.buffer.read(length - received))\n" " received += len(parts[-1])\n" - " data = ''.join(parts)\n" + " data = b''.join(parts)\n" " assert len(data) == length\n" " try:\n" - " return llsd.parse(data.encode())\n" + " return llsd.parse(data)\n" // Seems the old indra.base.llsd module didn't properly // convert IndexError (from running off end of string) to // LLSDParseError. @@ -179,11 +184,11 @@ namespace tut " return _reply\n" "\n" "def put(req):\n" - " sys.stdout.write(':'.join((str(len(req)), req)))\n" + " sys.stdout.buffer.write(b'%d:%b' % (len(req), req))\n" " sys.stdout.flush()\n" "\n" "def send(pump, data):\n" - " put(llsd.format_notation(dict(pump=pump, data=data)).decode())\n" + " put(llsd.format_notation(dict(pump=pump, data=data)))\n" "\n" "def request(pump, data):\n" " # we expect 'data' is a dict\n" diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 5dbcf4c9b8..acb2953b5b 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -46,20 +46,24 @@ typedef U32 uint32_t; #include "boost/range.hpp" #include "boost/foreach.hpp" -#include "boost/function.hpp" #include "boost/bind.hpp" #include "boost/phoenix/bind/bind_function.hpp" #include "boost/phoenix/core/argument.hpp" using namespace boost::phoenix; -#include "../llsd.h" -#include "../llsdserialize.h" +#include "llsd.h" +#include "llsdserialize.h" #include "llsdutil.h" -#include "../llformat.h" +#include "llformat.h" +#include "llmemorystream.h" #include "../test/lltut.h" #include "../test/namedtempfile.h" #include "stringize.h" +#include + +typedef std::function FormatterFunction; +typedef std::function ParserFunction; std::vector string_to_vector(const std::string& str) { @@ -112,7 +116,7 @@ namespace tut mSD = LLUUID::null; expected = "\n"; xml_test("null uuid", expected); - + mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); expected = "c96f9b1e-f589-4100-9774-d98643ce0bed\n"; xml_test("uuid", expected); @@ -136,7 +140,7 @@ namespace tut expected = "aGVsbG8=\n"; xml_test("binary", expected); } - + template<> template<> void sd_xml_object::test<2>() { @@ -225,7 +229,7 @@ namespace tut expected = "bazfoobar\n"; xml_test("2 element map", expected); } - + template<> template<> void sd_xml_object::test<6>() { @@ -241,7 +245,7 @@ namespace tut expected = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; xml_test("binary", expected); } - + class TestLLSDSerializeData { public: @@ -250,9 +254,34 @@ namespace tut void doRoundTripTests(const std::string&); void checkRoundTrip(const std::string&, const LLSD& v); - - LLPointer mFormatter; - LLPointer mParser; + + void setFormatterParser(LLPointer formatter, LLPointer parser) + { + mFormatter = [formatter](const LLSD& data, std::ostream& str) + { + formatter->format(data, str); + }; + // this lambda must be mutable since otherwise the bound 'parser' + // is assumed to point to a const LLSDParser + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable + { + // reset() call is needed since test code re-uses parser object + parser->reset(); + return (parser->parse(istr, data, max_bytes) > 0); + }; + } + + void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) + { + // why does LLSDSerialize::deserialize() reverse the parse() params?? + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) + { + return parser(data, istr, max_bytes); + }; + } + + FormatterFunction mFormatter; + ParserFunction mParser; }; TestLLSDSerializeData::TestLLSDSerializeData() @@ -265,12 +294,11 @@ namespace tut void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) { - std::stringstream stream; - mFormatter->format(v, stream); + std::stringstream stream; + mFormatter(v, stream); //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; LLSD w; - mParser->reset(); // reset() call is needed since test code re-uses mParser - mParser->parse(stream, w, stream.str().size()); + mParser(stream, w, stream.str().size()); try { @@ -299,52 +327,52 @@ namespace tut fillmap(root[key], width, depth - 1); } } - + void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) { LLSD v; checkRoundTrip(msg + " undefined", v); - + v = true; checkRoundTrip(msg + " true bool", v); - + v = false; checkRoundTrip(msg + " false bool", v); - + v = 1; checkRoundTrip(msg + " positive int", v); - + v = 0; checkRoundTrip(msg + " zero int", v); - + v = -1; checkRoundTrip(msg + " negative int", v); - + v = 1234.5f; checkRoundTrip(msg + " positive float", v); - + v = 0.0f; checkRoundTrip(msg + " zero float", v); - + v = -1234.5f; checkRoundTrip(msg + " negative float", v); - + // FIXME: need a NaN test - + v = LLUUID::null; checkRoundTrip(msg + " null uuid", v); - + LLUUID newUUID; newUUID.generate(); v = newUUID; checkRoundTrip(msg + " new uuid", v); - + v = ""; checkRoundTrip(msg + " empty string", v); - + v = "some string"; checkRoundTrip(msg + " non-empty string", v); - + v = "Second Life is a 3-D virtual world entirely built and owned by its residents. " "Since opening to the public in 2003, it has grown explosively and today is " @@ -372,7 +400,7 @@ namespace tut for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) { std::ostringstream out; - + for (U32 c = block; c < block + block_size; ++c) { if (c <= 0x000001f @@ -386,7 +414,7 @@ namespace tut if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } if ((c & 0x00fffe) == 0x00fffe) { continue; } // see Unicode standard, section 15.8 - + if (c <= 0x00007f) { out << (char)(c & 0x7f); @@ -410,55 +438,55 @@ namespace tut out << (char)(0x80 | ((c >> 0) & 0x3f)); } } - + v = out.str(); std::ostringstream blockmsg; blockmsg << msg << " unicode string block 0x" << std::hex << block; checkRoundTrip(blockmsg.str(), v); } - + LLDate epoch; v = epoch; checkRoundTrip(msg + " epoch date", v); - + LLDate aDay("2002-12-07T05:07:15.00Z"); v = aDay; checkRoundTrip(msg + " date", v); - + LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); v = path; checkRoundTrip(msg + " url", v); - + const char source[] = "it must be a blue moon again"; std::vector data; // note, includes terminating '\0' copy(&source[0], &source[sizeof(source)], back_inserter(data)); - + v = data; checkRoundTrip(msg + " binary", v); - + v = LLSD::emptyMap(); checkRoundTrip(msg + " empty map", v); - + v = LLSD::emptyMap(); v["name"] = "luke"; //v.insert("name", "luke"); v["age"] = 3; //v.insert("age", 3); checkRoundTrip(msg + " map", v); - + v.clear(); v["a"]["1"] = true; v["b"]["0"] = false; checkRoundTrip(msg + " nested maps", v); - + v = LLSD::emptyArray(); checkRoundTrip(msg + " empty array", v); - + v = LLSD::emptyArray(); v.append("ali"); v.append(28); checkRoundTrip(msg + " array", v); - + v.clear(); v[0][0] = true; v[1][0] = false; @@ -468,7 +496,7 @@ namespace tut fillmap(v, 10, 3); // 10^6 maps checkRoundTrip(msg + " many nested maps", v); } - + typedef tut::test_group TestLLSDSerializeGroup; typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); @@ -476,35 +504,106 @@ namespace tut template<> template<> void TestLLSDSerializeObject::test<1>() { - mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY); - mParser = new LLSDNotationParser(); + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), + new LLSDNotationParser()); doRoundTripTests("pretty binary notation serialization"); } template<> template<> void TestLLSDSerializeObject::test<2>() { - mFormatter = new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE); - mParser = new LLSDNotationParser(); + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); doRoundTripTests("raw binary notation serialization"); } template<> template<> void TestLLSDSerializeObject::test<3>() { - mFormatter = new LLSDXMLFormatter(); - mParser = new LLSDXMLParser(); + setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); doRoundTripTests("xml serialization"); } template<> template<> void TestLLSDSerializeObject::test<4>() { - mFormatter = new LLSDBinaryFormatter(); - mParser = new LLSDBinaryParser(); + setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); doRoundTripTests("binary serialization"); } + template<> template<> + void TestLLSDSerializeObject::test<5>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_BINARY)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<6>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_XML)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<7>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); + }; + setParser(LLSDSerialize::deserialize); + // In this test, serialize(LLSD_NOTATION) emits a header recognized by + // deserialize(). + doRoundTripTests("serialize(LLSD_NOTATION)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<8>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDNotationFormatter does not + // emit an llsd/notation header. + doRoundTripTests("LLSDNotationFormatter -> deserialize"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<9>() + { + setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDXMLParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDXMLFormatter does not + // emit an LLSD/XML header. + doRoundTripTests("LLSDXMLFormatter -> deserialize"); + }; + +/*==========================================================================*| + // We do not expect this test to succeed. Without a header, neither + // notation LLSD nor binary LLSD reliably start with a distinct character, + // the way XML LLSD starts with '<'. By convention, we default to notation + // rather than binary. + template<> template<> + void TestLLSDSerializeObject::test<10>() + { + setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDBinaryParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDBinaryFormatter does not + // emit an LLSD/Binary header. + doRoundTripTests("LLSDBinaryFormatter -> deserialize"); + }; +|*==========================================================================*/ /** * @class TestLLSDParsing @@ -555,7 +654,7 @@ namespace tut public: TestLLSDXMLParsing() {} }; - + typedef tut::test_group TestLLSDXMLParsingGroup; typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); @@ -586,8 +685,8 @@ namespace tut LLSD(), LLSDParser::PARSE_FAILURE); } - - + + template<> template<> void TestLLSDXMLParsingObject::test<2>() { @@ -596,7 +695,7 @@ namespace tut v["amy"] = 23; v["bob"] = LLSD(); v["cam"] = 1.23; - + ensureParse( "unknown data type", "" @@ -607,16 +706,16 @@ namespace tut v, v.size() + 1); } - + template<> template<> void TestLLSDXMLParsingObject::test<3>() { // test handling of nested bad data - + LLSD v; v["amy"] = 23; v["cam"] = 1.23; - + ensureParse( "map with html", "" @@ -626,7 +725,7 @@ namespace tut "", v, v.size() + 1); - + v.clear(); v["amy"] = 23; v["cam"] = 1.23; @@ -639,7 +738,7 @@ namespace tut "", v, v.size() + 1); - + v.clear(); v["amy"] = 23; v["bob"] = LLSD::emptyMap(); @@ -661,7 +760,7 @@ namespace tut v[0] = 23; v[1] = LLSD(); v[2] = 1.23; - + ensureParse( "array value of html", "" @@ -671,7 +770,7 @@ namespace tut "", v, v.size() + 1); - + v.clear(); v[0] = 23; v[1] = LLSD::emptyMap(); @@ -1225,7 +1324,7 @@ namespace tut vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; LLSD value = vec; - + vec.resize(11); vec[0] = 'b'; // for binary vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; @@ -1694,85 +1793,83 @@ namespace tut ensureBinaryAndXML("map", test); } - struct TestPythonCompatible + // helper for TestPythonCompatible + static std::string import_llsd("import os.path\n" + "import sys\n" + "try:\n" + // new freestanding llsd package + " import llsd\n" + "except ImportError:\n" + // older llbase.llsd module + " from llbase import llsd\n"); + + // helper for TestPythonCompatible + template + void python(const std::string& desc, const CONTENT& script, int expect=0) { - TestPythonCompatible(): - // Note the peculiar insertion of __FILE__ into this string. Since - // this script is being written into a platform-dependent temp - // directory, we can't locate indra/lib/python relative to - // Python's __file__. Use __FILE__ instead, navigating relative - // to this C++ source file. Use Python raw-string syntax so - // Windows pathname backslashes won't mislead Python's string - // scanner. - import_llsd("import os.path\n" - "import sys\n" - "from llbase import llsd\n") - {} - ~TestPythonCompatible() {} + auto PYTHON(LLStringUtil::getenv("PYTHON")); + ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty()); - std::string import_llsd; - - template - void python(const std::string& desc, const CONTENT& script, int expect=0) - { - auto PYTHON(LLStringUtil::getenv("PYTHON")); - ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty()); - - NamedTempFile scriptfile("py", script); + NamedTempFile scriptfile("py", script); #if LL_WINDOWS - std::string q("\""); - std::string qPYTHON(q + PYTHON + q); - std::string qscript(q + scriptfile.getName() + q); - int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL); - if (rc == -1) - { - char buffer[256]; - strerror_s(buffer, errno); // C++ can infer the buffer size! :-O - ensure(STRINGIZE("Couldn't run Python " << desc << "script: " << buffer), false); - } - else - { - ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, expect); - } + std::string q("\""); + std::string qPYTHON(q + PYTHON + q); + std::string qscript(q + scriptfile.getName() + q); + int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL); + if (rc == -1) + { + char buffer[256]; + strerror_s(buffer, errno); // C++ can infer the buffer size! :-O + ensure(STRINGIZE("Couldn't run Python " << desc << "script: " << buffer), false); + } + else + { + ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, expect); + } #else // LL_DARWIN, LL_LINUX - LLProcess::Params params; - params.executable = PYTHON; - params.args.add(scriptfile.getName()); - LLProcessPtr py(LLProcess::create(params)); - ensure(STRINGIZE("Couldn't launch " << desc << " script"), bool(py)); - // Implementing timeout would mean messing with alarm() and - // catching SIGALRM... later maybe... - int status(0); - if (waitpid(py->getProcessID(), &status, 0) == -1) + LLProcess::Params params; + params.executable = PYTHON; + params.args.add(scriptfile.getName()); + LLProcessPtr py(LLProcess::create(params)); + ensure(STRINGIZE("Couldn't launch " << desc << " script"), bool(py)); + // Implementing timeout would mean messing with alarm() and + // catching SIGALRM... later maybe... + int status(0); + if (waitpid(py->getProcessID(), &status, 0) == -1) + { + int waitpid_errno(errno); + ensure_equals(STRINGIZE("Couldn't retrieve rc from " << desc << " script: " + "waitpid() errno " << waitpid_errno), + waitpid_errno, ECHILD); + } + else + { + if (WIFEXITED(status)) { - int waitpid_errno(errno); - ensure_equals(STRINGIZE("Couldn't retrieve rc from " << desc << " script: " - "waitpid() errno " << waitpid_errno), - waitpid_errno, ECHILD); + int rc(WEXITSTATUS(status)); + ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), + rc, expect); + } + else if (WIFSIGNALED(status)) + { + ensure(STRINGIZE(desc << " script terminated by signal " << WTERMSIG(status)), + false); } else { - if (WIFEXITED(status)) - { - int rc(WEXITSTATUS(status)); - ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), - rc, expect); - } - else if (WIFSIGNALED(status)) - { - ensure(STRINGIZE(desc << " script terminated by signal " << WTERMSIG(status)), - false); - } - else - { - ensure(STRINGIZE(desc << " script produced impossible status " << status), - false); - } + ensure(STRINGIZE(desc << " script produced impossible status " << status), + false); } -#endif } +#endif + } + + struct TestPythonCompatible + { + TestPythonCompatible() {} + ~TestPythonCompatible() {} }; typedef tut::test_group TestPythonCompatibleGroup; @@ -1798,25 +1895,33 @@ namespace tut "print('Running on', sys.platform)\n"); } - // helper for test<3> - static void writeLLSDArray(std::ostream& out, const LLSD& array) + // helper for test<3> - test<7> + static void writeLLSDArray(const FormatterFunction& serialize, + std::ostream& out, const LLSD& array) { - BOOST_FOREACH(LLSD item, llsd::inArray(array)) + for (const LLSD& item : llsd::inArray(array)) { - LLSDSerialize::toNotation(item, out); - // It's important to separate with newlines because Python's llsd - // module doesn't support parsing from a file stream, only from a - // string, so we have to know how much of the file to read into a - // string. - out << '\n'; + // It's important to delimit the entries in this file somehow + // because, although Python's llsd.parse() can accept a file + // stream, the XML parser expects EOF after a single outer element + // -- it doesn't just stop. So we must extract a sequence of bytes + // strings from the file. But since one of the serialization + // formats we want to test is binary, we can't pick any single + // byte value as a delimiter! Use a binary integer length prefix + // instead. + std::ostringstream buffer; + serialize(item, buffer); + auto buffstr{ buffer.str() }; + int bufflen{ static_cast(buffstr.length()) }; + out.write(reinterpret_cast(&bufflen), sizeof(bufflen)); + out.write(buffstr.c_str(), buffstr.length()); } } - template<> template<> - void TestPythonCompatibleObject::test<3>() + // helper for test<3> - test<7> + static void toPythonUsing(const std::string& desc, + const FormatterFunction& serialize) { - set_test_name("verify sequence to Python"); - LLSD cdata(llsd::array(17, 3.14, "This string\n" "has several\n" @@ -1836,7 +1941,7 @@ namespace tut " except StopIteration:\n" " pass\n" " else:\n" - " assert False, 'Too many data items'\n"; + " raise AssertionError('Too many data items')\n"; // Create an llsdXXXXXX file containing 'data' serialized to // notation. @@ -1845,32 +1950,128 @@ namespace tut // takes a callable. To this callable it passes the // std::ostream with which it's writing the // NamedTempFile. - boost::bind(writeLLSDArray, _1, cdata)); + [serialize, cdata] + (std::ostream& out) + { writeLLSDArray(serialize, out, cdata); }); - python("read C++ notation", + python("read C++ " + desc, placeholders::arg1 << import_llsd << - "def parse_each(iterable):\n" - " for item in iterable:\n" - " yield llsd.parse(item)\n" << - pydata << + "from functools import partial\n" + "import io\n" + "import struct\n" + "lenformat = struct.Struct('i')\n" + "def parse_each(inf):\n" + " for rawlen in iter(partial(inf.read, lenformat.size), b''):\n" + " len = lenformat.unpack(rawlen)[0]\n" + // Since llsd.parse() has no max_bytes argument, instead of + // passing the input stream directly to parse(), read the item + // into a distinct bytes object and parse that. + " data = inf.read(len)\n" + " try:\n" + " frombytes = llsd.parse(data)\n" + " except llsd.LLSDParseError as err:\n" + " print(f'*** {err}')\n" + " print(f'Bad content:\\n{data!r}')\n" + " raise\n" + // Also try parsing from a distinct stream. + " stream = io.BytesIO(data)\n" + " fromstream = llsd.parse(stream)\n" + " assert frombytes == fromstream\n" + " yield frombytes\n" + << pydata << // Don't forget raw-string syntax for Windows pathnames. "verify(parse_each(open(r'" << file.getName() << "', 'rb')))\n"); } + template<> template<> + void TestPythonCompatibleObject::test<3>() + { + set_test_name("to Python using LLSDSerialize::serialize(LLSD_XML)"); + toPythonUsing("LLSD_XML", + [](const LLSD& sd, std::ostream& out) + { LLSDSerialize::serialize(sd, out, LLSDSerialize::LLSD_XML); }); + } + template<> template<> void TestPythonCompatibleObject::test<4>() { - set_test_name("verify sequence from Python"); + set_test_name("to Python using LLSDSerialize::serialize(LLSD_NOTATION)"); + toPythonUsing("LLSD_NOTATION", + [](const LLSD& sd, std::ostream& out) + { LLSDSerialize::serialize(sd, out, LLSDSerialize::LLSD_NOTATION); }); + } + template<> template<> + void TestPythonCompatibleObject::test<5>() + { + set_test_name("to Python using LLSDSerialize::serialize(LLSD_BINARY)"); + toPythonUsing("LLSD_BINARY", + [](const LLSD& sd, std::ostream& out) + { LLSDSerialize::serialize(sd, out, LLSDSerialize::LLSD_BINARY); }); + } + + template<> template<> + void TestPythonCompatibleObject::test<6>() + { + set_test_name("to Python using LLSDSerialize::toXML()"); + toPythonUsing("toXML()", LLSDSerialize::toXML); + } + + template<> template<> + void TestPythonCompatibleObject::test<7>() + { + set_test_name("to Python using LLSDSerialize::toNotation()"); + toPythonUsing("toNotation()", LLSDSerialize::toNotation); + } + +/*==========================================================================*| + template<> template<> + void TestPythonCompatibleObject::test<8>() + { + set_test_name("to Python using LLSDSerialize::toBinary()"); + // We don't expect this to work because, without a header, + // llsd.parse() will assume notation rather than binary. + toPythonUsing("toBinary()", LLSDSerialize::toBinary); + } +|*==========================================================================*/ + + // helper for test<8> - test<12> + bool itemFromStream(std::istream& istr, LLSD& item, const ParserFunction& parse) + { + // reset the output value for debugging clarity + item.clear(); + // We use an int length prefix as a foolproof delimiter even for + // binary serialized streams. + int length{ 0 }; + istr.read(reinterpret_cast(&length), sizeof(length)); +// return parse(istr, item, length); + // Sadly, as of 2022-12-01 it seems we can't really trust our LLSD + // parsers to honor max_bytes: this test works better when we read + // each item into its own distinct LLMemoryStream, instead of passing + // the original istr with a max_bytes constraint. + std::vector buffer(length); + istr.read(reinterpret_cast(buffer.data()), length); + LLMemoryStream stream(buffer.data(), length); + return parse(stream, item, length); + } + + // helper for test<8> - test<12> + void fromPythonUsing(const std::string& pyformatter, + const ParserFunction& parse= + [](std::istream& istr, LLSD& data, llssize max_bytes) + { return LLSDSerialize::deserialize(data, istr, max_bytes); }) + { // Create an empty data file. This is just a placeholder for our // script to write into. Create it to establish a unique name that // we know. NamedTempFile file("llsd", ""); - python("write Python notation", + python("Python " + pyformatter, placeholders::arg1 << import_llsd << + "import struct\n" + "lenformat = struct.Struct('i')\n" "DATA = [\n" " 17,\n" " 3.14,\n" @@ -1881,34 +2082,87 @@ namespace tut "]\n" // Don't forget raw-string syntax for Windows pathnames. // N.B. Using 'print' implicitly adds newlines. - "with open(r'" << file.getName() << "', 'w') as f:\n" + "with open(r'" << file.getName() << "', 'wb') as f:\n" " for item in DATA:\n" - " print(llsd.format_notation(item).decode(), file=f)\n"); + " serialized = llsd." << pyformatter << "(item)\n" + " f.write(lenformat.pack(len(serialized)))\n" + " f.write(serialized)\n"); std::ifstream inf(file.getName().c_str()); LLSD item; - // Notice that we're not doing anything special to parse out the - // newlines: LLSDSerialize::fromNotation ignores them. While it would - // seem they're not strictly necessary, going in this direction, we - // want to ensure that notation-separated-by-newlines works in both - // directions -- since in practice, a given file might be read by - // either language. - ensure_equals("Failed to read LLSD::Integer from Python", - LLSDSerialize::fromNotation(item, inf, LLSDSerialize::SIZE_UNLIMITED), - 1); - ensure_equals(item.asInteger(), 17); - ensure_equals("Failed to read LLSD::Real from Python", - LLSDSerialize::fromNotation(item, inf, LLSDSerialize::SIZE_UNLIMITED), - 1); - ensure_approximately_equals("Bad LLSD::Real value from Python", - item.asReal(), 3.14, 7); // 7 bits ~= 0.01 - ensure_equals("Failed to read LLSD::String from Python", - LLSDSerialize::fromNotation(item, inf, LLSDSerialize::SIZE_UNLIMITED), - 1); - ensure_equals(item.asString(), - "This string\n" - "has several\n" - "lines."); - + try + { + ensure("Failed to read LLSD::Integer from Python", + itemFromStream(inf, item, parse)); + ensure_equals(item.asInteger(), 17); + ensure("Failed to read LLSD::Real from Python", + itemFromStream(inf, item, parse)); + ensure_approximately_equals("Bad LLSD::Real value from Python", + item.asReal(), 3.14, 7); // 7 bits ~= 0.01 + ensure("Failed to read LLSD::String from Python", + itemFromStream(inf, item, parse)); + ensure_equals(item.asString(), + "This string\n" + "has several\n" + "lines."); + } + catch (const tut::failure& err) + { + std::cout << "for " << err.what() << ", item = " << item << std::endl; + throw; + } } + + template<> template<> + void TestPythonCompatibleObject::test<8>() + { + set_test_name("from Python XML using LLSDSerialize::deserialize()"); + fromPythonUsing("format_xml"); + } + + template<> template<> + void TestPythonCompatibleObject::test<9>() + { + set_test_name("from Python notation using LLSDSerialize::deserialize()"); + fromPythonUsing("format_notation"); + } + + template<> template<> + void TestPythonCompatibleObject::test<10>() + { + set_test_name("from Python binary using LLSDSerialize::deserialize()"); + fromPythonUsing("format_binary"); + } + + template<> template<> + void TestPythonCompatibleObject::test<11>() + { + set_test_name("from Python XML using fromXML()"); + // fromXML()'s optional 3rd param isn't max_bytes, it's emit_errors + fromPythonUsing("format_xml", + [](std::istream& istr, LLSD& data, llssize) + { return LLSDSerialize::fromXML(data, istr) > 0; }); + } + + template<> template<> + void TestPythonCompatibleObject::test<12>() + { + set_test_name("from Python notation using fromNotation()"); + fromPythonUsing("format_notation", + [](std::istream& istr, LLSD& data, llssize max_bytes) + { return LLSDSerialize::fromNotation(data, istr, max_bytes) > 0; }); + } + +/*==========================================================================*| + template<> template<> + void TestPythonCompatibleObject::test<13>() + { + set_test_name("from Python binary using fromBinary()"); + // We don't expect this to work because format_binary() emits a + // header, but fromBinary() won't recognize a header. + fromPythonUsing("format_binary", + [](std::istream& istr, LLSD& data, llssize max_bytes) + { return LLSDSerialize::fromBinary(data, istr, max_bytes) > 0; }); + } +|*==========================================================================*/ } diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py index 185e8e25c6..b9992538ba 100755 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py @@ -38,7 +38,7 @@ from io import StringIO from http.server import HTTPServer, BaseHTTPRequestHandler -from llbase import llsd +import llsd # we're in llcorehttp/tests ; testrunner.py is found in llmessage/tests sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 40f7b1e9fb..3b586d721f 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5482,14 +5482,14 @@ bool LLVolumeFace::cacheOptimize() new_indices.push_back(tri->mVertex[2]->mIdx); tri->complete(); - U32 breaks = 0; + //U32 breaks = 0; for (U32 i = 1; i < mNumIndices/3; ++i) { cache.updateScores(); tri = cache.mBestTriangle; if (!tri) { - breaks++; + //breaks++; for (U32 j = 0; j < triangle_data.size(); ++j) { if (triangle_data[j].mActive) diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 8baa2e328b..a9a292958f 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -271,7 +271,6 @@ void LLCircuitData::ackReliablePacket(TPACKETID packet_num) S32 LLCircuitData::resendUnackedPackets(const F64Seconds now) { - S32 resent_packets = 0; LLReliablePacket *packetp; @@ -375,7 +374,6 @@ S32 LLCircuitData::resendUnackedPackets(const F64Seconds now) // Don't remove it yet, it still gets to try to resend at least once. ++iter; } - resent_packets++; } else { diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index c8c9280029..6b9ce54c92 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -1336,6 +1336,48 @@ void HttpCoroutineAdapter::trivialPostCoro(std::string url, LLCore::HttpRequest: } +/*static*/ +void HttpCoroutineAdapter::callbackHttpDel(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, + completionCallback_t failure) +{ + LLCoros::instance().launch("HttpCoroutineAdapter::genericDelCoro", + boost::bind(&HttpCoroutineAdapter::trivialDelCoro, url, policyId, success, failure)); +} + +/*static*/ +void HttpCoroutineAdapter::trivialDelCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, + completionCallback_t failure) +{ + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericDelCoro", policyId)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + + LL_INFOS("HttpCoroutineAdapter", "genericDelCoro") << "Generic DEL for " << url << LL_ENDL; + + LLSD result = httpAdapter->deleteAndSuspend(httpRequest, url, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + if (failure) + { + failure(httpResults); + } + } + else + { + if (success) + { + success(result); + } + } +} + + } // end namespace LLCoreHttpUtil diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index 6f0b865f83..8df1425f2a 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -608,6 +608,9 @@ public: callbackHttpPost(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, postData, success, failure); } + static void callbackHttpDel(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success = NULL, + completionCallback_t failure = NULL); + /// Generic Get and post routines for HTTP via coroutines. /// These static methods do all required setup for the GET or POST operation. /// When the operation completes successfully they will put the success message in the log at INFO level, @@ -669,6 +672,7 @@ private: static void trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure); static void trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure); + static void trivialDelCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure); void checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers); diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 8548ed51e7..464bf05250 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -171,8 +171,9 @@ const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9; const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10; const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11; -const S32 ESTATE_MAX_MANAGERS = 15; -const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned +const S32 ESTATE_MAX_MANAGERS = 20; +const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access +const S32 ESTATE_MAX_BANNED_IDS = 750; // max for banned const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET; // 'Sim Wide Delete' flags diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index 5ba0749e31..8e9b6c09e7 100755 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -33,8 +33,8 @@ import os import sys from http.server import HTTPServer, BaseHTTPRequestHandler -from llbase.fastest_elementtree import parse as xml_parse -from llbase import llsd +from llsd.fastest_elementtree import parse as xml_parse +import llsd from testrunner import freeport, run, debug, VERBOSE import time diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h index ee663f8f99..c66e3e30a3 100644 --- a/indra/llprimitive/llmaterialid.h +++ b/indra/llprimitive/llmaterialid.h @@ -66,6 +66,14 @@ public: static const LLMaterialID null; + // Returns a 64 bits digest of the material Id, by XORing its two 64 bits + // long words. HB + inline U64 getDigest64() const + { + U64* tmp = (U64*)mID; + return tmp[0] ^ tmp[1]; + } + private: void parseFromBinary(const LLSD::Binary& pMaterialID); void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID); @@ -74,5 +82,23 @@ private: U8 mID[MATERIAL_ID_SIZE]; } ; +// std::hash implementation for LLMaterialID +namespace std +{ + template<> struct hash + { + inline size_t operator()(const LLMaterialID& id) const noexcept + { + return (size_t)id.getDigest64(); + } + }; +} + +// For use with boost containers. +inline size_t hash_value(const LLMaterialID& id) noexcept +{ + return (size_t)id.getDigest64(); +} + #endif // LL_LLMATERIALID_H diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 193cfa64b8..cfc9ce735d 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2329,9 +2329,7 @@ void LLGLSyncFence::wait() if (mSync) { while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) - { //track the number of times we've waited here - static S32 waits = 0; - waits++; + { } } #endif diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index a38b3323be..49d275997a 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -943,11 +943,8 @@ void LLButton::draw() break; } - S32 y_offset = 2 + (getRect().getHeight() - 20)/2; - if (pressed && mDisplayPressedState) { - y_offset--; x++; } diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index 48bf5bb80f..220f5ee825 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -68,6 +68,7 @@ LLDragHandle::LLDragHandle(const LLDragHandle::Params& p) LLDragHandle::~LLDragHandle() { + gFocusMgr.removeKeyboardFocusWithoutCallback(this); removeChild(mTitleBox); delete mTitleBox; } diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 38a1a9a1ab..0dc66bf37a 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -182,6 +182,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) LLFolderViewItem::~LLFolderViewItem() { mViewModelItem = NULL; + gFocusMgr.removeKeyboardFocusWithoutCallback(this); } BOOL LLFolderViewItem::postBuild() diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index b1968e6a42..7e4e828a88 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -89,6 +89,8 @@ LLLayoutPanel::~LLLayoutPanel() // probably not necessary, but... delete mResizeBar; mResizeBar = NULL; + + gFocusMgr.removeKeyboardFocusWithoutCallback(this); } F32 LLLayoutPanel::getAutoResizeFactor() const diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 1666ff8c98..cebca70b59 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -487,9 +487,6 @@ void LLMenuItemGL::draw( void ) // let disabled items be highlighted, just don't draw them as such if( getEnabled() && getHighlight() && !mBriefItem) { - int debug_count = 0; - if (dynamic_cast(this)) - debug_count++; gGL.color4fv( mHighlightBackground.get().mV ); gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); diff --git a/indra/llui/llresizehandle.cpp b/indra/llui/llresizehandle.cpp index 24794305ac..13ef0fdb7f 100644 --- a/indra/llui/llresizehandle.cpp +++ b/indra/llui/llresizehandle.cpp @@ -70,6 +70,11 @@ LLResizeHandle::LLResizeHandle(const LLResizeHandle::Params& p) } } +LLResizeHandle::~LLResizeHandle() +{ + gFocusMgr.removeKeyboardFocusWithoutCallback(this); +} + BOOL LLResizeHandle::handleMouseDown(S32 x, S32 y, MASK mask) { diff --git a/indra/llui/llresizehandle.h b/indra/llui/llresizehandle.h index 7541b9e6c0..ae20ecaa77 100644 --- a/indra/llui/llresizehandle.h +++ b/indra/llui/llresizehandle.h @@ -45,6 +45,7 @@ public: Params(); }; + ~LLResizeHandle(); protected: LLResizeHandle(const LLResizeHandle::Params&); friend class LLUICtrlFactory; diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index ead8634df4..2960ecf829 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -774,7 +774,6 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require return 0; } - U32 item = 0; U32 validitems = 0; S32 version; @@ -808,8 +807,6 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require } // Got an item. Load it up. - item++; - // If not declared, assume it's a string if (!declared) { diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index e9d5f8c17f..b69c12176f 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.6.14 +6.6.15 diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index e16a5c7e76..340334aee8 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -209,6 +209,12 @@ NoAudio + nofmod + + map-to + UseMediaPluginsForStreamingAudio + + noninteractive desc diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index edb0c6b4d1..28d84aba21 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7077,6 +7077,17 @@ Value 0 + UseMediaPluginsForStreamingAudio + + Comment + Use media plugins (VLC) for streaming audio. + Persist + 1 + Type + Boolean + Value + 0 + NoHardwareProbe Comment @@ -11349,11 +11360,11 @@ ShowBanLines Comment - Show in-world ban/access borders + Show in-world ban/access borders, 0 - do not show, 1 - show on collision, 2 - show on proximity Persist 1 Type - Boolean + S32 Value 1 @@ -16997,17 +17008,6 @@ Value 0 - 360CaptureUseInterestListCap - - Comment - Flag if set, uses the new InterestList cap to ask the simulator for full content - Persist - 1 - Type - Boolean - Value - 1 - 360CaptureJPEGEncodeQuality Comment @@ -17129,6 +17129,39 @@ Value 0 + StatsReportMaxDuration + + Comment + Maximum seconds for viewer stats file data, prevents huge file + Persist + 1 + Type + F32 + Value + 300 + + StatsReportFileInterval + + Comment + Interval to save viewer stats file data + Persist + 1 + Type + F32 + Value + 0.2 + + StatsReportSkipZeroDataSaves + + Comment + In viewer stats data file, skip saving entry if there is no data + Persist + 0 + Type + Boolean + Value + 0 + MultiModeDoubleClickFolder Comment diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 60e26274cb..ed37f541c8 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -507,7 +507,7 @@ Call un.UserSettingsFiles SectionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Make sure the user can install +;; Make sure the user can install/uninstall ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function CheckIfAdministrator DetailPrint $(CheckAdministratorInstDP) @@ -521,21 +521,6 @@ lbl_is_admin: FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Make sure the user can uninstall -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function un.CheckIfAdministrator - DetailPrint $(CheckAdministratorUnInstDP) - UserInfo::GetAccountType - Pop $R0 - StrCmp $R0 "Admin" lbl_is_admin - MessageBox MB_OK $(CheckAdministratorUnInstMB) - Quit -lbl_is_admin: - Return - -FunctionEnd - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Function CheckWillUninstallV2 ;; diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsi index 7922d9df52..0985663041 100755 Binary files a/indra/newview/installers/windows/lang_zh.nsi and b/indra/newview/installers/windows/lang_zh.nsi differ diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index bca2ce4b99..77fe601c1e 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -406,6 +406,7 @@ LLAgent::LLAgent() : mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), mTeleportState(TELEPORT_NONE), mRegionp(NULL), + mInterestListMode(LLViewerRegion::IL_MODE_DEFAULT), mAgentOriginGlobal(), mPositionGlobal(), @@ -986,11 +987,19 @@ boost::signals2::connection LLAgent::addParcelChangedCallback(parcel_changed_cal // static void LLAgent::capabilityReceivedCallback(const LLUUID ®ion_id, LLViewerRegion *regionp) -{ - if (regionp && regionp->getRegionID() == region_id) +{ // Changed regions and now have the region capabilities + if (regionp) { - regionp->requestSimulatorFeatures(); - LLAppViewer::instance()->updateNameLookupUrl(regionp); + if (regionp->getRegionID() == region_id) + { + regionp->requestSimulatorFeatures(); + LLAppViewer::instance()->updateNameLookupUrl(regionp); + } + + if (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360) + { + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); + } } } @@ -1454,26 +1463,21 @@ LLVector3 LLAgent::getReferenceUpVector() void LLAgent::pitch(F32 angle) { // don't let user pitch if pointed almost all the way down or up - mFrameAgent.pitch(clampPitchToLimits(angle)); -} - -// Radians, positive is forward into ground -//----------------------------------------------------------------------------- -// clampPitchToLimits() -//----------------------------------------------------------------------------- -F32 LLAgent::clampPitchToLimits(F32 angle) -{ // A dot B = mag(A) * mag(B) * cos(angle between A and B) // so... cos(angle between A and B) = A dot B / mag(A) / mag(B) // = A dot B for unit vectors LLVector3 skyward = getReferenceUpVector(); - const F32 look_down_limit = 179.f * DEG_TO_RAD;; - const F32 look_up_limit = 1.f * DEG_TO_RAD; + // SL-19286 Avatar is upside down when viewed from below + // after left-clicking the mouse on the avatar and dragging down + // + // The issue is observed on angle below 10 degrees + const F32 look_down_limit = 179.f * DEG_TO_RAD; + const F32 look_up_limit = 10.f * DEG_TO_RAD; - F32 angle_from_skyward = acos( mFrameAgent.getAtAxis() * skyward ); + F32 angle_from_skyward = acos(mFrameAgent.getAtAxis() * skyward); // clamp pitch to limits if ((angle >= 0.f) && (angle_from_skyward + angle > look_down_limit)) @@ -1484,8 +1488,11 @@ F32 LLAgent::clampPitchToLimits(F32 angle) { angle = look_up_limit - angle_from_skyward; } - - return angle; + + if (fabs(angle) > 1e-4) + { + mFrameAgent.pitch(angle); + } } @@ -3002,39 +3009,60 @@ void LLAgent::processMaturityPreferenceFromServer(const LLSD &result, U8 perferr handlePreferredMaturityResult(maturity); } +// Using a new capability, tell the simulator that we want it to send everything +// it knows about and not just what is in front of the camera, in its view +// frustum. We need this feature so that the contents of the region that appears +// in the 6 snapshots which we cannot see and is normally not "considered", is +// also rendered. Typically, this is turned on when the 360 capture floater is +// opened and turned off when it is closed. +// Note: for this version, we do not have a way to determine when "everything" +// has arrived and has been rendered so for now, the proposal is that users +// will need to experiment with the low resolution version and wait for some +// (hopefully) small period of time while the full contents resolves. +// Pass in a flag to ask the simulator/interest list to "send everything" or +// not (the default mode) +void LLAgent::changeInterestListMode(const std::string &new_mode) +{ + if (new_mode != mInterestListMode) + { + mInterestListMode = new_mode; + + // Change interest list mode for all regions. If they are already set for the current mode, + // the setting will have no effect. + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); + ++iter) + { + LLViewerRegion *regionp = *iter; + if (regionp && regionp->isAlive() && regionp->capabilitiesReceived()) + { + regionp->setInterestListMode(mInterestListMode); + } + } + } + else + { + LL_DEBUGS("360Capture") << "Agent interest list mode is already set to " << mInterestListMode << LL_ENDL; + } +} + bool LLAgent::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure) { - if (!getRegion()) + if (getRegion()) { - return false; + return getRegion()->requestPostCapability(capName, postData, cbSuccess, cbFailure); } - std::string url = getRegion()->getCapability(capName); - - if (url.empty()) - { - LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL; - return false; - } - - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, mHttpPolicy, postData, cbSuccess, cbFailure); - return true; + return false; } bool LLAgent::requestGetCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure) { - std::string url; - - url = getRegionCapability(capName); - - if (url.empty()) + if (getRegion()) { - LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL; - return false; + return getRegion()->requestGetCapability(capName, cbSuccess, cbFailure); } - - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(url, mHttpPolicy, cbSuccess, cbFailure); - return true; + return false; } BOOL LLAgent::getAdminOverride() const @@ -3800,7 +3828,6 @@ void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **) // take controls msg->getU32("Data", "Controls", controls, block_index ); msg->getBOOL("Data", "PassToAgent", passon, block_index ); - U32 total_count = 0; for (i = 0; i < TOTAL_CONTROLS; i++) { if (controls & ( 1 << i)) @@ -3813,7 +3840,6 @@ void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **) { gAgent.mControlsTakenCount[i]++; } - total_count++; } } } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 0ce6fda131..fd3a9b1d7b 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -299,10 +299,16 @@ public: boost::signals2::connection addRegionChangedCallback(const region_changed_signal_t::slot_type& cb); void removeRegionChangedCallback(boost::signals2::connection callback); + + void changeInterestListMode(const std::string & new_mode); + const std::string & getInterestListMode() const { return mInterestListMode; } + private: LLViewerRegion *mRegionp; region_changed_signal_t mRegionChangedSignal; + std::string mInterestListMode; // How agent wants regions to send updates + //-------------------------------------------------------------------- // History //-------------------------------------------------------------------- @@ -553,7 +559,6 @@ public: void roll(F32 angle); void yaw(F32 angle); LLVector3 getReferenceUpVector(); - F32 clampPitchToLimits(F32 angle); //-------------------------------------------------------------------- // Autopilot diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 77131efd75..d2fe570069 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -401,10 +401,15 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi // if is avatar - don't do any funk heuristics to position the focal point // see DEV-30589 - if (object->isAvatar() || (object->isAnimatedObject() && object->getControlAvatar())) + if ((object->isAvatar() && !object->isRoot()) || (object->isAnimatedObject() && object->getControlAvatar())) { return original_focus_point - obj_pos; } + if (object->isAvatar()) + { + LLVOAvatar* av = object->asAvatar(); + return original_focus_point - av->getCharacterPosition(); + } LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation LLVector3 object_extents = object->getScale(); @@ -1759,13 +1764,24 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) LL_WARNS() << "Null avatar drawable!" << LL_ENDL; return LLVector3d::zero; } + head_offset.clearVec(); + F32 fixup; + if (gAgentAvatarp->hasPelvisFixup(fixup)) + { + head_offset[VZ] -= fixup; + } + if (gAgentAvatarp->isSitting()) + { + head_offset.mdV[VZ] += 0.1; + } + if (gAgentAvatarp->isSitting() && gAgentAvatarp->getParent()) { gAgentAvatarp->updateHeadOffset(); - head_offset.mdV[VX] = gAgentAvatarp->mHeadOffset.mV[VX]; - head_offset.mdV[VY] = gAgentAvatarp->mHeadOffset.mV[VY]; - head_offset.mdV[VZ] = gAgentAvatarp->mHeadOffset.mV[VZ] + 0.1f; + head_offset.mdV[VX] += gAgentAvatarp->mHeadOffset.mV[VX]; + head_offset.mdV[VY] += gAgentAvatarp->mHeadOffset.mV[VY]; + head_offset.mdV[VZ] += gAgentAvatarp->mHeadOffset.mV[VZ]; const LLMatrix4& mat = ((LLViewerObject*) gAgentAvatarp->getParent())->getRenderMatrix(); camera_position_global = gAgent.getPosGlobalFromAgent ((gAgentAvatarp->getPosition()+ @@ -1773,11 +1789,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) } else { - head_offset.mdV[VZ] = gAgentAvatarp->mHeadOffset.mV[VZ]; - if (gAgentAvatarp->isSitting()) - { - head_offset.mdV[VZ] += 0.1; - } + head_offset.mdV[VZ] += gAgentAvatarp->mHeadOffset.mV[VZ]; camera_position_global = gAgent.getPosGlobalFromAgent(gAgentAvatarp->getRenderPosition());//frame_center_global; head_offset = head_offset * gAgentAvatarp->getRenderRotation(); camera_position_global = camera_position_global + head_offset; diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index b7f5aeb8e0..77a3d47aea 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -35,6 +35,7 @@ #include "llcommandhandler.h" #include "llslurl.h" #include "llurldispatcher.h" +#include "llviewernetwork.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" @@ -148,7 +149,7 @@ void LLAgentListener::requestTeleport(LLSD const & event_data) const params.append(event_data["x"]); params.append(event_data["y"]); params.append(event_data["z"]); - LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, LLCommandHandler::NAV_TYPE_CLICKED, true); + LLCommandDispatcher::dispatch("teleport", params, LLSD(), LLGridManager::getInstance()->getGrid(), NULL, LLCommandHandler::NAV_TYPE_CLICKED, true); // *TODO - lookup other LLCommandHandlers for "agent", "classified", "event", "group", "floater", "parcel", "login", login_refresh", "balance", "chat" // should we just compose LLCommandHandler and LLDispatchListener? } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index c19ad2ae6f..acb1a37ff5 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -82,9 +82,9 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const if (!region || !parcel) return FALSE; - S32 pos_x = S32(agent_pos_region.mV[VX]); - S32 pos_y = S32(agent_pos_region.mV[VY]); - S32 pos_z = S32(agent_pos_region.mV[VZ]); + S32 pos_x = S32(agent_pos_region.mV[VX] + 0.5f); + S32 pos_y = S32(agent_pos_region.mV[VY] + 0.5f); + S32 pos_z = S32(agent_pos_region.mV[VZ] + 0.5f); // Round the numbers based on the velocity F32 velocity_mag_sq = gAgent.getVelocity().magVecSquared(); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 0d63b91882..db99f20775 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -41,7 +41,6 @@ #include "llinventoryobserver.h" #include "llinventorypanel.h" #include "lllocaltextureobject.h" -#include "llmd5.h" #include "llnotificationsutil.h" #include "lloutfitobserver.h" #include "llsidepanelappearance.h" diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 6251737699..80ef5e3bae 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -42,7 +42,9 @@ #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" #include "llinventoryobserver.h" +#include "llmd5.h" #include "llnotificationsutil.h" +#include "llmd5.h" #include "lloutfitobserver.h" #include "lloutfitslist.h" #include "llselectmgr.h" @@ -146,7 +148,10 @@ public: // requests will be throttled from a non-trusted browser LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { // support secondlife:///app/appearance/show, but for now we just // make all secondlife:///app/appearance SLapps behave this way @@ -4701,8 +4706,10 @@ public: // not allowed from outside the app LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { } - bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& tokens, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { LLSD::UUID folder_uuid; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 69429fb5ce..3db5fe9260 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1536,7 +1536,12 @@ bool LLAppViewer::doFrame() LLFloaterSimpleSnapshot::update(); gGLActive = FALSE; } - } + + if (LLViewerStatsRecorder::instanceExists()) + { + LLViewerStatsRecorder::instance().idle(); + } + } } { diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index 926cab403e..bcd89cf8db 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llappearancemgr.h" #include "llinventorymodel.h" +#include "llstartup.h" #include "lltooldraganddrop.h" // pack_permissions_slam #include "llviewerinventory.h" #include "llviewerregion.h" @@ -378,7 +379,7 @@ void LLAttachmentsMgr::onAttachmentArrived(const LLUUID& inv_item_id) { LLTimer timer; bool expected = mAttachmentRequests.getTime(inv_item_id, timer); - if (!expected) + if (!expected && LLStartUp::getStartupState() > STATE_WEARABLES_WAIT) { LLInventoryItem *item = gInventory.getItem(inv_item_id); LL_WARNS() << "ATT Attachment was unexpected or arrived after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds: " @@ -417,11 +418,15 @@ void LLAttachmentsMgr::onDetachCompleted(const LLUUID& inv_item_id) LL_DEBUGS("Avatar") << "ATT all detach requests have completed" << LL_ENDL; } } - else + else if (!LLApp::isExiting()) { LL_WARNS() << "ATT unexpected detach for " << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; } + else + { + LL_DEBUGS("Avatar") << "ATT detach on shutdown for " << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL; + } LL_DEBUGS("Avatar") << "ATT detached item flagging as questionable for COF link checking " << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp index 7ad06f8eaa..37de89a48b 100644 --- a/indra/newview/llbuycurrencyhtml.cpp +++ b/indra/newview/llbuycurrencyhtml.cpp @@ -43,7 +43,7 @@ public: // requests will be throttled from a non-trusted browser LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_THROTTLE) {} - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { std::string action( "" ); if ( params.size() >= 1 ) diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 9a608fba8e..43dc10ef5f 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -82,7 +82,7 @@ public: // requests will be throttled from a non-trusted browser LLObjectIMHandler() : LLCommandHandler("objectim", UNTRUSTED_THROTTLE) {} - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (params.size() < 1) { diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 1c22e055bb..dc2cc57f0f 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -57,7 +57,7 @@ class LLObjectHandler : public LLCommandHandler public: LLObjectHandler() : LLCommandHandler("object", UNTRUSTED_BLOCK) { } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (params.size() < 2) return false; diff --git a/indra/newview/llcommanddispatcherlistener.cpp b/indra/newview/llcommanddispatcherlistener.cpp index 518f5bc374..46ec97d5c0 100644 --- a/indra/newview/llcommanddispatcherlistener.cpp +++ b/indra/newview/llcommanddispatcherlistener.cpp @@ -64,10 +64,10 @@ void LLCommandDispatcherListener::dispatch(const LLSD& params) const // But for testing, allow a caller to specify untrusted. trusted_browser = params["trusted"].asBoolean(); } - LLCommandDispatcher::dispatch( - params["cmd"], + LLCommandDispatcher::dispatch(params["cmd"], params["params"], params["query"], + "", NULL, LLCommandHandler::NAV_TYPE_CLICKED, trusted_browser); diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp index 9640b05b06..caa27e530b 100644 --- a/indra/newview/llcommandhandler.cpp +++ b/indra/newview/llcommandhandler.cpp @@ -62,6 +62,7 @@ public: bool dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, + const std::string& grid, LLMediaCtrl* web, const std::string& nav_type, bool trusted_browser); @@ -98,6 +99,7 @@ void LLCommandHandlerRegistry::add(const char* cmd, bool LLCommandHandlerRegistry::dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, + const std::string& grid, LLMediaCtrl* web, const std::string& nav_type, bool trusted_browser) @@ -165,7 +167,7 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd, } } if (!info.mHandler) return false; - return info.mHandler->handle(params, query_map, web); + return info.mHandler->handle(params, query_map, grid, web); } void LLCommandHandlerRegistry::notifySlurlBlocked() @@ -220,12 +222,13 @@ LLCommandHandler::~LLCommandHandler() bool LLCommandDispatcher::dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, + const std::string& grid, LLMediaCtrl* web, const std::string& nav_type, bool trusted_browser) { return LLCommandHandlerRegistry::instance().dispatch( - cmd, params, query_map, web, nav_type, trusted_browser); + cmd, params, query_map, grid, web, nav_type, trusted_browser); } static std::string lookup(LLCommandHandler::EUntrustedAccess value); diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h index 486feecca6..1a354b04f7 100644 --- a/indra/newview/llcommandhandler.h +++ b/indra/newview/llcommandhandler.h @@ -42,7 +42,7 @@ public: LLFooHandler() : LLCommandHandler("foo", UNTRUSTED_BLOCK) { } // Your code here - bool handle(const LLSD& tokens, const LLSD& query_map, + bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (tokens.size() < 1) return false; @@ -90,6 +90,7 @@ public: virtual bool handle(const LLSD& params, const LLSD& query_map, + const std::string& grid, LLMediaCtrl* web) = 0; // For URL secondlife:///app/foo/bar/baz?cat=1&dog=2 // @params - array of "bar", "baz", possibly empty @@ -106,6 +107,7 @@ public: static bool dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, + const std::string& grid, LLMediaCtrl* web, const std::string& nav_type, bool trusted_browser); diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 4a87273372..91031034c6 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -47,6 +47,7 @@ LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewer mGlobalScale(1.0f), mMarkedForDeath(false), mRootVolp(NULL), + mControlAVBridge(NULL), mScaleConstraintFixup(1.0), mRegionChanged(false) { @@ -376,6 +377,12 @@ void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time) } } +void LLControlAvatar::markDead() +{ + super::markDead(); + mControlAVBridge = NULL; +} + bool LLControlAvatar::computeNeedsUpdate() { computeUpdatePeriod(); diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h index 8e87299f3e..50e02d2d91 100644 --- a/indra/newview/llcontrolavatar.h +++ b/indra/newview/llcontrolavatar.h @@ -35,9 +35,12 @@ class LLControlAvatar: { LOG_CLASS(LLControlAvatar); + using super = LLVOAvatar; + public: LLControlAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - virtual void initInstance(); // Called after construction to initialize the class. + virtual void initInstance(); // Called after construction to initialize the class. + virtual void markDead(); virtual ~LLControlAvatar(); // If this is an attachment, return the avatar it is attached to. Otherwise NULL. @@ -87,6 +90,7 @@ public: F32 mGlobalScale; LLVOVolume *mRootVolp; + class LLControlAVBridge* mControlAVBridge; bool mMarkedForDeath; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 4a0c9d399f..bb4174d3b6 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -763,6 +763,19 @@ void LLDrawable::movePartition() if (part) { part->move(this, getSpatialGroup()); + + // SL-18251 "On-screen animesh characters using pelvis offset animations + // disappear when root goes off-screen" + // + // Update extents of the root node when Control Avatar changes it's bounds + if (mRenderType == LLPipeline::RENDER_TYPE_CONTROL_AV && isRoot()) + { + LLControlAvatar* controlAvatar = dynamic_cast(getVObj().get()); + if (controlAvatar && controlAvatar->mControlAVBridge) + { + ((LLSpatialGroup*)controlAvatar->mControlAVBridge->mOctree->getListener(0))->setState(LLViewerOctreeGroup::DIRTY); + } + } } } @@ -1216,10 +1229,11 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() { setSpatialBridge(new LLHUDBridge(this, getRegion())); } - else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) - { - setSpatialBridge(new LLControlAVBridge(this, getRegion())); - } + else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) + { + setSpatialBridge(new LLControlAVBridge(this, getRegion())); + mVObjp->getControlAvatar()->mControlAVBridge = (LLControlAVBridge*)getSpatialBridge(); + } // check HUD first, because HUD is also attachment else if (mVObjp->isAttachment()) { diff --git a/indra/newview/lleventnotifier.cpp b/indra/newview/lleventnotifier.cpp index f1a44a68c9..788b61b381 100644 --- a/indra/newview/lleventnotifier.cpp +++ b/indra/newview/lleventnotifier.cpp @@ -43,8 +43,10 @@ class LLEventHandler : public LLCommandHandler public: // requires trusted browser to trigger LLEventHandler() : LLCommandHandler("event", UNTRUSTED_THROTTLE) { } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (params.size() < 2) { diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index e5965abbd6..4dd8bea4e1 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -103,7 +103,6 @@ std::unique_ptr> doLoadDialog(const std::vector* allowed_types, } } -std::unique_ptr doSaveDialog(const std::string* file, +std::unique_ptr doSaveDialog(const std::string* file, const std::string* type, const std::string* creator, const std::string* extension, diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp index 23f86e2361..2c638fa959 100644 --- a/indra/newview/llfloater360capture.cpp +++ b/indra/newview/llfloater360capture.cpp @@ -64,12 +64,10 @@ LLFloater360Capture::LLFloater360Capture(const LLSD& key) // such time as we ask it not to (the dtor). If we crash or // otherwise, exit before this is turned off, the Simulator // will take care of cleaning up for us. - if (gSavedSettings.getBOOL("360CaptureUseInterestListCap")) - { - // send everything to us for as long as this floater is open - const bool send_everything = true; - changeInterestListMode(send_everything); - } + mStartILMode = gAgent.getInterestListMode(); + + // send everything to us for as long as this floater is open + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); } LLFloater360Capture::~LLFloater360Capture() @@ -81,13 +79,15 @@ LLFloater360Capture::~LLFloater360Capture() mWebBrowser->unloadMediaSource(); } - // Tell the Simulator not to send us everything anymore - // and revert to the regular "keyhole" frustum of interest + // Restore interest list mode to the state when started + // Normally LLFloater360Capture tells the Simulator send everything + // and now reverts to the regular "keyhole" frustum of interest // list updates. - if (!LLApp::isExiting() && gSavedSettings.getBOOL("360CaptureUseInterestListCap")) + if (!LLApp::isExiting() && + gSavedSettings.getBOOL("360CaptureUseInterestListCap") && + mStartILMode != gAgent.getInterestListMode()) { - const bool send_everything = false; - changeInterestListMode(send_everything); + gAgent.changeInterestListMode(mStartILMode); } } @@ -170,52 +170,6 @@ void LLFloater360Capture::onChooseQualityRadioGroup() setSourceImageSize(); } -// Using a new capability, tell the simulator that we want it to send everything -// it knows about and not just what is in front of the camera, in its view -// frustum. We need this feature so that the contents of the region that appears -// in the 6 snapshots which we cannot see and is normally not "considered", is -// also rendered. Typically, this is turned on when the 360 capture floater is -// opened and turned off when it is closed. -// Note: for this version, we do not have a way to determine when "everything" -// has arrived and has been rendered so for now, the proposal is that users -// will need to experiment with the low resolution version and wait for some -// (hopefully) small period of time while the full contents resolves. -// Pass in a flag to ask the simulator/interest list to "send everything" or -// not (the default mode) -void LLFloater360Capture::changeInterestListMode(bool send_everything) -{ - LLSD body; - - if (send_everything) - { - body["mode"] = LLSD::String("360"); - } - else - { - body["mode"] = LLSD::String("default"); - } - - if (gAgent.requestPostCapability("InterestList", body, [](const LLSD & response) - { - LL_INFOS("360Capture") << - "InterestList capability responded: \n" << - ll_pretty_print_sd(response) << - LL_ENDL; - })) - { - LL_INFOS("360Capture") << - "Successfully posted an InterestList capability request with payload: \n" << - ll_pretty_print_sd(body) << - LL_ENDL; - } - else - { - LL_INFOS("360Capture") << - "Unable to post an InterestList capability request with payload: \n" << - ll_pretty_print_sd(body) << - LL_ENDL; - } -} // There is is a setting (360CaptureSourceImageSize) that holds the size // (width == height since it's a square) of each of the 6 source snapshots. @@ -632,11 +586,8 @@ void LLFloater360Capture::capture360Images() // display time to encode all 6 images. It tends to be a fairly linear // time for each so we don't need to worry about displaying the time // for each - this gives us plenty to use for optimizing - LL_INFOS("360Capture") << - "Time to encode and save 6 images was " << - encode_time_total << - " seconds" << - LL_ENDL; + LL_INFOS("360Capture") << "Time to encode and save 6 images was " << + encode_time_total << " seconds" << LL_ENDL; // Write the JavaScript file footer (the bottom of the file after the // declarations of the actual data URLs array). The footer comprises of @@ -668,7 +619,7 @@ void LLFloater360Capture::capture360Images() // as a change - only the subsequent 5 are if (camera_changed_times < 5) { - LL_INFOS("360Capture") << "Warning: we only captured " << camera_changed_times << " images." << LL_ENDL; + LL_WARNS("360Capture") << "360 image capture expected 5 or more images, only captured " << camera_changed_times << " images." << LL_ENDL; } // now we have the 6 shots saved in a well specified location, diff --git a/indra/newview/llfloater360capture.h b/indra/newview/llfloater360capture.h index 8f765c0b1b..3fb2c7f3c7 100644 --- a/indra/newview/llfloater360capture.h +++ b/indra/newview/llfloater360capture.h @@ -50,8 +50,6 @@ class LLFloater360Capture: void onOpen(const LLSD& key) override; void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override; - void changeInterestListMode(bool send_everything); - const std::string getHTMLBaseFolder(); void capture360Images(); @@ -93,6 +91,8 @@ class LLFloater360Capture: std::string mImageSaveDir; LLPointer mRawImages[6]; + + std::string mStartILMode; }; #endif // LL_FLOATER_360CAPTURE_H diff --git a/indra/newview/llfloatercamerapresets.cpp b/indra/newview/llfloatercamerapresets.cpp index 300c945a85..a1cbffd094 100644 --- a/indra/newview/llfloatercamerapresets.cpp +++ b/indra/newview/llfloatercamerapresets.cpp @@ -24,6 +24,7 @@ */ #include "llviewerprecompiledheaders.h" +#include "llfloatercamera.h" #include "llfloatercamerapresets.h" #include "llfloaterreg.h" #include "llnotificationsutil.h" @@ -40,7 +41,8 @@ LLFloaterCameraPresets::~LLFloaterCameraPresets() BOOL LLFloaterCameraPresets::postBuild() { mPresetList = getChild("preset_list"); - + mPresetList->setCommitCallback(boost::bind(&LLFloaterCameraPresets::onSelectionChange, this)); + mPresetList->setCommitOnSelectionChange(true); LLPresetsManager::getInstance()->setPresetListChangeCameraCallback(boost::bind(&LLFloaterCameraPresets::populateList, this)); return TRUE; @@ -58,6 +60,7 @@ void LLFloaterCameraPresets::populateList() std::list preset_names; presetsMgr->loadPresetNamesFromDir(PRESETS_CAMERA, preset_names, DEFAULT_BOTTOM); + std::string active_preset = gSavedSettings.getString("PresetCameraActive"); for (std::list::const_iterator it = preset_names.begin(); it != preset_names.end(); ++it) { @@ -66,6 +69,19 @@ void LLFloaterCameraPresets::populateList() LLCameraPresetFlatItem* item = new LLCameraPresetFlatItem(name, is_default); item->postBuild(); mPresetList->addItem(item); + if(name == active_preset) + { + mPresetList->selectItem(item); + } + } +} + +void LLFloaterCameraPresets::onSelectionChange() +{ + LLCameraPresetFlatItem* selected_preset = dynamic_cast(mPresetList->getSelectedItem()); + if(selected_preset) + { + LLFloaterCamera::switchToPreset(selected_preset->getPresetName()); } } diff --git a/indra/newview/llfloatercamerapresets.h b/indra/newview/llfloatercamerapresets.h index 66430fa399..4430a4209e 100644 --- a/indra/newview/llfloatercamerapresets.h +++ b/indra/newview/llfloatercamerapresets.h @@ -38,6 +38,7 @@ class LLFloaterCameraPresets : public LLFloater virtual void onOpen(const LLSD& key); void populateList(); + void onSelectionChange(); private: LLFloaterCameraPresets(const LLSD& key); @@ -58,6 +59,8 @@ public: virtual void onMouseEnter(S32 x, S32 y, MASK mask); virtual void onMouseLeave(S32 x, S32 y, MASK mask); + std::string getPresetName() { return mPresetName; } + private: void onDeleteBtnClick(); void onResetBtnClick(); diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp index a99a096ea7..f6afdd29fb 100644 --- a/indra/newview/llfloaterexperienceprofile.cpp +++ b/indra/newview/llfloaterexperienceprofile.cpp @@ -92,8 +92,10 @@ class LLExperienceHandler : public LLCommandHandler public: LLExperienceHandler() : LLCommandHandler("experience", UNTRUSTED_THROTTLE) { } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if(params.size() != 2 || params[1].asString() != "profile") return false; diff --git a/indra/newview/llfloaterhandler.cpp b/indra/newview/llfloaterhandler.cpp index 8ebb14149c..b66049de7f 100644 --- a/indra/newview/llfloaterhandler.cpp +++ b/indra/newview/llfloaterhandler.cpp @@ -49,7 +49,7 @@ LLFloater* get_parent_floater(LLView* view) } -bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, LLMediaCtrl *web) +bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, const std::string& grid, LLMediaCtrl *web) { if (params.size() < 1) return false; LLFloater* floater = NULL; diff --git a/indra/newview/llfloaterhandler.h b/indra/newview/llfloaterhandler.h index 5915642d66..959c972275 100644 --- a/indra/newview/llfloaterhandler.h +++ b/indra/newview/llfloaterhandler.h @@ -33,7 +33,7 @@ class LLFloaterHandler { public: LLFloaterHandler() : LLCommandHandler("floater", UNTRUSTED_BLOCK) { } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web); + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web); }; #endif diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 0d2c6d8e4c..bb4cc9bca3 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -903,8 +903,10 @@ public: LLChatCommandHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { } // Your code here - bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& tokens, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { bool retval = false; // Need at least 2 tokens to have a valid message. diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index a24f04ccfb..d4eb40ff92 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -2795,7 +2795,7 @@ BOOL LLPanelEstateAccess::postBuild() if (banned_name_list) { banned_name_list->setCommitOnSelectionChange(TRUE); - banned_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + banned_name_list->setMaxItemCount(ESTATE_MAX_BANNED_IDS); } getChild("banned_search_input")->setCommitCallback(boost::bind(&LLPanelEstateAccess::onBannedSearchEdit, this, _2)); @@ -2939,10 +2939,10 @@ void LLPanelEstateAccess::onClickAddBannedAgent() { LLCtrlListInterface *list = childGetListInterface("banned_avatar_name_list"); if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) + if (list->getItemCount() >= ESTATE_MAX_BANNED_IDS) { LLSD args; - args["MAX_BANNED"] = llformat("%d", ESTATE_MAX_ACCESS_IDS); + args["MAX_BANNED"] = llformat("%d", ESTATE_MAX_BANNED_IDS); LLNotificationsUtil::add("MaxBannedAgentsOnRegion", args); return; } @@ -3180,13 +3180,13 @@ void LLPanelEstateAccess::accessAddCore3(const uuid_vec_t& ids, std::vectorgetChild("banned_avatar_name_list"); LLNameListCtrl* em_list = panel->getChild("estate_manager_name_list"); int currentCount = (name_list ? name_list->getItemCount() : 0); - if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) + if (ids.size() + currentCount > ESTATE_MAX_BANNED_IDS) { LLSD args; args["NUM_ADDED"] = llformat("%d", ids.size()); - args["MAX_AGENTS"] = llformat("%d", ESTATE_MAX_ACCESS_IDS); + args["MAX_AGENTS"] = llformat("%d", ESTATE_MAX_BANNED_IDS); args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeBannedAgents"); - args["NUM_EXCESS"] = llformat("%d", (ids.size() + currentCount) - ESTATE_MAX_ACCESS_IDS); + args["NUM_EXCESS"] = llformat("%d", (ids.size() + currentCount) - ESTATE_MAX_BANNED_IDS); LLNotificationsUtil::add("MaxAgentOnRegionBatch", args); delete change_info; return; @@ -3565,7 +3565,7 @@ void LLPanelEstateAccess::requestEstateGetAccessCoro(std::string url) { LLStringUtil::format_map_t args; args["[BANNEDAGENTS]"] = llformat("%d", result["BannedAgents"].size()); - args["[MAXBANNED]"] = llformat("%d", ESTATE_MAX_ACCESS_IDS); + args["[MAXBANNED]"] = llformat("%d", ESTATE_MAX_BANNED_IDS); std::string msg = LLTrans::getString("RegionInfoBannedResidents", args); panel->getChild("ban_resident_label")->setValue(LLSD(msg)); diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 7e6af45515..37ae80fa8f 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -46,7 +46,7 @@ class LLSearchHandler : public LLCommandHandler public: // requires trusted browser to trigger LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { } - bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch")) { diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index bd49405f34..9f277021c8 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -49,6 +49,7 @@ #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lluictrlfactory.h" +#include "llviewerobjectlist.h" #include "llviewerwindow.h" #include "llfloaterregioninfo.h" @@ -83,6 +84,8 @@ LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key) mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this)); mCommitCallbackRegistrar.add("TopObjects.GetByParcelName", boost::bind(&LLFloaterTopObjects::onGetByParcelName, this)); mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this)); + + mCommitCallbackRegistrar.add("TopObjects.TeleportToSelected", boost::bind(&LLFloaterTopObjects::teleportToSelectedObject, this)); } LLFloaterTopObjects::~LLFloaterTopObjects() @@ -92,10 +95,11 @@ LLFloaterTopObjects::~LLFloaterTopObjects() // virtual BOOL LLFloaterTopObjects::postBuild() { - LLScrollListCtrl *objects_list = getChild("objects_list"); - getChild("objects_list")->setFocus(TRUE); - objects_list->setDoubleClickCallback(onDoubleClickObjectsList, this); - objects_list->setCommitOnSelectionChange(TRUE); + mObjectsScrollList = getChild("objects_list"); + mObjectsScrollList->setFocus(TRUE); + mObjectsScrollList->setDoubleClickCallback(onDoubleClickObjectsList, this); + mObjectsScrollList->setCommitOnSelectionChange(TRUE); + mObjectsScrollList->setCommitCallback(boost::bind(&LLFloaterTopObjects::onSelectionChanged, this)); setDefaultBtn("show_beacon_btn"); @@ -421,6 +425,8 @@ void LLFloaterTopObjects::clearList() mObjectListData.clear(); mObjectListIDs.clear(); mtotalScore = 0.f; + + onSelectionChanged(); } @@ -507,3 +513,38 @@ void LLFloaterTopObjects::showBeacon() std::string tooltip(""); LLTracker::trackLocation(pos_global, name, tooltip, LLTracker::LOCATION_ITEM); } + +void LLFloaterTopObjects::teleportToSelectedObject() +{ + std::vector selected_items = mObjectsScrollList->getAllSelected(); + if (selected_items.size() == 1) + { + LLScrollListItem* first_selected = selected_items.front(); + + LLVector3d teleport_location; + LLViewerObject *viewer_object = gObjectList.findObject(first_selected->getUUID()); + if (viewer_object == NULL) + { + // If we cannot find the object in the viewer list, teleport to the last reported position + std::string pos_string = first_selected->getColumn(3)->getValue().asString(); + + F32 x, y, z; + S32 matched = sscanf(pos_string.c_str(), "<%g,%g,%g>", &x, &y, &z); + if (matched != 3) return; + + LLVector3 pos_agent(x, y, z); + teleport_location = gAgent.getPosGlobalFromAgent(pos_agent); + } + else + { + // If we can find the object in the viewer list, teleport to the known current position + teleport_location = viewer_object->getPositionGlobal(); + } + gAgent.teleportViaLocationLookAt(teleport_location); + } +} + +void LLFloaterTopObjects::onSelectionChanged() +{ + getChildView("teleport_btn")->setEnabled(mObjectsScrollList->getNumSelected() == 1); +} diff --git a/indra/newview/llfloatertopobjects.h b/indra/newview/llfloatertopobjects.h index 3138249c7a..b73401e50d 100644 --- a/indra/newview/llfloatertopobjects.h +++ b/indra/newview/llfloatertopobjects.h @@ -30,6 +30,7 @@ #include "llfloater.h" class LLUICtrl; +class LLScrollListCtrl; // Bits for simulator performance query flags enum LAND_STAT_FLAGS @@ -75,6 +76,7 @@ private: void initColumns(LLCtrlListInterface *list); void onCommitObjectsList(); + void onSelectionChanged(); static void onDoubleClickObjectsList(void* data); void onClickShowBeacon(); @@ -90,6 +92,7 @@ private: void onGetByParcelName(); void showBeacon(); + void teleportToSelectedObject(); private: std::string mMethod; @@ -106,6 +109,7 @@ private: F32 mtotalScore; static LLFloaterTopObjects* sInstance; + LLScrollListCtrl* mObjectsScrollList; }; #endif diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 704abd269f..8f3ec8af05 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -124,8 +124,10 @@ public: // requires trusted browser to trigger LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_CLICK_ONLY ) { } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap")) { @@ -163,7 +165,10 @@ public: { } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap")) { diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 0c8e248538..03c1b6f631 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -741,6 +741,12 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV gGL.end(); } +void LLViewerParcelMgr::resetCollisionTimer() +{ + mCollisionTimer.reset(); + mRenderCollision = TRUE; +} + void draw_line_cube(F32 width, const LLVector3& center) { width = 0.5f * width; diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index aec6c23e34..043316ccca 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -78,8 +78,10 @@ public: return true; } - bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& tokens, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (LLStartUp::getStartupState() < STATE_STARTED) { diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 3536b83989..948793681d 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1631,14 +1631,19 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) from_group = message_data["from_group"].asString() == "Y"; } - + EInstantMessage dialog = static_cast(message_data["dialog"].asInteger()); + LLUUID session_id = message_data["transaction-id"].asUUID(); + if (session_id.isNull() && dialog == IM_FROM_TASK) + { + session_id = message_data["asset_id"].asUUID(); + } LLIMProcessing::processNewMessage( message_data["from_agent_id"].asUUID(), from_group, message_data["to_agent_id"].asUUID(), message_data.has("offline") ? static_cast(message_data["offline"].asInteger()) : IM_OFFLINE, - static_cast(message_data["dialog"].asInteger()), - message_data["transaction-id"].asUUID(), + dialog, + session_id, static_cast(message_data["timestamp"].asInteger()), message_data["from_agent_name"].asString(), message_data["message"].asString(), diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index f813639073..f5f0d74f0f 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -217,8 +217,7 @@ bool contains_nocopy_items(const LLUUID& id) return false; } -// Generates a string containing the path to the item specified by -// item_id. +// Generates a string containing the path to the item specified by id. void append_path(const LLUUID& id, std::string& path) { std::string temp; @@ -238,6 +237,36 @@ void append_path(const LLUUID& id, std::string& path) path.append(temp); } +// Generates a string containing the path name of the object. +std::string make_path(const LLInventoryObject* object) +{ + std::string path; + append_path(object->getUUID(), path); + return path + "/" + object->getName(); +} + +// Generates a string containing the path name of the object specified by id. +std::string make_inventory_path(const LLUUID& id) +{ + if (LLInventoryObject* object = gInventory.getObject(id)) + return make_path(object); + return ""; +} + +// Generates a string containing the path name and id of the object. +std::string make_info(const LLInventoryObject* object) +{ + return "'" + make_path(object) + "' (" + object->getUUID().asString() + ")"; +} + +// Generates a string containing the path name and id of the object specified by id. +std::string make_inventory_info(const LLUUID& id) +{ + if (LLInventoryObject* object = gInventory.getObject(id)) + return make_info(object); + return " (" + id.asString() + ")"; +} + void update_marketplace_folder_hierarchy(const LLUUID cat_id) { // When changing the marketplace status of a folder, the only thing that needs to happen is @@ -1570,6 +1599,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU } else { + LL_INFOS("SLM") << "Move category " << make_info(viewer_inv_cat) << " to '" << make_inventory_path(dest_folder) << "'" << LL_ENDL; // Reparent the folder gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false); // Check the destination folder recursively for no copy items and promote the including folders if any diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index f19cadaded..925217dda3 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -79,9 +79,18 @@ void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items); -// Generates a string containing the path to the item specified by item_id. +// Generates a string containing the path to the object specified by id (not including the object name). void append_path(const LLUUID& id, std::string& path); +// Generates a string containing the path name of the object. +std::string make_path(const LLInventoryObject* object); +// Generates a string containing the path name of the object specified by id. +std::string make_inventory_path(const LLUUID& id); + +// Generates a string containing the path name and id of the object. +std::string make_info(const LLInventoryObject* object); +// Generates a string containing the path name and id of the object specified by id. +std::string make_inventory_info(const LLUUID& id); bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false); bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index aa750a19b0..a41ab4eec3 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -65,6 +65,7 @@ #include "bufferarray.h" #include "bufferstream.h" #include "llcorehttputil.h" +#include "hbxxh.h" //#define DIFF_INVENTORY_FILES #ifdef DIFF_INVENTORY_FILES @@ -703,17 +704,16 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& } } -LLMD5 LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const +LLInventoryModel::digest_t LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const { LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::item_array_t* item_array; getDirectDescendentsOf(cat_id,cat_array,item_array); - LLMD5 item_name_hash; if (!item_array) { - item_name_hash.finalize(); - return item_name_hash; + return LLUUID::null; } + HBXXH128 item_name_hash; for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); iter != item_array->end(); iter++) @@ -723,8 +723,7 @@ LLMD5 LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const continue; item_name_hash.update(item->getName()); } - item_name_hash.finalize(); - return item_name_hash; + return item_name_hash.digest(); } // SJB: Added version to lock the arrays to catch potential logic bugs @@ -988,6 +987,7 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, inventory_func_type callback, const LLUUID& thumbnail_id) { + LL_DEBUGS(LOG_INV) << "Create '" << pname << "' in '" << make_inventory_path(parent_id) << "'" << LL_ENDL; if (!isInventoryUsable()) { LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " @@ -1696,6 +1696,7 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) LLPointer cat = getCategory(object_id); if(cat && (cat->getParentUUID() != cat_id)) { + LL_DEBUGS(LOG_INV) << "Move category '" << make_path(cat) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; cat_array_t* cat_array; cat_array = getUnlockedCatArray(cat->getParentUUID()); if(cat_array) vector_replace_with_last(*cat_array, cat); @@ -1708,6 +1709,7 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) LLPointer item = getItem(object_id); if(item && (item->getParentUUID() != cat_id)) { + LL_DEBUGS(LOG_INV) << "Move item '" << make_path(item) << "' to '" << make_inventory_path(cat_id) << "'" << LL_ENDL; item_array_t* item_array; item_array = getUnlockedItemArray(item->getParentUUID()); if(item_array) vector_replace_with_last(*item_array, item); @@ -1726,14 +1728,14 @@ void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, { if (item->getParentUUID() == new_parent_id) { - LL_DEBUGS(LOG_INV) << "'" << item->getName() << "' (" << item->getUUID() - << ") is already in folder " << new_parent_id << LL_ENDL; + LL_DEBUGS(LOG_INV) << make_info(item) << " is already in folder " << make_inventory_info(new_parent_id) << LL_ENDL; } else { - LL_INFOS(LOG_INV) << "Moving '" << item->getName() << "' (" << item->getUUID() - << ") from " << item->getParentUUID() << " to folder " - << new_parent_id << LL_ENDL; + LL_INFOS(LOG_INV) << "Move item " << make_info(item) + << " from " << make_inventory_info(item->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + LLInventoryModel::update_list_t update; LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); update.push_back(old_folder); @@ -1765,6 +1767,10 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, return; } + LL_INFOS(LOG_INV) << "Move category " << make_info(cat) + << " from " << make_inventory_info(cat->getParentUUID()) + << " to " << make_inventory_info(new_parent_id) << LL_ENDL; + LLInventoryModel::update_list_t update; LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); update.push_back(old_folder); diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a90ed2bf42..4309c03f8e 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -39,7 +39,6 @@ #include "llpermissionsflags.h" #include "llviewerinventory.h" #include "llstring.h" -#include "llmd5.h" #include "httpcommon.h" #include "httprequest.h" #include "httpoptions.h" @@ -262,8 +261,9 @@ public: item_array_t*& items) const; void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const; + typedef LLUUID digest_t; // To clarify the actual usage of this "UUID" // Compute a hash of direct descendant names (for detecting child name changes) - LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const; + digest_t hashDirectDescendentNames(const LLUUID& cat_id) const; // Starting with the object specified, add its descendants to the // array provided, but do not add the inventory object specified diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 0d96c7a005..227d4285eb 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -732,7 +732,7 @@ void LLInventoryCategoriesObserver::changed(U32 mask) // computed, or (b) a name has changed. if (!cat_data.mIsNameHashInitialized || (mask & LLInventoryObserver::LABEL)) { - LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cat_id); + digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id); if (cat_data.mItemNameHash != item_name_hash) { cat_data.mIsNameHashInitialized = true; @@ -802,7 +802,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t { if(init_name_hash) { - LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cat_id); + digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id); mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash))); } else @@ -829,11 +829,10 @@ LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( , mThumbnailId(thumbnail_id) , mIsNameHashInitialized(false) { - mItemNameHash.finalize(); } LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( - const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, LLMD5 name_hash) + const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash) : mCatID(cat_id) , mCallback(cb) diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index f0ed2f7003..93109a70ac 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -28,7 +28,6 @@ #define LL_LLINVENTORYOBSERVERS_H #include "lluuid.h" -#include "llmd5.h" #include #include @@ -271,14 +270,15 @@ public: void removeCategory(const LLUUID& cat_id); protected: + typedef LLUUID digest_t; // To clarify the actual usage of this "UUID" struct LLCategoryData { LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents); - LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, LLMD5 name_hash); + LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash); callback_t mCallback; S32 mVersion; S32 mDescendentsCount; - LLMD5 mItemNameHash; + digest_t mItemNameHash; bool mIsNameHashInitialized; LLUUID mCatID; LLUUID mThumbnailId; diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index 22cedf450e..92e341ce93 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -87,6 +87,7 @@ void LLLoginHandler::parse(const LLSD& queryMap) bool LLLoginHandler::handle(const LLSD& tokens, const LLSD& query_map, + const std::string& grid, LLMediaCtrl* web) { // do nothing if we are already logged in diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h index 1f2eacd094..2579341dbf 100644 --- a/indra/newview/llloginhandler.h +++ b/indra/newview/llloginhandler.h @@ -35,7 +35,7 @@ class LLLoginHandler : public LLCommandHandler public: // allow from external browsers LLLoginHandler() : LLCommandHandler("login", UNTRUSTED_ALLOW) { } - /*virtual*/ bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web); + /*virtual*/ bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web); // Fill in our internal fields from a SLURL like // secondlife:///app/login?first=Bob&last=Dobbs diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index 843dc66fbc..8f1ec8584b 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -93,7 +93,11 @@ private: bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); } }; - + + // definitions follow class + friend std::hash; + friend size_t hash_value(const TEMaterialPair&) noexcept; + friend inline bool operator<( const LLMaterialMgr::TEMaterialPair& lhs, const LLMaterialMgr::TEMaterialPair& rhs) @@ -102,13 +106,6 @@ private: (lhs.materialID < rhs.materialID); } - struct TEMaterialPairHasher - { - enum { bucket_size = 8 }; - size_t operator()(const TEMaterialPair& key_value) const { return *((size_t*)key_value.materialID.get()); } // cheesy, but effective - bool operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; } - }; - typedef std::set material_queue_t; typedef std::map get_queue_t; typedef std::pair pending_material_t; @@ -116,7 +113,7 @@ private: typedef std::map get_callback_map_t; - typedef boost::unordered_map get_callback_te_map_t; + typedef boost::unordered_map get_callback_te_map_t; typedef std::set getall_queue_t; typedef std::map getall_pending_map_t; typedef std::map getall_callback_map_t; @@ -146,5 +143,23 @@ private: U32 getMaxEntries(const LLViewerRegion* regionp); }; +// std::hash implementation for TEMaterialPair +namespace std +{ + template<> struct hash + { + inline size_t operator()(const LLMaterialMgr::TEMaterialPair& p) const noexcept + { + return size_t((p.te + 1) * p.materialID.getDigest64()); + } + }; +} + +// For use with boost containers. +inline size_t hash_value(const LLMaterialMgr::TEMaterialPair& p) noexcept +{ + return size_t((p.te + 1) * p.materialID.getDigest64()); +} + #endif // LL_LLMATERIALMGR_H diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f937754368..d6eba6b4bf 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -56,6 +56,7 @@ #include "llviewermessage.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +#include "llviewerstatsrecorder.h" #include "llviewertexturelist.h" #include "llvolume.h" #include "llvolumemgr.h" @@ -1862,10 +1863,10 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes const LLUUID mesh_id = mesh_params.getSculptID(); LLSD header; - U32 header_size = 0; + llssize header_size = 0; if (data_size > 0) { - U32 dsize = data_size; + llssize dsize = data_size; char* result_ptr = strip_deprecated_header((char*)data, dsize, &header_size); data_size = dsize; @@ -4089,6 +4090,8 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol } mLoadingMeshes[detail].erase(obj_iter); + + LLViewerStatsRecorder::instance().meshLoaded(); } } diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index e1a5b22490..495153981b 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2685,9 +2685,6 @@ void LLModelPreview::clearBuffers() void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) { - U32 mesh_count = 0; - - LLModelLoader::model_list* model = NULL; if (lod < 0 || lod > 4) @@ -2818,8 +2815,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) vb->flush(); mVertexBuffer[lod][mdl].push_back(vb); - - ++mesh_count; } } } diff --git a/indra/newview/lloutfitobserver.cpp b/indra/newview/lloutfitobserver.cpp index 5bb69367aa..3ec5bcd9fc 100644 --- a/indra/newview/lloutfitobserver.cpp +++ b/indra/newview/lloutfitobserver.cpp @@ -34,7 +34,6 @@ LLOutfitObserver::LLOutfitObserver() : mCOFLastVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) { - mItemNameHash.finalize(); gInventory.addObserver(this); } @@ -83,7 +82,7 @@ bool LLOutfitObserver::checkCOF() return false; bool cof_changed = false; - LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cof); + LLUUID item_name_hash = gInventory.hashDirectDescendentNames(cof); if (item_name_hash != mItemNameHash) { cof_changed = true; diff --git a/indra/newview/lloutfitobserver.h b/indra/newview/lloutfitobserver.h index 77041db68d..2f136d48e8 100644 --- a/indra/newview/lloutfitobserver.h +++ b/indra/newview/lloutfitobserver.h @@ -28,7 +28,6 @@ #define LL_OUTFITOBSERVER_H #include "llsingleton.h" -#include "llmd5.h" /** * Outfit observer facade that provides simple possibility to subscribe on @@ -78,7 +77,7 @@ protected: bool mLastOutfitDirtiness; - LLMD5 mItemNameHash; + LLUUID mItemNameHash; private: signal_t mBOFReplaced; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 0103bf628a..1b4684d073 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1665,7 +1665,7 @@ class LLMetricSystemHandler : public LLCommandHandler public: LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_CLICK_ONLY) { } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { // change height units TRUE for meters and FALSE for feet BOOL new_value = (gSavedSettings.getBOOL("HeightUnits") == FALSE) ? TRUE : FALSE; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index b14fdbf38e..8f1e57e44c 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -97,7 +97,7 @@ class LLLoginLocationAutoHandler : public LLCommandHandler public: // don't allow from external browsers LLLoginLocationAutoHandler() : LLCommandHandler("location_login", UNTRUSTED_BLOCK) { } - bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) { diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index 02911313ed..3c3cd5d522 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -619,7 +619,6 @@ void LLPanelNearByMedia::refreshList() LLViewerMedia::impl_list impls = media_inst->getPriorityList(); LLViewerMedia::impl_list::iterator priority_iter; - U32 enabled_count = 0; U32 disabled_count = 0; // iterate over the impl list, creating rows as necessary. @@ -662,13 +661,10 @@ void LLPanelNearByMedia::refreshList() { disabled_count++; } - else { - enabled_count++; } } - } mDisableAllCtrl->setEnabled((gSavedSettings.getBOOL("AudioStreamingMusic") || - gSavedSettings.getBOOL("AudioStreamingMedia")) && + gSavedSettings.getBOOL("AudioStreamingMedia")) && (media_inst->isAnyMediaShowing() || media_inst->isParcelMediaPlaying() || media_inst->isParcelAudioPlaying())); diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index 3e770958da..67f913a067 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -76,30 +76,34 @@ std::string click_action_to_string_value( U8 action); U8 string_value_to_click_action(std::string p_value) { - if(p_value == "Touch") + if (p_value == "Touch") { return CLICK_ACTION_TOUCH; } - if(p_value == "Sit") + if (p_value == "Sit") { return CLICK_ACTION_SIT; } - if(p_value == "Buy") + if (p_value == "Buy") { return CLICK_ACTION_BUY; } - if(p_value == "Pay") + if (p_value == "Pay") { return CLICK_ACTION_PAY; } - if(p_value == "Open") + if (p_value == "Open") { return CLICK_ACTION_OPEN; } - if(p_value == "Zoom") + if (p_value == "Zoom") { return CLICK_ACTION_ZOOM; } + if (p_value == "Ignore") + { + return CLICK_ACTION_IGNORE; + } if (p_value == "None") { return CLICK_ACTION_DISABLED; @@ -130,6 +134,9 @@ std::string click_action_to_string_value( U8 action) case CLICK_ACTION_ZOOM: return "Zoom"; break; + case CLICK_ACTION_IGNORE: + return "Ignore"; + break; case CLICK_ACTION_DISABLED: return "None"; break; @@ -274,12 +281,12 @@ void LLPanelPermissions::disableAll() combo_click_action->setEnabled(FALSE); combo_click_action->clear(); } - getChildView("B:")->setVisible( FALSE); - getChildView("O:")->setVisible( FALSE); - getChildView("G:")->setVisible( FALSE); - getChildView("E:")->setVisible( FALSE); - getChildView("N:")->setVisible( FALSE); - getChildView("F:")->setVisible( FALSE); + getChildView("B:")->setVisible(FALSE); + getChildView("O:")->setVisible(FALSE); + getChildView("G:")->setVisible(FALSE); + getChildView("E:")->setVisible(FALSE); + getChildView("N:")->setVisible(FALSE); + getChildView("F:")->setVisible(FALSE); } void LLPanelPermissions::refresh() @@ -949,19 +956,19 @@ void LLPanelPermissions::refresh() getChild("search_check")->setValue(include_in_search); getChild("search_check")->setTentative( !all_include_in_search); - // Click action (touch, sit, buy) + // Click action (touch, sit, buy, pay, open, play, open media, zoom, ignore) U8 click_action = 0; if (LLSelectMgr::getInstance()->selectionGetClickAction(&click_action)) { LLComboBox* combo_click_action = getChild("clickaction"); - if(combo_click_action) + if (combo_click_action) { const std::string combo_value = click_action_to_string_value(click_action); combo_click_action->setValue(LLSD(combo_value)); } } - if(LLSelectMgr::getInstance()->getSelection()->isAttachment()) + if (LLSelectMgr::getInstance()->getSelection()->isAttachment()) { getChildView("checkbox for sale")->setEnabled(FALSE); getChildView("Edit Cost")->setEnabled(FALSE); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 0f00231643..1d5ed93c4d 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -91,8 +91,10 @@ class LLParcelHandler : public LLCommandHandler public: // requires trusted browser to trigger LLParcelHandler() : LLCommandHandler("parcel", UNTRUSTED_THROTTLE) { } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (params.size() < 2) { diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index b6c2d1f0fd..3333c832d2 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -462,8 +462,10 @@ public: // requires trusted browser to trigger LLProfileHandler() : LLCommandHandler("profile", UNTRUSTED_THROTTLE) { } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (params.size() < 1) return false; std::string agent_name = params[0]; @@ -510,8 +512,10 @@ public: return false; } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (params.size() < 2) return false; LLUUID avatar_id; diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index 1ff12b4f37..dec6cfd83b 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -106,7 +106,7 @@ public: return true; } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (LLStartUp::getStartupState() < STATE_STARTED) { diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index db3a3c6de5..0535036cb0 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -87,8 +87,10 @@ public: return true; } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (LLStartUp::getStartupState() < STATE_STARTED) { diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 33656566d1..095d5a0a1e 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -39,7 +39,9 @@ #include "llinventorydefines.h" #include "llinventorymodel.h" #include "lllineeditor.h" +#include "llmd5.h" #include "llnotificationsutil.h" +#include "llmd5.h" #include "llresmgr.h" #include "roles_constants.h" #include "llscrollbar.h" diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index d677a996c1..23c6cc01f5 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -40,6 +40,7 @@ #include "llinventorymodel.h" #include "llkeyboard.h" #include "lllineeditor.h" +#include "llmd5.h" #include "llhelp.h" #include "llnotificationsutil.h" #include "llresmgr.h" diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp index 5e339a52bf..9b1d2d48c6 100644 --- a/indra/newview/llsceneview.cpp +++ b/indra/newview/llsceneview.cpp @@ -100,8 +100,6 @@ void LLSceneView::draw() F32 total_physics[] = { 0.f, 0.f }; - U32 object_count = 0; - LLViewerRegion* region = gAgent.getRegion(); if (region) { @@ -116,8 +114,7 @@ void LLSceneView::draw() U32 idx = object->isAttachment() ? 1 : 0; LLVolume* volume = object->getVolume(); - object_count++; - + F32 radius = object->getScale().magVec(); size[idx].push_back(radius); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 17daff3676..cf9a80221b 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5273,8 +5273,8 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, LLViewerRegion* last_region; LLViewerRegion* current_region; - S32 objects_sent = 0; - S32 packets_sent = 0; +// S32 objects_sent = 0; +// S32 packets_sent = 0; S32 objects_in_this_packet = 0; bool link_operation = message_name == "ObjectLink"; @@ -5406,7 +5406,7 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, (*pack_body)(node, user_data); // do any related logging (*log_func)(node, user_data); - ++objects_sent; +// ++objects_sent; ++objects_in_this_packet; // and on to the next object @@ -5424,7 +5424,7 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, { // otherwise send current message and start new one gMessageSystem->sendReliable( last_region->getHost()); - packets_sent++; +// packets_sent++; objects_in_this_packet = 0; gMessageSystem->newMessage(message_name.c_str()); @@ -5441,7 +5441,7 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, { // add root instance into new message (*pack_body)(linkset_root, user_data); - ++objects_sent; +// ++objects_sent; ++objects_in_this_packet; } } @@ -5455,7 +5455,7 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, if (gMessageSystem->getCurrentSendTotal() > 0) { gMessageSystem->sendReliable( current_region->getHost()); - packets_sent++; +// packets_sent++; } else { diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 0cfdf67ed5..eaa23d6a6c 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -326,7 +326,7 @@ void LLSettingsVOBase::onAssetDownloadComplete(const LLUUID &asset_id, S32 statu std::stringstream llsdstream(buffer); LLSD llsdsettings; - if (LLSDSerialize::deserialize(llsdsettings, llsdstream, -1)) + if (LLSDSerialize::deserialize(llsdsettings, llsdstream, LLSDSerialize::SIZE_UNLIMITED)) { settings = createFromLLSD(llsdsettings); } @@ -393,7 +393,7 @@ LLSettingsBase::ptr_t LLSettingsVOBase::importFile(const std::string &filename) return LLSettingsBase::ptr_t(); } - if (!LLSDSerialize::deserialize(settings, file, -1)) + if (!LLSDSerialize::deserialize(settings, file, LLSDSerialize::SIZE_UNLIMITED)) { LL_WARNS("SETTINGS") << "Unable to deserialize settings from '" << filename << "'" << LL_ENDL; return LLSettingsBase::ptr_t(); diff --git a/indra/newview/llshareavatarhandler.cpp b/indra/newview/llshareavatarhandler.cpp index 142e00c3f7..8c5ebb75ef 100644 --- a/indra/newview/llshareavatarhandler.cpp +++ b/indra/newview/llshareavatarhandler.cpp @@ -38,7 +38,7 @@ public: { } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAvatarShare")) { diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 5e363fc9b1..3331bc4d68 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -852,7 +852,7 @@ void LLSidepanelTaskInfo::refresh() const BOOL all_include_in_search = LLSelectMgr::getInstance()->selectionGetIncludeInSearch(&include_in_search); getChildView("search_check")->setEnabled(has_change_sale_ability && all_volume); getChild("search_check")->setValue(include_in_search); - getChild("search_check")->setTentative( !all_include_in_search); + getChild("search_check")->setTentative(!all_include_in_search); // Click action (touch, sit, buy) U8 click_action = 0; @@ -1126,7 +1126,8 @@ static U8 string_value_to_click_action(std::string p_value) void LLSidepanelTaskInfo::onCommitClickAction(LLUICtrl* ctrl, void*) { LLComboBox* box = (LLComboBox*)ctrl; - if (!box) return; + if (!box) + return; std::string value = box->getValue().asString(); U8 click_action = string_value_to_click_action(value); doClickAction(click_action); diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 42cd1133a2..17c834326c 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -237,6 +237,59 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) return FALSE; } +void LLSpatialGroup::expandExtents(const LLVector4a* addingExtents, const LLXformMatrix& currentTransform) +{ + // Get coordinates of the adding extents + const LLVector4a& min = addingExtents[0]; + const LLVector4a& max = addingExtents[1]; + + // Get coordinates of all corners of the bounding box + LLVector3 corners[] = + { + LLVector3(min[0], min[1], min[2]), + LLVector3(min[0], min[1], max[2]), + LLVector3(min[0], max[1], min[2]), + LLVector3(min[0], max[1], max[2]), + LLVector3(max[0], min[1], min[2]), + LLVector3(max[0], min[1], max[2]), + LLVector3(max[0], max[1], min[2]), + LLVector3(max[0], max[1], max[2]) + }; + + // New extents (to be expanded) + LLVector3 extents[] = + { + LLVector3(mExtents[0].getF32ptr()), + LLVector3(mExtents[1].getF32ptr()) + }; + + LLQuaternion backwardRotation = ~currentTransform.getRotation(); + for (LLVector3& corner : corners) + { + // Make coordinates relative to the current position + corner -= currentTransform.getPosition(); + // Rotate coordinates backward to the current rotation + corner.rotVec(backwardRotation); + // Expand root extents on the current corner + for (int j = 0; j < 3; ++j) + { + if (corner[j] < extents[0][j]) + extents[0][j] = corner[j]; + if (corner[j] > extents[1][j]) + extents[1][j] = corner[j]; + } + } + + // Set new expanded extents + mExtents[0].load3(extents[0].mV); + mExtents[1].load3(extents[1].mV); + + // Calculate new center and size + mBounds[0].setAdd(mExtents[0], mExtents[1]); + mBounds[0].mul(0.5f); + mBounds[1].setSub(mExtents[0], mExtents[1]); + mBounds[1].mul(0.5f); +} BOOL LLSpatialGroup::addObject(LLDrawable *drawablep) { @@ -3950,6 +4003,11 @@ public: if (vobj) { + if (vobj->getClickAction() == CLICK_ACTION_IGNORE && !LLFloater::isVisible(gFloaterTools)) + { + return false; + } + LLVector4a intersection; bool skip_check = false; if (vobj->isAvatar()) diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 6d3ef33801..cdb591083c 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -298,6 +298,7 @@ public: BOOL addObject(LLDrawable *drawablep); BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE); BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group + void expandExtents(const LLVector4a* addingExtents, const LLXformMatrix& currentTransform); void shift(const LLVector4a &offset); void destroyGL(bool keep_occlusion = false); @@ -699,8 +700,10 @@ public: class LLControlAVBridge : public LLVolumeBridge { + using super = LLVolumeBridge; public: LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regionp); + virtual void updateSpatialExtents(); }; class LLHUDBridge : public LLVolumeBridge diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp index c3eb70f850..fd41cdf0d7 100644 --- a/indra/newview/llsprite.cpp +++ b/indra/newview/llsprite.cpp @@ -79,7 +79,6 @@ void LLSprite::updateFace(LLFace &face) // First, figure out how many vertices/indices we need. U32 num_vertices, num_indices; - U32 vertex_count = 0; // Get the total number of vertices and indices if (mFollow) @@ -203,25 +202,21 @@ void LLSprite::updateFace(LLFace &face) *verticesp = mC; tex_coordsp++; verticesp++; - vertex_count++; *tex_coordsp = LLVector2(0.f, 1.f); *verticesp = mB; tex_coordsp++; verticesp++; - vertex_count++; *tex_coordsp = LLVector2(1.f, 1.f); *verticesp = mA; tex_coordsp++; verticesp++; - vertex_count++; *tex_coordsp = LLVector2(1.f, 0.0f); *verticesp = mD; tex_coordsp++; verticesp++; - vertex_count++; // Generate indices, since they're easy. // Just a series of quads. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 5511ab2c62..ced6ffa32e 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -663,9 +663,22 @@ bool idle_startup() #else void* window_handle = NULL; #endif - bool init = gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle()); - if(init) + if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle())) { + if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio")) + { + LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl()); + } + + // if the audio engine hasn't set up its own preferred handler for streaming audio + // then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + gAudiop->setMuted(TRUE); } else @@ -674,16 +687,6 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; } - - if (gAudiop) - { - // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins - if (NULL == gAudiop->getStreamingAudioImpl()) - { - LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); - } - } } } @@ -3308,7 +3311,7 @@ LLSD transform_cert_args(LLPointer cert) // are actually arrays, and we want to format them as comma separated // strings, so special case those. LLSDSerialize::toXML(cert_info[iter->first], std::cout); - if((iter->first== std::string(CERT_KEY_USAGE)) | + if((iter->first == std::string(CERT_KEY_USAGE)) || (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) { value = ""; diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 0a87b14e17..1ef5d1c50b 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -729,7 +729,7 @@ class LLBalanceHandler : public LLCommandHandler public: // Requires "trusted" browser/URL source LLBalanceHandler() : LLCommandHandler("balance", UNTRUSTED_BLOCK) { } - bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (tokens.size() == 1 && tokens[0].asString() == "request") diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 6f6ca2be9b..a1beec7c1f 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2183,7 +2183,6 @@ S32 LLTextureFetchWorker::callbackHttpGet(LLCore::HttpResponse * response, LL_DEBUGS(LOG_TXT) << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL; if (data_size > 0) { - LLViewerStatsRecorder::instance().textureFetch(data_size); // *TODO: set the formatted image data here directly to avoid the copy // Hold on to body for later copy @@ -2249,6 +2248,13 @@ S32 LLTextureFetchWorker::callbackHttpGet(LLCore::HttpResponse * response, mHaveAllData = TRUE; } mRequestedSize = data_size; + + if (mHaveAllData) + { + LLViewerStatsRecorder::instance().textureFetch(); + } + + // *TODO: set the formatted image data here directly to avoid the copy } else { @@ -2258,11 +2264,6 @@ S32 LLTextureFetchWorker::callbackHttpGet(LLCore::HttpResponse * response, mLoaded = TRUE; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - if (LLViewerStatsRecorder::instanceExists()) - { - // Do not create this instance inside thread - LLViewerStatsRecorder::instance().log(0.2f); - } return data_size ; } diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index cf9211767e..84b61fc612 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -845,8 +845,8 @@ void LLTextureView::draw() if (imagep->getID() == LLAppViewer::getTextureFetch()->mDebugID) { - static S32 debug_count = 0; - ++debug_count; // for breakpoints +// static S32 debug_count = 0; +// ++debug_count; // for breakpoints } F32 pri; diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 0da769999b..76fb138768 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -97,6 +97,8 @@ private: // Called by LLWorldMap when a region name has been resolved to a // location in-world, used by places-panel display. + static bool handleGrid(const LLSLURL& slurl); + friend class LLTeleportHandler; }; @@ -155,7 +157,7 @@ bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl, LL_INFOS() << "cmd: " << slurl.getAppCmd() << " path: " << slurl.getAppPath() << " query: " << slurl.getAppQuery() << LL_ENDL; const LLSD& query_map = LLURI::queryMap(slurl.getAppQuery()); bool handled = LLCommandDispatcher::dispatch( - slurl.getAppCmd(), slurl.getAppPath(), query_map, web, nav_type, trusted_browser); + slurl.getAppCmd(), slurl.getAppPath(), query_map, slurl.getGrid(), web, nav_type, trusted_browser); // alert if we didn't handle this secondlife:///app/ SLURL // (but still return true because it is a valid app SLURL) @@ -184,6 +186,11 @@ bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, const std::string return true; } + if (!handleGrid(slurl)) + { + return true; + } + // Request a region handle by name LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(), LLURLDispatcherImpl::regionNameCallback, @@ -202,31 +209,39 @@ void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const LLSLURL& s } } +bool LLURLDispatcherImpl::handleGrid(const LLSLURL& slurl) +{ + if (LLGridManager::getInstance()->getGrid(slurl.getGrid()) + != LLGridManager::getInstance()->getGrid()) + { + LLSD args; + args["SLURL"] = slurl.getLocationString(); + args["CURRENT_GRID"] = LLGridManager::getInstance()->getGridLabel(); + std::string grid_label = + LLGridManager::getInstance()->getGridLabel(slurl.getGrid()); + + if (!grid_label.empty()) + { + args["GRID"] = grid_label; + } + else + { + args["GRID"] = slurl.getGrid(); + } + LLNotificationsUtil::add("CantTeleportToGrid", args); + return false; + } + return true; +} + /* static */ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport) { - - // we can't teleport cross grid at this point - if( LLGridManager::getInstance()->getGrid(slurl.getGrid()) - != LLGridManager::getInstance()->getGrid()) - { - LLSD args; - args["SLURL"] = slurl.getLocationString(); - args["CURRENT_GRID"] = LLGridManager::getInstance()->getGridLabel(); - std::string grid_label = - LLGridManager::getInstance()->getGridLabel(slurl.getGrid()); - - if(!grid_label.empty()) - { - args["GRID"] = grid_label; - } - else - { - args["GRID"] = slurl.getGrid(); - } - LLNotificationsUtil::add("CantTeleportToGrid", args); - return; - } + if (!handleGrid(slurl)) + { + // we can't teleport cross grid at this point + return; + } LLVector3d global_pos = from_region_handle(region_handle); global_pos += LLVector3d(slurl.getPosition()); @@ -274,8 +289,10 @@ public: &LLTeleportHandler::from_event); } - bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& tokens, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { // construct a "normal" SLURL, resolve the region to // a global position, and teleport to it @@ -297,7 +314,7 @@ public: LLSD payload; payload["region_name"] = region_name; - payload["callback_url"] = LLSLURL(region_name, coords).getSLURLString(); + payload["callback_url"] = LLSLURL(grid, region_name, coords).getSLURLString(); LLNotificationsUtil::add("TeleportViaSLAPP", args, payload); return true; diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index cc73f7ca80..6a0edbecb1 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -91,17 +91,18 @@ void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI return; } - // Record the URI we are going to be switching to + if (!gAudiop) + { + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; + return; + } + + // Record the URI we are going to be switching to mNextStreamURI = streamURI; switch (mFadeState) { case FADE_IDLE: - if (!gAudiop) - { - LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; - break; - } // If a stream is playing fade it out first if (!gAudiop->getInternetStreamURL().empty()) { @@ -114,28 +115,28 @@ void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI mFadeState = FADE_IN; LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); - if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + if (stream && stream->supportsAdjustableBufferSizes()) + stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"), gSavedSettings.getU32("FMODExDecodeBufferSize")); gAudiop->startInternetStream(mNextStreamURI); - startFading(); - registerIdleListener(); - break; } + startFading(); + break; + case FADE_OUT: startFading(); - registerIdleListener(); break; case FADE_IN: - registerIdleListener(); break; default: LL_WARNS() << "Unknown fading state: " << mFadeState << LL_ENDL; - break; + return; } + + registerIdleListener(); } // A return of false from onIdleUpdate means it will be called again next idle update. @@ -236,15 +237,12 @@ void LLViewerAudio::startFading() // This minimum fade time prevents divide by zero and negative times const F32 AUDIO_MUSIC_MINIMUM_FADE_TIME = 0.01f; - if(mDone) + if (mDone) { // The fade state here should only be one of FADE_IN or FADE_OUT, but, in case it is not, // rather than check for both states assume a fade in and check for the fade out case. - mFadeTime = AUDIO_MUSIC_FADE_IN_TIME; - if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT) - { - mFadeTime = AUDIO_MUSIC_FADE_OUT_TIME; - } + mFadeTime = LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT ? + AUDIO_MUSIC_FADE_OUT_TIME : AUDIO_MUSIC_FADE_IN_TIME; // Prevent invalid fade time mFadeTime = llmax(mFadeTime, AUDIO_MUSIC_MINIMUM_FADE_TIME); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 060bdb6995..15b95d70a9 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -275,6 +275,7 @@ public: bool handle( const LLSD& params, const LLSD& query_map, + const std::string& grid, LLMediaCtrl* web) override { if (params.size() != 1) diff --git a/indra/newview/llviewerhelp.cpp b/indra/newview/llviewerhelp.cpp index 3273090da5..3181ae6283 100644 --- a/indra/newview/llviewerhelp.cpp +++ b/indra/newview/llviewerhelp.cpp @@ -45,7 +45,7 @@ public: // requests will be throttled from a non-trusted browser LLHelpHandler() : LLCommandHandler("help", UNTRUSTED_CLICK_ONLY) {} - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { LLViewerHelp* vhelp = LLViewerHelp::getInstance(); if (! vhelp) diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 226e0a9a56..7207d6c6ba 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1617,9 +1617,9 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask, // If the first LMB click is handled by the menu, skip the following double click static bool skip_double_click = false; - if (clicktype == CLICK_LEFT && down && !is_toolmgr_action) + if (clicktype == CLICK_LEFT && down) { - skip_double_click = handled; + skip_double_click = is_toolmgr_action ? false : handled; } if (double_click_sp && down) diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 94390b899d..c0a74e828e 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -234,8 +234,10 @@ public: // requires trusted browser to trigger LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_CLICK_ONLY) { } - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + bool handle(const LLSD& params, + const LLSD& query_map, + const std::string& grid, + LLMediaCtrl* web) { if (params.size() < 1) { diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index ba80eeb6b6..e914e2121c 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -63,6 +63,7 @@ LLViewerMediaFocus::~LLViewerMediaFocus() { // The destructor for LLSingletons happens at atexit() time, which is too late to do much. // Clean up in cleanupClass() instead. + gFocusMgr.removeKeyboardFocusWithoutCallback(this); } void LLViewerMediaFocus::setFocusFace(LLPointer objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 5b32ccf9e2..8686fad3e6 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -119,8 +119,10 @@ #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" #include "llvoavatarself.h" #include "llvoicevivox.h" +#include "llworld.h" #include "llworldmap.h" #include "pipeline.h" #include "llviewerjoystick.h" @@ -328,6 +330,7 @@ void handle_debug_avatar_textures(void*); void handle_grab_baked_texture(void*); BOOL enable_grab_baked_texture(void*); void handle_dump_region_object_cache(void*); +void handle_reset_interest_lists(void *); BOOL enable_save_into_task_inventory(void*); @@ -1291,49 +1294,66 @@ class LLAdvancedDumpRegionObjectCache : public view_listener_t } }; -class LLAdvancedInterestListFullUpdate : public view_listener_t +class LLAdvancedToggleInterestList360Mode : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - LLSD request; - LLSD body; - static bool using_360 = false; - - if (using_360) - { - body["mode"] = LLSD::String("default"); +public: + bool handleEvent(const LLSD &userdata) + { + // Toggle the mode - regions will get updated + if (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360) + { + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_DEFAULT); } else { - body["mode"] = LLSD::String("360"); + gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360); } - using_360 = !using_360; + return true; + } +}; - if (gAgent.requestPostCapability("InterestList", body, [](const LLSD& response) - { - LL_INFOS("360Capture") << - "InterestList capability responded: \n" << - ll_pretty_print_sd(response) << - LL_ENDL; - })) - { - LL_INFOS("360Capture") << - "Successfully posted an InterestList capability request with payload: \n" << - ll_pretty_print_sd(body) << - LL_ENDL; - return true; - } - else - { - LL_INFOS("360Capture") << - "Unable to post an InterestList capability request with payload: \n" << - ll_pretty_print_sd(body) << - LL_ENDL; - return false; - } +class LLAdvancedCheckInterestList360Mode : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + return (gAgent.getInterestListMode() == LLViewerRegion::IL_MODE_360); } }; +class LLAdvancedToggleStatsRecorder : public view_listener_t +{ + bool handleEvent(const LLSD &userdata) + { + if (LLViewerStatsRecorder::instance().isEnabled()) + { // Turn off both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(false); + } + else + { // Turn on both recording and logging + LLViewerStatsRecorder::instance().enableObjectStatsRecording(true, true); + } + return true; + } +}; + +class LLAdvancedCheckStatsRecorder : public view_listener_t +{ + bool handleEvent(const LLSD &userdata) + { // Use the logging state as the indicator of whether the stats recorder is on + return LLViewerStatsRecorder::instance().isLogging(); + } +}; + +class LLAdvancedResetInterestLists : public view_listener_t +{ + bool handleEvent(const LLSD &userdata) + { // Reset all region interest lists + handle_reset_interest_lists(NULL); + return true; + } +}; + + class LLAdvancedBuyCurrencyTest : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -3883,6 +3903,22 @@ void handle_dump_region_object_cache(void*) } } +void handle_reset_interest_lists(void *) +{ + // Check all regions and reset their interest list + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); + ++iter) + { + LLViewerRegion *regionp = *iter; + if (regionp && regionp->isAlive() && regionp->capabilitiesReceived()) + { + regionp->resetInterestList(); + } + } +} + + void handle_dump_focus() { LLUICtrl *ctrl = dynamic_cast(gFocusMgr.getKeyboardFocus()); @@ -4493,33 +4529,6 @@ void handle_duplicate_in_place(void*) LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); } -/* dead code 30-apr-2008 -void handle_deed_object_to_group(void*) -{ - LLUUID group_id; - - LLSelectMgr::getInstance()->selectGetGroup(group_id); - LLSelectMgr::getInstance()->sendOwner(LLUUID::null, group_id, FALSE); - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_RELEASE_COUNT); -} - -BOOL enable_deed_object_to_group(void*) -{ - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) return FALSE; - LLPermissions perm; - LLUUID group_id; - - if (LLSelectMgr::getInstance()->selectGetGroup(group_id) && - gAgent.hasPowerInGroup(group_id, GP_OBJECT_DEED) && - LLSelectMgr::getInstance()->selectGetPermissions(perm) && - perm.deedToGroup(gAgent.getID(), group_id)) - { - return TRUE; - } - return FALSE; -} - -*/ /* @@ -9063,6 +9072,25 @@ class LLWorldPostProcess : public view_listener_t } }; +class LLWorldCheckBanLines : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + S32 callback_data = userdata.asInteger(); + return gSavedSettings.getS32("ShowBanLines") == callback_data; + } +}; + +class LLWorldShowBanLines : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + S32 callback_data = userdata.asInteger(); + gSavedSettings.setS32("ShowBanLines", callback_data); + return true; + } +}; + void handle_flush_name_caches() { if (gCacheName) gCacheName->clear(); @@ -9352,6 +9380,8 @@ void initialize_menus() view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset"); view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset"); view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); + view_listener_t::addMenu(new LLWorldCheckBanLines() , "World.CheckBanLines"); + view_listener_t::addMenu(new LLWorldShowBanLines() , "World.ShowBanLines"); // Tools menu view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); @@ -9449,7 +9479,11 @@ void initialize_menus() // Advanced > World view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); - view_listener_t::addMenu(new LLAdvancedInterestListFullUpdate(), "Advanced.InterestListFullUpdate"); + view_listener_t::addMenu(new LLAdvancedToggleStatsRecorder(), "Advanced.ToggleStatsRecorder"); + view_listener_t::addMenu(new LLAdvancedCheckStatsRecorder(), "Advanced.CheckStatsRecorder"); + view_listener_t::addMenu(new LLAdvancedToggleInterestList360Mode(), "Advanced.ToggleInterestList360Mode"); + view_listener_t::addMenu(new LLAdvancedCheckInterestList360Mode(), "Advanced.CheckInterestList360Mode"); + view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists"); // Advanced > UI commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index beb592cac6..f3288a5300 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -100,6 +100,7 @@ #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" #include "llviewertexteditor.h" #include "llviewerthrottle.h" #include "llviewerwindow.h" @@ -3784,31 +3785,34 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) continue; } - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) + LLViewerObject *objectp = gObjectList.findObject(id); + if (objectp) + { + // Display green bubble on kill + if ( gShowObjectUpdates ) { - // Display green bubble on kill - if ( gShowObjectUpdates ) - { - LLColor4 color(0.f,1.f,0.f,1.f); - gPipeline.addDebugBlip(objectp->getPositionAgent(), color); - LL_DEBUGS("MessageBlip") << "Kill blip for local " << local_id << " at " << objectp->getPositionAgent() << LL_ENDL; - } - - // Do the kill - gObjectList.killObject(objectp); + LLColor4 color(0.f,1.f,0.f,1.f); + gPipeline.addDebugBlip(objectp->getPositionAgent(), color); + LL_DEBUGS("MessageBlip") << "Kill blip for local " << local_id << " at " << objectp->getPositionAgent() << LL_ENDL; } - if(delete_object) - { - regionp->killCacheEntry(local_id); + // Do the kill + gObjectList.killObject(objectp); + } + + if(delete_object) + { + regionp->killCacheEntry(local_id); } // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, // which is using the object, release the mouse capture correctly when the object dies. // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical(). LLSelectMgr::getInstance()->removeObjectFromSelections(id); - } + + } // end for loop + + LLViewerStatsRecorder::instance().recordObjectKills(num_objects); } void process_time_synch(LLMessageSystem *mesgsys, void **user_data) @@ -5176,6 +5180,11 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) LandBuyAccessBlocked_AdultsOnlyContent -----------------------------------------------------------------------*/ + static LLCachedControl ban_lines_mode(gSavedSettings , "ShowBanLines" , LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION); + if (ban_lines_mode == LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION) + { + LLViewerParcelMgr::getInstance()->resetCollisionTimer(); + } if (handle_special_notification(notificationID, llsdBlock)) { return true; @@ -5344,6 +5353,13 @@ void process_alert_message(LLMessageSystem *msgsystem, void **user_data) { BOOL modal = FALSE; process_alert_core(message, modal); + + static LLCachedControl ban_lines_mode(gSavedSettings , "ShowBanLines" , LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION); + if (ban_lines_mode == LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION + && message.find("Cannot enter parcel") != std::string::npos) + { + LLViewerParcelMgr::getInstance()->resetCollisionTimer(); + } } } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index efc4ded79e..c479afaa52 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -369,7 +369,7 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* if (!objectp) { LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL; - recorder.objectUpdateFailure(entry->getLocalID(), OUT_FULL_CACHED, 0); + recorder.objectUpdateFailure(); return NULL; } justCreated = true; @@ -393,7 +393,6 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* objectp->setLastUpdateType(OUT_FULL_COMPRESSED); //newly cached objectp->setLastUpdateCached(TRUE); } - recorder.log(0.2f); LLVOAvatar::cullAvatarsByPixelArea(); return objectp; @@ -472,18 +471,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, for (i = 0; i < num_objects; i++) { - // timer is unused? - LLTimer update_timer; BOOL justCreated = FALSE; - S32 msg_size = 0; bool update_cache = false; //update object cache if it is a full-update or terse update if (compressed) { - S32 uncompressed_length = 2048; compressed_dp.reset(); - uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); + S32 uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); LL_DEBUGS("ObjectUpdate") << "got binary data from message to compressed_dpbuffer" << LL_ENDL; mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i, 2048); compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); @@ -505,7 +500,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, << " Flags: " << flags << " Region: " << regionp->getName() << " Region id: " << regionp->getRegionID() << LL_ENDL; - recorder.objectUpdateFailure(local_id, update_type, msg_size); + recorder.objectUpdateFailure(); continue; } else if ((flags & FLAGS_TEMPORARY_ON_REZ) == 0) @@ -533,7 +528,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only? { mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - msg_size += sizeof(U32); getUUIDFromLocal(fullid, local_id, @@ -554,8 +548,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, update_cache = true; mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i); mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - msg_size += sizeof(LLUUID); - msg_size += sizeof(U32); LL_DEBUGS("ObjectUpdate") << "Full Update, obj " << local_id << ", global ID " << fullid << " from " << mesgsys->getSender() << LL_ENDL; } objectp = findObject(fullid); @@ -616,7 +608,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (update_type == OUT_TERSE_IMPROVED) { // LL_INFOS() << "terse update for an unknown object (compressed):" << fullid << LL_ENDL; - recorder.objectUpdateFailure(local_id, update_type, msg_size); + recorder.objectUpdateFailure(); continue; } } @@ -625,12 +617,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (update_type != OUT_FULL) { //LL_INFOS() << "terse update for an unknown object:" << fullid << LL_ENDL; - recorder.objectUpdateFailure(local_id, update_type, msg_size); + recorder.objectUpdateFailure(); continue; } mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_PCode, pcode, i); - msg_size += sizeof(U8); } #ifdef IGNORE_DEAD @@ -638,7 +629,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { mNumDeadObjectUpdates++; //LL_INFOS() << "update for a dead object:" << fullid << LL_ENDL; - recorder.objectUpdateFailure(local_id, update_type, msg_size); + recorder.objectUpdateFailure(); continue; } #endif @@ -651,7 +642,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (!objectp) { LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL; - recorder.objectUpdateFailure(local_id, update_type, msg_size); + recorder.objectUpdateFailure(); continue; } @@ -681,11 +672,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if(!(flags & FLAGS_TEMPORARY_ON_REZ)) { - bCached = true; + bCached = true; LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp, flags); - recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size); + recorder.cacheFullUpdate(result); + } } - } #endif } else @@ -696,12 +687,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated); } - recorder.objectUpdateEvent(local_id, update_type, objectp, msg_size); + recorder.objectUpdateEvent(update_type); objectp->setLastUpdateType(update_type); } - recorder.log(0.2f); - LLVOAvatar::cullAvatarsByPixelArea(); } @@ -734,28 +723,26 @@ void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys, for (S32 i = 0; i < num_objects; i++) { - S32 msg_size = 0; U32 id; U32 crc; U32 flags; mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i); mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); - msg_size += sizeof(U32) * 2; LL_DEBUGS("ObjectUpdate") << "got probe for id " << id << " crc " << crc << LL_ENDL; dumpStack("ObjectUpdateStack"); // Lookup data packer and add this id to cache miss lists if necessary. U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; - if(!regionp->probeCache(id, crc, flags, cache_miss_type)) - { - // Cache Miss. + if (regionp->probeCache(id, crc, flags, cache_miss_type)) + { // Cache Hit + recorder.cacheHitEvent(); + } + else + { // Cache Miss LL_DEBUGS("ObjectUpdate") << "cache miss for id " << id << " crc " << crc << " miss type " << (S32) cache_miss_type << LL_ENDL; - - recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size); - - continue; // no data packer, skip this object + recorder.cacheMissEvent(cache_miss_type); } } @@ -773,7 +760,6 @@ void LLViewerObjectList::dirtyAllObjectInventory() void LLViewerObjectList::updateApparentAngles(LLAgent &agent) { S32 i; - S32 num_objects = 0; LLViewerObject *objectp; S32 num_updates, max_value; @@ -830,8 +816,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) objectp = mObjects[i]; if (!objectp->isDead()) { - num_objects++; - // Update distance & gpw objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area objectp->updateTextures(); // Update the image levels of textures for this object. diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 97dc916bfe..15accd0547 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -72,12 +72,16 @@ #include "llenvironment.h" -const F32 PARCEL_COLLISION_DRAW_SECS = 1.f; +const F32 PARCEL_BAN_LINES_DRAW_SECS_ON_COLLISION = 10.f; +const F32 PARCEL_COLLISION_DRAW_SECS_ON_PROXIMITY = 1.f; // Globals U8* LLViewerParcelMgr::sPackedOverlay = NULL; +S32 LLViewerParcelMgr::PARCEL_BAN_LINES_HIDE = 0; +S32 LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION = 1; +S32 LLViewerParcelMgr::PARCEL_BAN_LINES_ON_PROXIMITY = 2; LLUUID gCurrentMovieID = LLUUID::null; @@ -892,13 +896,18 @@ void LLViewerParcelMgr::render() void LLViewerParcelMgr::renderParcelCollision() { + static LLCachedControl ban_lines_mode(gSavedSettings , "ShowBanLines" , PARCEL_BAN_LINES_ON_COLLISION); + // check for expiration - if (mCollisionTimer.getElapsedTimeF32() > PARCEL_COLLISION_DRAW_SECS) + F32 expiration = (ban_lines_mode == PARCEL_BAN_LINES_ON_PROXIMITY) + ? PARCEL_COLLISION_DRAW_SECS_ON_PROXIMITY + : PARCEL_BAN_LINES_DRAW_SECS_ON_COLLISION; + if (mCollisionTimer.getElapsedTimeF32() > expiration) { - mRenderCollision = FALSE; + mRenderCollision = false; } - if (mRenderCollision && gSavedSettings.getBOOL("ShowBanLines")) + if (mRenderCollision && ban_lines_mode != PARCEL_BAN_LINES_HIDE) { LLViewerRegion* regionp = gAgent.getRegion(); if (regionp) @@ -1842,8 +1851,11 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID) { // We're about to collide with this parcel - parcel_mgr.mRenderCollision = TRUE; - parcel_mgr.mCollisionTimer.reset(); + static LLCachedControl ban_lines_mode(gSavedSettings , "ShowBanLines" , PARCEL_BAN_LINES_ON_COLLISION); + if (ban_lines_mode == PARCEL_BAN_LINES_ON_PROXIMITY) + { + parcel_mgr.resetCollisionTimer(); + } // Differentiate this parcel if we are banned from it. if (sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID) diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 6ce389ab88..56dacd3efd 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -205,6 +205,11 @@ public: void renderHighlightSegments(const U8* segments, LLViewerRegion* regionp); void renderCollisionSegments(U8* segments, BOOL use_pass, LLViewerRegion* regionp); + static S32 PARCEL_BAN_LINES_HIDE; + static S32 PARCEL_BAN_LINES_ON_COLLISION; + static S32 PARCEL_BAN_LINES_ON_PROXIMITY; + void resetCollisionTimer(); // Ban lines visibility timer + void sendParcelGodForceOwner(const LLUUID& owner_id); // make the selected parcel a content parcel. @@ -361,7 +366,7 @@ private: // If it's coming, draw the parcel's boundaries. LLParcel* mCollisionParcel; U8* mCollisionSegments; - BOOL mRenderCollision; + bool mRenderCollision; BOOL mRenderSelection; S32 mCollisionBanned; LLFrameTimer mCollisionTimer; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 538a254c2e..84956d3b3d 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -104,6 +104,9 @@ S32 LLViewerRegion::sLastCameraUpdated = 0; S32 LLViewerRegion::sNewObjectCreationThrottle = -1; LLViewerRegion::vocache_entry_map_t LLViewerRegion::sRegionCacheCleanup; +const std::string LLViewerRegion::IL_MODE_DEFAULT = "default"; +const std::string LLViewerRegion::IL_MODE_360 = "360"; + typedef std::map CapabilityMap; static void log_capabilities(const CapabilityMap &capmap); @@ -131,8 +134,8 @@ class LLRegionHandler : public LLCommandHandler public: // requests will be throttled from a non-trusted browser LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {} - - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { // make sure that we at least have a region name int num_params = params.size(); @@ -143,6 +146,10 @@ public: // build a secondlife://{PLACE} SLurl from this SLapp std::string url = "secondlife://"; + if (!grid.empty()) + { + url += grid + "/secondlife/"; + } boost::regex name_rx("[A-Za-z0-9()_%]+"); boost::regex coord_rx("[0-9]+"); for (int i = 0; i < num_params; i++) @@ -642,7 +649,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mInvisibilityCheckHistory(-1), mPaused(FALSE), mRegionCacheHitCount(0), - mRegionCacheMissCount(0) + mRegionCacheMissCount(0), + mInterestListMode(IL_MODE_DEFAULT) { mWidth = region_width_meters; mImpl->mOriginGlobal = from_region_handle(handle); @@ -2618,14 +2626,10 @@ LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id, bool valid) return NULL; } -void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type) +void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType cache_miss_type) { mRegionCacheMissCount++; -#if 0 - mCacheMissList.insert(CacheMissItem(id, miss_type)); -#else - mCacheMissList.push_back(CacheMissItem(id, miss_type)); -#endif + mCacheMissList.push_back(CacheMissItem(id, cache_miss_type)); } //check if a non-cacheable object is already created. @@ -2701,10 +2705,10 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss } } else - { + { // Total miss, don't have the object in cache // LL_INFOS() << "Cache miss for " << local_id << LL_ENDL; - addCacheMiss(local_id, CACHE_MISS_TYPE_FULL); - cache_miss_type = CACHE_MISS_TYPE_FULL; + addCacheMiss(local_id, CACHE_MISS_TYPE_TOTAL); + cache_miss_type = CACHE_MISS_TYPE_TOTAL; } return false; @@ -2712,7 +2716,7 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss void LLViewerRegion::addCacheMissFull(const U32 local_id) { - addCacheMiss(local_id, CACHE_MISS_TYPE_FULL); + addCacheMiss(local_id, CACHE_MISS_TYPE_TOTAL); } void LLViewerRegion::requestCacheMisses() @@ -2763,7 +2767,6 @@ void LLViewerRegion::requestCacheMisses() mCacheDirty = TRUE ; // LL_INFOS() << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << LL_ENDL; LLViewerStatsRecorder::instance().requestCacheMissesEvent(mCacheMissList.size()); - LLViewerStatsRecorder::instance().log(0.2f); mCacheMissList.clear(); } @@ -3285,6 +3288,9 @@ void LLViewerRegion::setCapabilitiesReceived(bool received) // This is a single-shot signal. Forget callbacks to save resources. mCapabilitiesReceivedSignal.disconnect_all_slots(); + + // Set the region to the desired interest list mode + setInterestListMode(gAgent.getInterestListMode()); } } @@ -3303,7 +3309,111 @@ void LLViewerRegion::logActiveCapabilities() const log_capabilities(mImpl->mCapabilities); } -LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) + +bool LLViewerRegion::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url = getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Region") << "Could not retrieve region " << getRegionID() + << " POST capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, gAgent.getAgentPolicy(), postData, cbSuccess, cbFailure); + return true; +} + +bool LLViewerRegion::requestGetCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url; + + url = getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Region") << "Could not retrieve region " << getRegionID() + << " GET capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(url, gAgent.getAgentPolicy(), cbSuccess, cbFailure); + return true; +} + +bool LLViewerRegion::requestDelCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url; + + url = getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Region") << "Could not retrieve region " << getRegionID() << " DEL capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpDel(url, gAgent.getAgentPolicy(), cbSuccess, cbFailure); + return true; +} + +void LLViewerRegion::setInterestListMode(const std::string &new_mode) +{ + if (new_mode != mInterestListMode) + { + mInterestListMode = new_mode; + + if (mInterestListMode != std::string(IL_MODE_DEFAULT) && mInterestListMode != std::string(IL_MODE_360)) + { + LL_WARNS("360Capture") << "Region " << getRegionID() << " setInterestListMode() invalid interest list mode: " + << mInterestListMode << ", setting to default" << LL_ENDL; + mInterestListMode = IL_MODE_DEFAULT; + } + + LLSD body; + body["mode"] = mInterestListMode; + if (requestPostCapability("InterestList", body, + [](const LLSD &response) { + LL_DEBUGS("360Capture") << "InterestList capability responded: \n" + << ll_pretty_print_sd(response) << LL_ENDL; + })) + { + LL_DEBUGS("360Capture") << "Region " << getRegionID() + << " Successfully posted an InterestList capability request with payload: \n" + << ll_pretty_print_sd(body) << LL_ENDL; + } + else + { + LL_WARNS("360Capture") << "Region " << getRegionID() + << " Unable to post an InterestList capability request with payload: \n" + << ll_pretty_print_sd(body) << LL_ENDL; + } + } + else + { + LL_DEBUGS("360Capture") << "Region " << getRegionID() << "No change, skipping Interest List mode POST to " + << new_mode << " mode" << LL_ENDL; + } +} + + +void LLViewerRegion::resetInterestList() +{ + if (requestDelCapability("InterestList", [](const LLSD &response) { + LL_DEBUGS("360Capture") << "InterestList capability DEL responded: \n" << ll_pretty_print_sd(response) << LL_ENDL; + })) + { + LL_DEBUGS("360Capture") << "Region " << getRegionID() << " Successfully reset InterestList capability" << LL_ENDL; + } + else + { + LL_WARNS("360Capture") << "Region " << getRegionID() << " Unable to DEL InterestList capability request" << LL_ENDL; + } +} + + +LLSpatialPartition *LLViewerRegion::getSpatialPartition(U32 type) { if (type < mImpl->mObjectPartition.size() && type < PARTITION_VO_CACHE) { diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 6548e8d372..6956e9eb08 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -32,6 +32,7 @@ #include #include +#include "llcorehttputil.h" #include "llwind.h" #include "v3dmath.h" #include "llstring.h" @@ -278,6 +279,16 @@ public: static bool isSpecialCapabilityName(const std::string &name); void logActiveCapabilities() const; + // Utilities to post and get via + // HTTP using the agent's policy settings and headers. + typedef LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t httpCallback_t; + bool requestPostCapability(const std::string &capName, + LLSD &postData, + httpCallback_t cbSuccess = NULL, + httpCallback_t cbFailure = NULL); + bool requestGetCapability(const std::string &capName, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL); + bool requestDelCapability(const std::string &capName, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL); + /// implements LLCapabilityProvider /*virtual*/ const LLHost& getHost() const; const U64 &getHandle() const { return mHandle; } @@ -332,9 +343,9 @@ public: typedef enum { - CACHE_MISS_TYPE_FULL = 0, - CACHE_MISS_TYPE_CRC, - CACHE_MISS_TYPE_NONE + CACHE_MISS_TYPE_TOTAL = 0, // total cache miss - object not in cache + CACHE_MISS_TYPE_CRC, // object in cache, but CRC doesn't match + CACHE_MISS_TYPE_NONE // not a miss: cache hit } eCacheMissType; typedef enum @@ -477,7 +488,15 @@ public: }; typedef std::set region_priority_list_t; -private: + void setInterestListMode(const std::string & new_mode); + const std::string & getInterestListMode() const { return mInterestListMode; } + + void resetInterestList(); + + static const std::string IL_MODE_DEFAULT; + static const std::string IL_MODE_360; + + private: static S32 sNewObjectCreationThrottle; LLViewerRegionImpl * mImpl; LLFrameTimer mRegionTimer; @@ -551,10 +570,10 @@ private: class CacheMissItem { public: - CacheMissItem(U32 id, LLViewerRegion::eCacheMissType miss_type) : mID(id), mType(miss_type){} + CacheMissItem(U32 id, LLViewerRegion::eCacheMissType miss_type) : mID(id), mType(miss_type) {} - U32 mID; //local object id - LLViewerRegion::eCacheMissType mType; //cache miss type + U32 mID; //local object id + LLViewerRegion::eCacheMissType mType; // cache miss type typedef std::list cache_miss_list_t; }; @@ -574,6 +593,9 @@ private: LLFrameTimer mMaterialsCapThrottleTimer; LLFrameTimer mRenderInfoRequestTimer; LLFrameTimer mRenderInfoReportTimer; + + // how the server interest list works + std::string mInterestListMode; }; inline BOOL LLViewerRegion::getRegionProtocol(U64 protocol) const diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index b5ccf4ffa0..6372679a07 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -28,24 +28,25 @@ #include "llviewerstatsrecorder.h" +#include "llcontrol.h" #include "llfile.h" #include "llviewerregion.h" #include "llviewerobject.h" +#include "llworld.h" - -// To do - something using region name or global position -#if LL_WINDOWS - static const std::string STATS_FILE_NAME("C:\\ViewerObjectCacheStats.csv"); -#else - static const std::string STATS_FILE_NAME("/tmp/viewerstats.csv"); -#endif +extern LLControlGroup gSavedSettings; LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL; LLViewerStatsRecorder::LLViewerStatsRecorder() : - mObjectCacheFile(NULL), + mStatsFile(NULL), mTimer(), - mStartTime(0.0), - mLastSnapshotTime(0.0) + mFileOpenTime(0.0), + mLastSnapshotTime(0.0), + mEnableStatsRecording(false), + mEnableStatsLogging(false), + mInterval(0.2), + mMaxDuration(300.f), + mSkipSaveIfZeros(false) { if (NULL != sInstance) { @@ -57,79 +58,70 @@ LLViewerStatsRecorder::LLViewerStatsRecorder() : LLViewerStatsRecorder::~LLViewerStatsRecorder() { - if (mObjectCacheFile != NULL) + if (mStatsFile) { - // last chance snapshot - writeToLog(0.f); - LLFile::close(mObjectCacheFile); - mObjectCacheFile = NULL; + writeToLog(0.f); // Save last data + closeStatsFile(); } } void LLViewerStatsRecorder::clearStats() { mObjectCacheHitCount = 0; - mObjectCacheHitSize = 0; mObjectCacheMissFullCount = 0; - mObjectCacheMissFullSize = 0; mObjectCacheMissCrcCount = 0; - mObjectCacheMissCrcSize = 0; mObjectFullUpdates = 0; - mObjectFullUpdatesSize = 0; mObjectTerseUpdates = 0; - mObjectTerseUpdatesSize = 0; mObjectCacheMissRequests = 0; - mObjectCacheMissResponses = 0; - mObjectCacheMissResponsesSize = 0; mObjectCacheUpdateDupes = 0; mObjectCacheUpdateChanges = 0; mObjectCacheUpdateAdds = 0; mObjectCacheUpdateReplacements = 0; mObjectUpdateFailures = 0; - mObjectUpdateFailuresSize = 0; - mTextureFetchSize = 0; + mTextureFetchCount = 0; + mMeshLoadedCount = 0; + mObjectKills = 0; } -void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type, S32 msg_size) +void LLViewerStatsRecorder::enableObjectStatsRecording(bool enable, bool logging /* false */) { - mObjectUpdateFailures++; - mObjectUpdateFailuresSize += msg_size; + mEnableStatsRecording = enable; + + // if logging is stopping, close the file + if (mStatsFile && !logging) + { + writeToLog(0.f); // Save last data + closeStatsFile(); + } + mEnableStatsLogging = logging; } -void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type, S32 msg_size) + + +void LLViewerStatsRecorder::recordCacheMissEvent(U8 cache_miss_type) { - if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type) + if (LLViewerRegion::CACHE_MISS_TYPE_TOTAL == cache_miss_type) { mObjectCacheMissFullCount++; - mObjectCacheMissFullSize += msg_size; } else { mObjectCacheMissCrcCount++; - mObjectCacheMissCrcSize += msg_size; } } -void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp, S32 msg_size) + +void LLViewerStatsRecorder::recordObjectUpdateEvent(const EObjectUpdateType update_type) { - switch (update_type) + switch (update_type) { case OUT_FULL: - mObjectFullUpdates++; - mObjectFullUpdatesSize += msg_size; + case OUT_FULL_COMPRESSED: + mObjectFullUpdates++; break; case OUT_TERSE_IMPROVED: mObjectTerseUpdates++; - mObjectTerseUpdatesSize += msg_size; - break; - case OUT_FULL_COMPRESSED: - mObjectCacheMissResponses++; - mObjectCacheMissResponsesSize += msg_size; - break; - case OUT_FULL_CACHED: - mObjectCacheHitCount++; - mObjectCacheHitSize += msg_size; break; default: LL_WARNS() << "Unknown update_type" << LL_ENDL; @@ -137,9 +129,9 @@ void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectU }; } -void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp, S32 msg_size) +void LLViewerStatsRecorder::recordCacheFullUpdate(LLViewerRegion::eCacheUpdateResult update_result) { - switch (update_result) + switch (update_result) { case LLViewerRegion::CACHE_UPDATE_DUPE: mObjectCacheUpdateDupes++; @@ -154,124 +146,176 @@ void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpd mObjectCacheUpdateReplacements++; break; default: - LL_WARNS() << "Unknown update_result type" << LL_ENDL; + LL_WARNS() << "Unknown update_result type " << (S32) update_result << LL_ENDL; break; }; } -void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count) -{ - mObjectCacheMissRequests += count; -} - void LLViewerStatsRecorder::writeToLog( F32 interval ) { + if (!mEnableStatsLogging || !mEnableStatsRecording) + { + return; + } + size_t data_size = 0; - F64 delta_time = LLTimer::getTotalSeconds() - mLastSnapshotTime; - S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; + F64 delta_time = LLFrameTimer::getTotalSeconds() - mLastSnapshotTime; + if (delta_time < interval) + return; - if ( delta_time < interval || total_objects == 0) return; + if (mSkipSaveIfZeros) + { + S32 total_events = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheUpdateDupes + + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; + if (total_events == 0) + { + LL_DEBUGS("ILXZeroData") << "ILX: not saving zero data" << LL_ENDL; + return; + } + } - mLastSnapshotTime = LLTimer::getTotalSeconds(); - LL_DEBUGS() << "ILX: " + mLastSnapshotTime = LLFrameTimer::getTotalSeconds(); + LL_DEBUGS("ILX") << "ILX: " << mObjectCacheHitCount << " hits, " << mObjectCacheMissFullCount << " full misses, " << mObjectCacheMissCrcCount << " crc misses, " << mObjectFullUpdates << " full updates, " << mObjectTerseUpdates << " terse updates, " << mObjectCacheMissRequests << " cache miss requests, " - << mObjectCacheMissResponses << " cache miss responses, " << mObjectCacheUpdateDupes << " cache update dupes, " << mObjectCacheUpdateChanges << " cache update changes, " << mObjectCacheUpdateAdds << " cache update adds, " - << mObjectCacheUpdateReplacements << " cache update replacements, " - << mObjectUpdateFailures << " update failures" + << mObjectCacheUpdateReplacements << " cache update replacements," + << mObjectUpdateFailures << " update failures," + << mTextureFetchCount << " texture fetches, " + << mMeshLoadedCount << " mesh loads, " + << mObjectKills << " object kills" << LL_ENDL; - - if (mObjectCacheFile == NULL) + + if (mStatsFile == NULL) { - mStartTime = LLTimer::getTotalSeconds(); - mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb"); - if (mObjectCacheFile) - { // Write column headers - std::ostringstream data_msg; - data_msg << "EventTime(ms)\t" - << "Cache Hits\t" - << "Cache Full Misses\t" - << "Cache Crc Misses\t" - << "Full Updates\t" - << "Terse Updates\t" - << "Cache Miss Requests\t" - << "Cache Miss Responses\t" - << "Cache Update Dupes\t" - << "Cache Update Changes\t" - << "Cache Update Adds\t" - << "Cache Update Replacements\t" - << "Update Failures\t" - << "Cache Hits bps\t" - << "Cache Full Misses bps\t" - << "Cache Crc Misses bps\t" - << "Full Updates bps\t" - << "Terse Updates bps\t" - << "Cache Miss Responses bps\t" - << "Texture Fetch bps\t" - << "\n"; + // Refresh settings + mInterval = gSavedSettings.getF32("StatsReportFileInterval"); + mSkipSaveIfZeros = gSavedSettings.getBOOL("StatsReportSkipZeroDataSaves"); + mMaxDuration = gSavedSettings.getF32("StatsReportMaxDuration"); - data_size = data_msg.str().size(); - if (fwrite(data_msg.str().c_str(), 1, data_size, mObjectCacheFile ) != data_size) + // Open the data file + makeStatsFileName(); + mStatsFile = LLFile::fopen(mStatsFileName, "wb"); + + if (mStatsFile) + { + LL_INFOS("ILX") << "ILX: Writing update information to " << mStatsFileName << LL_ENDL; + + mFileOpenTime = LLFrameTimer::getTotalSeconds(); + + // Write column headers + std::ostringstream col_headers; + col_headers << "Time (sec)," + << "Regions," + << "Active Cached Objects," + << "Cache Hits," + << "Cache Full Misses," + << "Cache Crc Misses," + << "Full Updates," + << "Terse Updates," + << "Cache Miss Requests," // Normally results in a Full Update from simulator + << "Cache Update Dupes," + << "Cache Update Changes," + << "Cache Update Adds," + << "Cache Update Replacements," + << "Update Failures," + << "Texture Count," + << "Mesh Load Count," + << "Object Kills" + << "\n"; + + data_size = col_headers.str().size(); + if (fwrite(col_headers.str().c_str(), 1, data_size, mStatsFile ) != data_size) { - LL_WARNS() << "failed to write full headers to " << STATS_FILE_NAME << LL_ENDL; + LL_WARNS() << "failed to write full headers to " << mStatsFileName << LL_ENDL; + // Close the file and turn off stats logging + closeStatsFile(); + return; } } else - { - //LL_WARNS() << "Couldn't open " << STATS_FILE_NAME << " for logging." << LL_ENDL; + { // Failed to open file + LL_WARNS() << "Couldn't open " << mStatsFileName << " for logging, turning off stats recording." << LL_ENDL; + mEnableStatsLogging = false; return; } } - std::ostringstream data_msg; + std::ostringstream stats_data; - data_msg << getTimeSinceStart() - << "\t " << mObjectCacheHitCount - << "\t" << mObjectCacheMissFullCount - << "\t" << mObjectCacheMissCrcCount - << "\t" << mObjectFullUpdates - << "\t" << mObjectTerseUpdates - << "\t" << mObjectCacheMissRequests - << "\t" << mObjectCacheMissResponses - << "\t" << mObjectCacheUpdateDupes - << "\t" << mObjectCacheUpdateChanges - << "\t" << mObjectCacheUpdateAdds - << "\t" << mObjectCacheUpdateReplacements - << "\t" << mObjectUpdateFailures - << "\t" << (mObjectCacheHitSize * 8 / delta_time) - << "\t" << (mObjectCacheMissFullSize * 8 / delta_time) - << "\t" << (mObjectCacheMissCrcSize * 8 / delta_time) - << "\t" << (mObjectFullUpdatesSize * 8 / delta_time) - << "\t" << (mObjectTerseUpdatesSize * 8 / delta_time) - << "\t" << (mObjectCacheMissResponsesSize * 8 / delta_time) - << "\t" << (mTextureFetchSize * 8 / delta_time) + stats_data << getTimeSinceStart() + << "," << LLWorld::getInstance()->getRegionList().size() + << "," << LLWorld::getInstance()->getNumOfActiveCachedObjects() + << "," << mObjectCacheHitCount + << "," << mObjectCacheMissFullCount + << "," << mObjectCacheMissCrcCount + << "," << mObjectFullUpdates + << "," << mObjectTerseUpdates + << "," << mObjectCacheMissRequests + << "," << mObjectCacheUpdateDupes + << "," << mObjectCacheUpdateChanges + << "," << mObjectCacheUpdateAdds + << "," << mObjectCacheUpdateReplacements + << "," << mObjectUpdateFailures + << "," << mTextureFetchCount + << "," << mMeshLoadedCount + << "," << mObjectKills << "\n"; - data_size = data_msg.str().size(); - if ( data_size != fwrite(data_msg.str().c_str(), 1, data_size, mObjectCacheFile )) + data_size = stats_data.str().size(); + if ( data_size != fwrite(stats_data.str().c_str(), 1, data_size, mStatsFile )) { - LL_WARNS() << "Unable to write complete column data to " << STATS_FILE_NAME << LL_ENDL; - } + LL_WARNS() << "Unable to write complete column data to " << mStatsFileName << LL_ENDL; + closeStatsFile(); + } clearStats(); + + if (getTimeSinceStart() >= mMaxDuration) + { // If file recording has been running for too long, stop it. + closeStatsFile(); + } +} + +void LLViewerStatsRecorder::closeStatsFile() +{ + if (mStatsFile) + { + LL_INFOS("ILX") << "ILX: Stopped writing update information to " << mStatsFileName << " after " << getTimeSinceStart() + << " seconds." << LL_ENDL; + LLFile::close(mStatsFile); + mStatsFile = NULL; + } + mEnableStatsLogging = false; +} + +void LLViewerStatsRecorder::makeStatsFileName() +{ + // Create filename - tbd: use pid? +#if LL_WINDOWS + std::string stats_file_name("SLViewerStats-"); +#else + std::string stats_file_name("slviewerstats-"); +#endif + + F64 now = LLFrameTimer::getTotalSeconds(); + std::string date_str = LLDate(now).asString(); + std::replace(date_str.begin(), date_str.end(), ':', '-'); // Make it valid for a filename + stats_file_name.append(date_str); + stats_file_name.append(".csv"); + mStatsFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, stats_file_name); } F32 LLViewerStatsRecorder::getTimeSinceStart() { - return (F32) (LLTimer::getTotalSeconds() - mStartTime); -} - -void LLViewerStatsRecorder::recordTextureFetch( S32 msg_size ) -{ - mTextureFetchSize += msg_size; + return (F32) (LLFrameTimer::getTotalSeconds() - mFileOpenTime); } - diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index c974bea49d..b9fe02e54d 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -31,10 +31,6 @@ // This is a diagnostic class used to record information from the viewer // for analysis. -// This is normally 0. Set to 1 to enable viewer stats recording -#define LL_RECORD_VIEWER_STATS 0 - - #include "llframetimer.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -49,97 +45,132 @@ class LLViewerStatsRecorder : public LLSingleton ~LLViewerStatsRecorder(); public: - void objectUpdateFailure(U32 local_id, const EObjectUpdateType update_type, S32 msg_size) - { -#if LL_RECORD_VIEWER_STATS - recordObjectUpdateFailure(local_id, update_type, msg_size); -#endif + // Enable/disable stats recording. This is broken down into two + // flags so we can record stats without writing them to the log + // file. This is useful to analyzing updates for scene loading. + void enableObjectStatsRecording(bool enable, bool logging = false); + + bool isEnabled() const { return mEnableStatsRecording; } + bool isLogging() const { return mEnableStatsLogging; } + + void objectUpdateFailure() + { + if (mEnableStatsRecording) + { + mObjectUpdateFailures++; + } } - void cacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type, S32 msg_size) + void cacheMissEvent(U8 cache_miss_type) { -#if LL_RECORD_VIEWER_STATS - recordCacheMissEvent(local_id, update_type, cache_miss_type, msg_size); -#endif + if (mEnableStatsRecording) + { + recordCacheMissEvent(cache_miss_type); + } + } + + void cacheHitEvent() + { + if (mEnableStatsRecording) + { + mObjectCacheHitCount++; + } + } + + void objectUpdateEvent(const EObjectUpdateType update_type) + { + if (mEnableStatsRecording) + { + recordObjectUpdateEvent(update_type); + } } - void objectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp, S32 msg_size) - { -#if LL_RECORD_VIEWER_STATS - recordObjectUpdateEvent(local_id, update_type, objectp, msg_size); -#endif - } - - void cacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp, S32 msg_size) - { -#if LL_RECORD_VIEWER_STATS - recordCacheFullUpdate(local_id, update_type, update_result, objectp, msg_size); -#endif + void cacheFullUpdate(LLViewerRegion::eCacheUpdateResult update_result) + { + if (mEnableStatsRecording) + { + recordCacheFullUpdate(update_result); + } } void requestCacheMissesEvent(S32 count) { -#if LL_RECORD_VIEWER_STATS - recordRequestCacheMissesEvent(count); -#endif + if (mEnableStatsRecording) + { + mObjectCacheMissRequests += count; + } } - void textureFetch(S32 msg_size) + void textureFetch() { -#if LL_RECORD_VIEWER_STATS - recordTextureFetch(msg_size); -#endif + if (mEnableStatsRecording) + { + mTextureFetchCount += 1; + } } - void log(F32 interval) + void meshLoaded() { -#if LL_RECORD_VIEWER_STATS - writeToLog(interval); -#endif + if (mEnableStatsRecording) + { + mMeshLoadedCount += 1; + } + } + + void recordObjectKills(S32 num_objects) + { + if (mEnableStatsRecording) + { + mObjectKills += num_objects; + } + } + + void idle() + { + writeToLog(mInterval); } F32 getTimeSinceStart(); private: - void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type, S32 msg_size); - void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type, S32 msg_size); - void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp, S32 msg_size); - void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp, S32 msg_size); - void recordRequestCacheMissesEvent(S32 count); - void recordTextureFetch(S32 msg_size); + void recordCacheMissEvent(U8 cache_miss_type); + void recordObjectUpdateEvent(const EObjectUpdateType update_type); + void recordCacheFullUpdate(LLViewerRegion::eCacheUpdateResult update_result); void writeToLog(F32 interval); + void closeStatsFile(); + void makeStatsFileName(); static LLViewerStatsRecorder* sInstance; - LLFILE * mObjectCacheFile; // File to write data into + LLFILE * mStatsFile; // File to write data into + std::string mStatsFileName; + LLFrameTimer mTimer; - F64 mStartTime; + F64 mFileOpenTime; F64 mLastSnapshotTime; + F32 mInterval; // Interval between data log writes + F32 mMaxDuration; // Time limit on file + + bool mEnableStatsRecording; // Set to true to enable recording stats data + bool mEnableStatsLogging; // Set true to write stats to log file + bool mSkipSaveIfZeros; // Set true to skip saving stats if all values are zero S32 mObjectCacheHitCount; - S32 mObjectCacheHitSize; S32 mObjectCacheMissFullCount; - S32 mObjectCacheMissFullSize; S32 mObjectCacheMissCrcCount; - S32 mObjectCacheMissCrcSize; S32 mObjectFullUpdates; - S32 mObjectFullUpdatesSize; S32 mObjectTerseUpdates; - S32 mObjectTerseUpdatesSize; S32 mObjectCacheMissRequests; - S32 mObjectCacheMissResponses; - S32 mObjectCacheMissResponsesSize; S32 mObjectCacheUpdateDupes; S32 mObjectCacheUpdateChanges; S32 mObjectCacheUpdateAdds; S32 mObjectCacheUpdateReplacements; S32 mObjectUpdateFailures; - S32 mObjectUpdateFailuresSize; - S32 mTextureFetchSize; - + S32 mTextureFetchCount; + S32 mMeshLoadedCount; + S32 mObjectKills; void clearStats(); }; #endif // LLVIEWERSTATSRECORDER_H - diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 5ff84558cf..c28fed9ca4 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -1210,7 +1210,11 @@ void LLViewerTextEditor::openEmbeddedLandmark( LLPointer item_p void LLViewerTextEditor::openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc ) { - if(item && !item->getCreatorUUID().isNull()) + if (item && !item->getDescription().empty()) + { + LLAvatarActions::showProfile(LLUUID(item->getDescription())); + } + else if (item && !item->getCreatorUUID().isNull()) { LLAvatarActions::showProfile(item->getCreatorUUID()); } diff --git a/indra/newview/llviewerthrottle.cpp b/indra/newview/llviewerthrottle.cpp index 2729253d18..20390a316a 100644 --- a/indra/newview/llviewerthrottle.cpp +++ b/indra/newview/llviewerthrottle.cpp @@ -84,7 +84,7 @@ LLViewerThrottleGroup::LLViewerThrottleGroup() } -LLViewerThrottleGroup::LLViewerThrottleGroup(const F32 settings[]) +LLViewerThrottleGroup::LLViewerThrottleGroup(const F32 settings[TC_EOF]) { mThrottleTotal = 0.f; S32 i; diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index cc99f6af2f..24b1323b2b 100644 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -93,7 +93,6 @@ public: // the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem, // not the wearable asset itself. void refreshName(); - /*virtual*/void addToBakedTextureHash(LLMD5& hash) const {} protected: LLAssetID mAssetID; diff --git a/indra/newview/llvoicecallhandler.cpp b/indra/newview/llvoicecallhandler.cpp index 1e993d1384..95e11abd82 100644 --- a/indra/newview/llvoicecallhandler.cpp +++ b/indra/newview/llvoicecallhandler.cpp @@ -38,7 +38,7 @@ public: { } - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableVoiceCall")) { diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 150b556284..68d9f4ffab 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -53,7 +53,7 @@ public: // requests will be throttled from a non-trusted browser LLVoiceHandler() : LLCommandHandler("voice", UNTRUSTED_THROTTLE) {} - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { if (params[0].asString() == "effects") { diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index b0af565867..5cb7e7478b 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -408,7 +408,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, LLStrider &indicesp, U32 &index_offset) { - S32 vertex_count = 0; S32 i, x, y; S32 num_vertices; @@ -443,7 +442,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, normalsp++; texCoords0p++; texCoords1p++; - vertex_count++; } // North patch @@ -456,7 +454,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, normalsp++; texCoords0p++; texCoords1p++; - vertex_count++; } @@ -493,7 +490,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, normalsp++; texCoords0p++; texCoords1p++; - vertex_count++; } // Iterate through the north patch's points @@ -507,7 +503,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, normalsp++; texCoords0p++; texCoords1p++; - vertex_count++; } @@ -551,7 +546,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, normalsp++; texCoords0p++; texCoords1p++; - vertex_count++; } // Iterate through the north patch's points @@ -565,7 +559,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep, normalsp++; texCoords0p++; texCoords1p++; - vertex_count++; } for (i = 0; i < length; i++) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index bf9a4dfa12..4ddba872f1 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5110,6 +5110,28 @@ LLControlAVBridge::LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regi mPartitionType = LLViewerRegion::PARTITION_CONTROL_AV; } +void LLControlAVBridge::updateSpatialExtents() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + + LLControlAvatar* controlAvatar = getVObj()->getControlAvatar(); + + LLSpatialGroup* root = (LLSpatialGroup*)mOctree->getListener(0); + + bool rootWasDirty = root->isDirty(); + + super::updateSpatialExtents(); // root becomes non-dirty here + + // SL-18251 "On-screen animesh characters using pelvis offset animations + // disappear when root goes off-screen" + // + // Expand extents to include Control Avatar placed outside of the bounds + if (controlAvatar && (rootWasDirty || controlAvatar->mPlaying)) + { + root->expandExtents(controlAvatar->mDrawable->getSpatialExtents(), *mDrawable->getXform()); + } +} + bool can_batch_texture(LLFace* facep) { if (facep->getTextureEntry()->getBumpmap()) @@ -6306,7 +6328,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace LLSpatialGroup::buffer_map_t buffer_map; LLViewerTexture* last_tex = NULL; - S32 buffer_index = 0; S32 texture_index_channels = 1; @@ -6319,11 +6340,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels; } - - if (distance_sort) - { - buffer_index = -1; - } static LLCachedControl max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index); @@ -6347,14 +6363,9 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace tex = NULL; } - if (last_tex == tex) - { - buffer_index++; - } - else + if (last_tex != tex) { last_tex = tex; - buffer_index = 0; } bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic(); diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 89b74ae962..8681f7c14e 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -104,8 +104,6 @@ BOOL LLPanelWearableOutfitItem::postBuild() { LLPanelWearableListItem::postBuild(); - LLViewerInventoryItem* inv_item = getItem(); - mShowWidgets &= (inv_item->getType() != LLAssetType::AT_BODYPART); if(mShowWidgets) { addWidgetToRightSide("add_wearable"); @@ -208,7 +206,12 @@ void LLPanelWearableOutfitItem::updateItem(const std::string& name, if(mShowWidgets) { setShowWidget("add_wearable", !is_worn); - setShowWidget("remove_wearable", is_worn); + + // Body parts can't be removed, only replaced + LLViewerInventoryItem* inv_item = getItem(); + bool show_remove = is_worn && inv_item && (inv_item->getType() != LLAssetType::AT_BODYPART); + setShowWidget("remove_wearable", show_remove); + if(mHovered) { setWidgetsVisible(true); diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 8f46e66551..6dd58518c5 100755 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -50,6 +50,7 @@ #include "lltextureview.h" #include "lltracker.h" #include "llviewercamera.h" +#include "llviewernetwork.h" #include "llviewertexture.h" #include "llviewertexturelist.h" #include "llviewerregion.h" @@ -1829,7 +1830,7 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask ) // Invoke the event details floater if someone is clicking on an event. LLSD params(LLSD::emptyArray()); params.append(event_id); - LLCommandDispatcher::dispatch("event", params, LLSD(), NULL, LLCommandHandler::NAV_TYPE_CLICKED, true); + LLCommandDispatcher::dispatch("event", params, LLSD(), LLGridManager::getInstance()->getGrid(), NULL, LLCommandHandler::NAV_TYPE_CLICKED, true); break; } case MAP_ITEM_LAND_FOR_SALE: diff --git a/indra/newview/skins/default/html/ja/help-offline/index.html b/indra/newview/skins/default/html/ja/help-offline/index.html new file mode 100644 index 0000000000..aeaafe8216 --- /dev/null +++ b/indra/newview/skins/default/html/ja/help-offline/index.html @@ -0,0 +1,42 @@ + + + + + オフラインヘルプ + + + +
+

Second Lifeオフラインヘルプ

+

+ オンラインではなく、リモートでヘルプを取得しないように構成されています。 +
+ これは、さらに作業が完了するまで利用できるすべてのヘルプです。うん。 +

+
+ + diff --git a/indra/newview/skins/default/html/ja/loading-error/index.html b/indra/newview/skins/default/html/ja/loading-error/index.html index d969c03098..27d4425016 100644 --- a/indra/newview/skins/default/html/ja/loading-error/index.html +++ b/indra/newview/skins/default/html/ja/loading-error/index.html @@ -1,25 +1,99 @@ - - - -接続できません - - -

-

Second Lifeによるログインサーバーへの接続が確立できません。 -

-

インターネット接続を確認してください。 お使いのコンピュータやネットワークがファイヤウォールまたはプロキシにより保護されている場合は、Second Lifeによるネットワークへのアクセスが許可されていることを確認してください。 -

-
- - + + + + + 接続できません + + + +
+ unabletoconnect +
+

Second Lifeによるログインサーバーへの接続が確立できません。

+

+ インターネット接続を確認してください。 + お使いのコンピュータやネットワークがファイヤウォールまたはプロキシにより保護されている場合は、 + Second + Lifeによるネットワークへのアクセスが許可されていることを確認してください。 +

+
+ +
+
+ + diff --git a/indra/newview/skins/default/html/ja/loading/loading.html b/indra/newview/skins/default/html/ja/loading/loading.html index 35cf74a35f..ea576ed082 100644 --- a/indra/newview/skins/default/html/ja/loading/loading.html +++ b/indra/newview/skins/default/html/ja/loading/loading.html @@ -1,10 +1,22 @@ - - - - - - -
-
   ロード中... -
- + + + + + 読み込んでいます… + + + + loading +
+

   読み込んでいます…

+ + diff --git a/indra/newview/skins/default/xui/da/floater_animation_preview.xml b/indra/newview/skins/default/xui/da/floater_animation_preview.xml deleted file mode 100644 index adf96841c0..0000000000 --- a/indra/newview/skins/default/xui/da/floater_animation_preview.xml +++ /dev/null @@ -1,187 +0,0 @@ - - - - Fejlede at starte bevægelse - - - Animations filen er [LENGTH] sekunder lang. - -Maksimal animations længde er [MAX_LENGTH] sekunder. - - - Kan ikke læse animations fil. - -[STATUS] - - - OK - - - Fil afsluttet for tidligt. - - - Kan ikke læse "constraint definition". - - - Kan ikke åbne BVH fil. - - - Ugyldig header i HIERARCHY. - - - Kan ikke finde "ROOT" eller "JOINT". - - - Kan ikke finde JOINT navn. - - - Kan ikke finde OFFSET. - - - Kan ikke finde CHANNELS. - - - Kan ikke læse "rotation order". - - - Kan ikke finde rotationsakser. - - - Kan ikke finde MOTION. - - - Kan ikke læse antal "frames". - - - Kan ikke læse "frame time". - - - Kan ikke læse positionsværdier. - - - Kan ikke læse rotationsværdier. - - - kan ikke åbne "translation file". - - - Kan ikke læse "translation header. - - - Kan ikke aflæse "translation" navne. - - - Kan ikke læse "translation ignore" værdi. - - - Kan ikke læse "translation relative" værdi. - - - Kan ikke læse "translation outname" værdi. - - - Kan ikke læse "translation matrix". - - - Kan ikke læse "mergechild" navn. - - - Kan ikke læse "mergeparent" navn. - - - Kan ikke finde prioritetsværdi. - - - Kan ikke læse "loop" værdi. - - - kan ikke læse "easeIn" værdier. - - - Kan ikke læse "easeOut" værdier. - - - Kan ikke læse "hand morph" værdi. - - - kan ikke læse "emote" navn. - - - Incorrect root joint name, use "hip". - - - Navn: - - - Beskrivelse: - - - - - - - Hånd posering - - - - - - - - - - - - - - - - - - Ansigtsudtryk - - - - - - - - - - - - - - - - - - - - - - - - - Vis mens - - - - - - - - - - + diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby.xml b/indra/newview/skins/default/xui/en/menu_people_nearby.xml index c1500d4e7c..425de6cab8 100644 --- a/indra/newview/skins/default/xui/en/menu_people_nearby.xml +++ b/indra/newview/skins/default/xui/en/menu_people_nearby.xml @@ -75,7 +75,7 @@ name="remove_friend"> - diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index f72d1f0bf9..810d3fddd5 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -794,14 +794,36 @@ name="LandShow" tear_off="true"> + label="Hide Ban Lines" + name="Hide Ban Lines"> + function="World.CheckBanLines" + parameter="0" /> + function="World.ShowBanLines" + parameter="0" /> + + + + + + + + + - - + + + + - - - + + + + + + + - - - diff --git a/indra/newview/skins/default/xui/en/panel_script_experience.xml b/indra/newview/skins/default/xui/en/panel_script_experience.xml index e798638751..9ae5b201a6 100644 --- a/indra/newview/skins/default/xui/en/panel_script_experience.xml +++ b/indra/newview/skins/default/xui/en/panel_script_experience.xml @@ -48,23 +48,28 @@ layout="topleft" visible="false"> - + height="140" + name="xp_layout_panel"> + Script: - + Associated with: - + You can contribute: - + Associate with: + height="140" + name="xp_choose_panel"> EasySit Animator 1.2.4 diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml index 5647fd27db..fa2d4dfe73 100644 --- a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml +++ b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml @@ -319,7 +319,7 @@ Maximum Altitude: + For Sale: L$[AMOUNT] Group Build No Build - Group Build + No Edit Not Safe No Fly Group Scripts diff --git a/indra/newview/skins/default/xui/es/floater_chat_bar.xml b/indra/newview/skins/default/xui/es/floater_chat_bar.xml deleted file mode 100644 index 02369c9a43..0000000000 --- a/indra/newview/skins/default/xui/es/floater_chat_bar.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - + + + + + 名前タグ: + + + + + + + diff --git a/indra/newview/skins/default/xui/ja/panel_performance_preferences.xml b/indra/newview/skins/default/xui/ja/panel_performance_preferences.xml new file mode 100644 index 0000000000..a031cd7176 --- /dev/null +++ b/indra/newview/skins/default/xui/ja/panel_performance_preferences.xml @@ -0,0 +1,120 @@ + + +