# Conflicts:
#	indra/llcommon/llsdserialize.cpp
#	indra/llcommon/llsdserialize.h
#	indra/llmath/llvolume.cpp
#	indra/llrender/llgl.cpp
#	indra/llxml/llcontrol.cpp
#	indra/newview/llpanelnearbymedia.cpp
#	indra/newview/llsceneview.cpp
#	indra/newview/llselectmgr.cpp
#	indra/newview/llstartup.cpp
#	indra/newview/lltextureview.cpp
#	indra/newview/llvovolume.cpp
#	indra/newview/skins/default/xui/en/menu_viewer.xml
master
Ansariel 2023-08-25 02:57:48 +02:00
commit 701cf51cd7
462 changed files with 5685 additions and 3058 deletions

1
.gitattributes vendored
View File

@ -30,6 +30,7 @@ indra/tools/vstool/* -text
# Files with Windows line endings
VivoxAUP.txt text eol=crlf
FILES_ARE_UNICODE_UTF-16LE.txt text eol=crlf
*.nsi text eol=crlf
# Windows Manifest files
*.manifest text eol=crlf

93
.github/workflows/build.yaml vendored Normal file
View File

@ -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 }}

View File

@ -2,8 +2,9 @@ name: Build viewer
on:
push:
branches:
- "*release"
- master
- "Firestorm*.*.*"
tags:
- "preview"
schedule:
- cron: '00 03 * * *' # Run every day at 3am UTC
env:
@ -74,14 +75,14 @@ jobs:
- name: find channel from Branch name
run: |
if [[ "${{ github.ref_name }}" == *Release* ]]; then
if [[ "${{ github.ref_name }}" == Firestorm* ]]; then
FS_RELEASE_TYPE=Release
elif [[ "${{ github.ref_name }}" == *review* ]]; then
FS_RELEASE_TYPE=Beta
elif [[ "${{ github.event_name }}" == 'schedule' ]]; then
FS_RELEASE_TYPE=Nightly
else
if [[ "${{github.event_name}}" == 'schedule' ]]; then
FS_RELEASE_TYPE=Nightly
else
FS_RELEASE_TYPE=Beta
fi
FS_RELEASE_TYPE=Unknown
fi
if [[ "${{ matrix.addrsize }}" == "64" ]]; then
FS_RELEASE_CHAN="${FS_RELEASE_TYPE}x64"
@ -118,7 +119,11 @@ jobs:
shell: bash
- name: rclone the private 3p packages for this platform (both 64 & 32)
run: 'rclone copy fs_bundles: --include "*${{ env.fallback_platform }}*bz2" .'
run: 'rclone copy fs_bundles: --filter "- Alpha/*" --filter "+ *${{ env.fallback_platform }}*bz2" .'
- name: rclone any extra private 3p packages for Alpha (allows library updates not in the main repo)
if: env.FS_BUILD_TYPE == 'Alpha'
run: 'rclone copy fs_bundles:Alpha --include "*${{ env.fallback_platform }}*bz2" .'
- name: set VSVER for Windows builds
if: runner.os == 'Windows'
@ -255,17 +260,17 @@ jobs:
- name: find channel and webhook from Branch name
run: |
if [[ "${{ github.ref_name }}" == *Release* ]]; then
if [[ "${{ github.ref_name }}" == Firestorm* ]]; then
FS_RELEASE_FOLDER=release
FS_BUILD_WEBHOOK_URL=${{ secrets.RELEASE_WEBHOOK_URL }}
else
if [[ "${{github.event_name}}" == 'schedule' ]]; then
FS_RELEASE_FOLDER=nightly
FS_BUILD_WEBHOOK_URL=${{ secrets.NIGHTLY_WEBHOOK_URL }}
else
elif [[ "${{ github.ref_name }}" == *review* ]]; then
FS_RELEASE_FOLDER=preview
FS_BUILD_WEBHOOK_URL=${{ secrets.BETA_WEBHOOK_URL }}
fi
elif [[ "${{ github.event_name }}" == 'schedule' ]]; then
FS_RELEASE_FOLDER=nightly
FS_BUILD_WEBHOOK_URL=${{ secrets.NIGHTLY_WEBHOOK_URL }}
else
FS_RELEASE_TYPE=Unknown
fi
echo "FS_RELEASE_FOLDER=${FS_RELEASE_FOLDER}" >> $GITHUB_ENV
echo "FS_BUILD_WEBHOOK_URL=${FS_BUILD_WEBHOOK_URL}" >> $GITHUB_ENV

18
.github/workflows/pre-commit.yaml vendored Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -3430,9 +3430,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>9e1b5515ab59b4e9cfeef6626d65d03d</string>
<string>6ba629ff34c4b14a1f851de707bc35041df8b6a9</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108609/945996/viewer_manager-3.0.577252-darwin64-577252.tar.bz2</string>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-bd3aec2/viewer_manager-3.0-bd3aec2-darwin64-bd3aec2.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3442,24 +3444,28 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>129b80dd47b53bfa02fc21ab1eb1901c</string>
<string>7e086a28db17b0c086a5460e9d62f0c6584560b3</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>http://3p.firestormviewer.org/viewer_manager-1.0.180861311-linux64-180861311.tar.bz2</string>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-bd3aec2/viewer_manager-3.0-bd3aec2-linux64-bd3aec2.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>windows</key>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>a3c599595ecc8fb987a5499fca42520a</string>
<string>1eab994c0c1df5b2c057878a4071a88320cec978</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/108610/946003/viewer_manager-3.0.577252-windows-577252.tar.bz2</string>
<string>https://github.com/secondlife/viewer-manager/releases/download/v3.0-bd3aec2/viewer_manager-3.0-bd3aec2-windows64-bd3aec2.tar.zst</string>
</map>
<key>name</key>
<string>windows</string>
<string>windows64</string>
</map>
</map>
<key>source</key>
@ -3467,7 +3473,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>3.0.577252</string>
<string>3.0-bd3aec2</string>
</map>
<key>vlc-bin</key>
<map>
@ -4404,7 +4410,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<string>/t:Build</string>
<string>/p:useenv=true</string>
<string>/verbosity:minimal</string>
<string>/toolsversion:4.0</string>
<string>/p:VCBuildAdditionalOptions= /incremental</string>
</array>
</map>
@ -4478,7 +4483,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<string>/t:Build</string>
<string>/p:useenv=true</string>
<string>/verbosity:minimal</string>
<string>/toolsversion:4.0</string>
<string>/p:VCBuildAdditionalOptions= /incremental</string>
</array>
</map>

View File

@ -600,6 +600,7 @@ Henri Beauchamp
VWR-4157
SL-15175
SL-19110
SL-19159
herina Bode
Hikkoshi Sakai
VWR-429
@ -940,6 +941,8 @@ Lexi Frua
Lillie Cordeaux
Lilly Zenovka
Lizzy Macarthur
Logue Takacs
INTL-490
Luban Yiyuan
Luc Starsider
Luminous Luminos
@ -1196,6 +1199,7 @@ PanteraPolnocy
SL-18891
SL-18904
SL-18937
SL-19207
SL-19681
Parvati Silverweb
Patric Mills

View File

@ -77,11 +77,9 @@ 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.
# <FS:ND> Remove this, it's no option to cl.exe and causes a massive amount of warnings.
#if( ADDRESS_SIZE EQUAL 32 )
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64")
#endif()
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
add_link_options(/LARGEADDRESSAWARE
/SAFESEH:NO
@ -216,6 +214,10 @@ if (DARWIN)
set(ENABLE_SIGNING TRUE)
set(SIGNING_IDENTITY "Developer ID Application: The Phoenix Firestorm Project, 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)

View File

@ -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 (DEFINED ENV{VIRTUAL_ENV})
@ -53,7 +57,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")

View File

@ -32,7 +32,7 @@
#include "llsaleinfo.h"
#include "llwearabletype.h"
class LLMD5;
class LLMD5; // <FS:Ansariel> [Legacy Bake]
class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
@ -131,6 +131,7 @@ public:
// Something happened that requires the wearable to be updated (e.g. worn/unworn).
virtual void setUpdated() const = 0;
// <FS:Ansariel> [Legacy Bake]
// Update the baked texture hash.
virtual void addToBakedTextureHash(LLMD5& hash) const = 0;

View File

@ -31,7 +31,7 @@
#include "llavatarappearance.h"
#include "llavatarappearancedefines.h"
#include "lldriverparam.h"
#include "llmd5.h"
#include "llmd5.h" // <FS:Ansariel> [Legacy Bake]
LLWearableData::LLWearableData() :
mAvatarAppearance(NULL)
@ -355,6 +355,7 @@ U32 LLWearableData::getWearableCount(const U32 tex_index) const
return getWearableCount(wearable_type);
}
// <FS:Ansariel> [Legacy Bake]
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
{
@ -391,5 +392,6 @@ LLUUID LLWearableData::computeBakedTextureHash(LLAvatarAppearanceDefines::EBaked
return hash_id;
}
// </FS:Ansariel> [Legacy Bake]

View File

@ -85,6 +85,7 @@ protected:
private:
void pullCrossWearableValues(const LLWearableType::EType type);
// <FS:Ansariel> [Legacy Bake]
//--------------------------------------------------------------------
// Server Communication
//--------------------------------------------------------------------
@ -93,6 +94,7 @@ public:
BOOL generate_valid_hash = TRUE);
protected:
virtual void invalidateBakedTextureHash(LLMD5& hash) const {}
// </FS:Ansariel> [Legacy Bake]
//--------------------------------------------------------------------
// Member variables

View File

@ -217,7 +217,8 @@ std::string LLAudioEngine::getInternetStreamURL()
{
if (mStreamingAudioImpl)
return mStreamingAudioImpl->getURL();
else return std::string();
return std::string();
}
@ -358,42 +359,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();
}
}
}
}
@ -409,18 +411,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();
}
}
@ -755,7 +750,7 @@ F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec)
}
return (gain);
}
}
F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec)
@ -996,11 +991,10 @@ void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp)
else
{
LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <<LL_ENDL;
delete asp;
mAllSources.erase(iter);
delete asp;
mAllSources.erase(iter);
}
}
}
bool LLAudioEngine::hasDecodedFile(const LLUUID &uuid)
{
@ -1829,19 +1823,18 @@ void LLAudioChannel::setSource(LLAudioSource *sourcep)
{
LL_DEBUGS("AudioEngine") << "( id: " << sourcep->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()
{

View File

@ -95,6 +95,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
@ -526,13 +527,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;
}
};

View File

@ -308,10 +308,6 @@ bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title
Check_FMOD_Error(mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]), "FMOD::System::createChannelGroup");
}
// 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;
FMOD_ADVANCEDSETTINGS settings_dump = { };
@ -395,6 +391,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)
{
try

View File

@ -59,6 +59,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();

View File

@ -500,13 +500,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:

View File

@ -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);

View File

@ -349,6 +349,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!!

View File

@ -828,11 +828,11 @@ bool unix_post_minidump_callback(const char *dump_dir,
auto dirPathLength = strlen(dump_dir);
auto idLength = strlen(minidump_id);
// The path must not be truncated.
llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
// The path must not be truncated, and we need to have room left for a terminating zero.
llassert((dirPathLength + idLength + 5) < LLApp::MAX_MINDUMP_PATH_LENGTH); // <FS:Beq/> Buffer overrun avoidance (from Aleric Inglewood)
char * path = LLApp::instance()->getMiniDumpFilename();
auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - 1; // <FS:Beq/> Buffer overrun avoidance (from Aleric Inglewood
strncpy(path, dump_dir, remaining);
remaining -= dirPathLength;
path += dirPathLength;

View File

@ -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 <typename T1, typename T2>
inline auto llmax(T1 d1, T2 d2)
// recursion tail
template <typename T>
inline auto llmax(T data)
{
return (d1 > d2) ? d1 : d2;
return data;
}
template <typename T1, typename T2, typename T3>
inline auto llmax(T1 d1, T2 d2, T3 d3)
template <typename T0, typename T1, typename... Ts>
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 <typename T1, typename T2, typename T3, typename T4>
inline auto llmax(T1 d1, T2 d2, T3 d3, T4 d4)
// recursion tail
template <typename T>
inline auto llmin(T data)
{
auto r1 = llmax(d1,d2);
auto r2 = llmax(d3,d4);
return llmax(r1, r2);
return data;
}
template <typename T1, typename T2>
inline auto llmin(T1 d1, T2 d2)
template <typename T0, typename T1, typename... Ts>
inline auto llmin(T0 d0, T1 d1, Ts... rest)
{
return (d1 < d2) ? d1 : d2;
}
template <typename T1, typename T2, typename T3>
inline auto llmin(T1 d1, T2 d2, T3 d3)
{
auto r = llmin(d1,d2);
return (r < d3 ? r : d3);
}
template <typename T1, typename T2, typename T3, typename T4>
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 <typename A, typename MIN, typename MAX>

View File

@ -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<U64>(buffer.tellp()) << " != "
<< "str().length() -> " << strdata.length() << LL_ENDL;
}
// DEBUGGING ONLY: reading back is terribly inefficient.
std::istringstream readback(strdata);
LLSD echo;
LLPointer<LLSDParser> 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<LLSDParser> 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");
}

View File

@ -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<uint4*>(&count), 8);
// Treat count, a uint64_t, as uint32_t[2].
encode (bits, reinterpret_cast<uint32_t*>(&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);
}

View File

@ -67,6 +67,8 @@ documentation and/or software.
*/
#include <cstdint> // 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);
};

View File

@ -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 <class Formatter>
void format_using(const LLSD& data, std::ostream& ostr,
LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY)
{
LLPointer<Formatter> f{ new Formatter };
f->format(data, ostr, options);
}
template <class Parser>
S32 parse_using(std::istream& istr, LLSD& data, size_t max_bytes, S32 max_depth=-1)
{
LLPointer<Parser> 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 << "<? " << LLSD_NOTATION_HEADER << " ?>\n";
f = new LLSDNotationFormatter;
break;
case LLSD_NOTATION:
str << "<? " << LLSD_NOTATION_HEADER << " ?>\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<LLSDParser> 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<std::string::size_type>(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("<? ");
if (start != std::string::npos)
{
end = header.find_first_of(" ?", start);
}
if ((start == std::string::npos) || (end == std::string::npos))
goto fail;
/*
* Remove the newline chars
*/
std::string::size_type lastchar = header.find_last_not_of("\r\n");
if (lastchar != std::string::npos)
{
// It's important that find_last_not_of() returns size_type, which is
// why lastchar explicitly declares the type above. erase(size_type)
// erases from that offset to the end of the string, whereas
// erase(iterator) erases only a single character.
header.erase(lastchar+1);
}
header = header.substr(start, end - start);
ws(str);
// trim off the <? ... ?> header syntax
auto start = header.find_first_not_of("<? ");
if (start != std::string::npos)
{
auto end = header.find_first_of(" ?", start);
if (end != std::string::npos)
{
header = header.substr(start, end - start);
ws(str);
}
}
/*
* Create the parser as appropriate
*/
if (legacy_no_header)
{ // Create a LLSD XML parser, and parse the first chunk read above
LLSDXMLParser* x = new LLSDXMLParser();
x->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<LLSDBinaryParser>(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<LLSDXMLParser>(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<LLSDNotationParser>(str, sd, max_bytes-inbuf) > 0);
}
else
else // no header we recognize
{
LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL;
LLPointer<LLSDParser> 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<const U8*>(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<char> wholemsg((max_bytes == size_t(SIZE_UNLIMITED))? 1024 : max_bytes);
prepend.read(wholemsg.data(), std::min(max_bytes, wholemsg.size()));
LLMemoryStream replay(reinterpret_cast<const U8*>(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;
}
/**
@ -2195,7 +2250,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32
U8* result = NULL;
llssize cur_size = 0;
z_stream strm;
constexpr U32 CHUNK = 1024 * 512;
static thread_local std::unique_ptr<U8[]> out;
@ -2399,7 +2454,7 @@ U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size
return result;
}
char* strip_deprecated_header(char* in, llssize& cur_size, U32* header_size)
char* strip_deprecated_header(char* in, llssize& cur_size, llssize* header_size)
{
const char* deprecated_header = "<? LLSD/Binary ?>";
constexpr size_t deprecated_header_size = 17;

View File

@ -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, llssize& 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

View File

@ -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<char>::eof()
: std::char_traits<char>::to_int_type(*gptr());
}

View File

@ -27,8 +27,10 @@
#ifndef LL_STREAM_TOOLS_H
#define LL_STREAM_TOOLS_H
#include <deque>
#include <iostream>
#include <string>
#include <vector>
// 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<std::streambuf*> mInputs;
std::vector<char> mBuffer;
public:
// only valid for std::streambuf* arguments
template <typename... Inputs>
cat_streambuf(Inputs... inputs):
mInputs{inputs...},
mBuffer(1024)
{}
int underflow() override;
};
#endif

View File

@ -577,10 +577,12 @@ S32 Recording::getSampleCount( const StatType<EventAccumulator>& 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<Recording>::iterator src_it = other.mRecordingPeriods.begin() + other_index ;
std::vector<Recording>::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<Recording&>(
const_cast<const PeriodicRecording*>(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<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
F64 min_val = std::numeric_limits<F64>::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<EventAccumulator>& stat, siz
: NaN;
}
F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
F64 max_val = std::numeric_limits<F64>::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<EventAccumulator>& stat, siz
}
// calculates means using aggregates per period
F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
@ -842,7 +828,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& 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<EventAccumulator>& stat, si
: NaN;
}
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
@ -866,7 +852,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
F64 sum_of_squares = 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))
@ -882,14 +868,14 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
: NaN;
}
F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
F64 min_val = std::numeric_limits<F64>::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<SampleAccumulator>& stat, si
: NaN;
}
F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/)
F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
F64 max_val = std::numeric_limits<F64>::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<SampleAccumulator>& stat, siz
}
F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
@ -935,7 +921,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& 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<SampleAccumulator>& stat, s
: NaN;
}
F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
std::vector<F64> 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<SampleAccumulator>& 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<SampleAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
@ -985,7 +971,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
S32 valid_period_count = 0;
F64 sum_of_squares = 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))
@ -1002,13 +988,13 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
}
F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64Kilobytes min_val(std::numeric_limits<F64>::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<const StatType<MemAccumulator>&>(stat), num_periods);
}
F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/)
F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::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<const StatType<MemAccumulator>&>(stat), num_periods);
}
F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::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<const StatType<MemAccumulator>&>(stat), num_periods);
}
F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, size_t num_periods /*= S32_MAX*/ )
F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
@ -1072,7 +1058,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAc
S32 valid_period_count = 0;
F64 sum_of_squares = 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))

View File

@ -33,6 +33,7 @@
#include "lltimer.h"
#include "lltraceaccumulators.h"
#include "llpointer.h"
#include <limits>
class LLStopWatchControlsMixinCommon
{
@ -330,7 +331,7 @@ namespace LLTrace
: public LLStopWatchControlsMixin<PeriodicRecording>
{
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 <typename T>
auto getSampleCount(const StatType<T>& stat, size_t num_periods = S32_MAX)
auto getSampleCount(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::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>
typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = S32_MAX)
typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::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<typename T::value_t>::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<typename T>
T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::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 T>
typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
@ -449,14 +450,14 @@ namespace LLTrace
// catch all for stats that have a defined sum
template <typename T>
typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = S32_MAX)
typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::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<typename T::value_t>::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<typename T>
T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64 max_val = std::numeric_limits<F64>::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 T>
typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
@ -525,14 +526,14 @@ namespace LLTrace
// catch all for stats that have a defined sum
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
typename RelatedTypes<typename T::value_t>::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 T>
typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
typename RelatedTypes<typename T::value_t>::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 T>
typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = S32_MAX)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
std::vector <typename RelatedTypes<typename T::value_t>::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 <typename RelatedTypes<typename T::value_t>::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<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
}
return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
}
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = S32_MAX)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
//
// PERIODIC STANDARD DEVIATION
//
F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = S32_MAX);
F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = S32_MAX)
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = S32_MAX);
F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::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<Recording> mRecordingPeriods;
const bool mAutoResize;

View File

@ -888,7 +888,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);
}

View File

@ -171,6 +171,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;
@ -222,29 +230,23 @@ public:
LLAssetID makeAssetID(const LLUUID& session) const;
};
// Generate a hash of an LLUUID object using the boost hash templates.
// <FS:ND> GCC 4.9 does not like the specialization in form of boost::hash but rather wants a namespace
// template <>
// struct boost::hash<LLUUID>
namespace boost { template <> struct hash<LLUUID>
// </FS:ND>
// std::hash implementation for LLUUID
namespace std
{
typedef LLUUID argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const
{
result_type seed(0);
template<> struct hash<LLUUID>
{
inline size_t operator()(const LLUUID& id) const noexcept
{
return (size_t)id.getDigest64();
}
};
}
for (S32 i = 0; i < UUID_BYTES; ++i)
{
boost::hash_combine(seed, s.mData[i]);
}
return seed;
}
};
} // <FS:ND/> close namespace
// For use with boost containers.
inline size_t hash_value(const LLUUID& id) noexcept
{
return (size_t)id.getDigest64();
}
// <FS:Ansariel> UUID hash calculation
struct FSUUIDHash
@ -256,17 +258,4 @@ struct FSUUIDHash
};
// </FS:Ansariel> UUID hash calculation
// Adapt boost hash to std hash
namespace std
{
template<> struct hash<LLUUID>
{
std::size_t operator()(LLUUID const& s) const noexcept
{
return boost::hash<LLUUID>()(s);
}
};
}
#endif
#endif // LL_LLUUID_H

View File

@ -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<std::size_t>::type llssize; // <FS:Ansariel> Stop Linux complaining
typedef typename std::make_signed<std::size_t>::type llssize;
#if LL_WINDOWS
// https://docs.microsoft.com/en-us/cpp/build/reference/zc-wchar-t-wchar-t-is-native-type

View File

@ -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"

View File

@ -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 <functional>
typedef std::function<void(const LLSD& data, std::ostream& str)> FormatterFunction;
typedef std::function<bool(std::istream& istr, LLSD& data, llssize max_bytes)> ParserFunction;
std::vector<U8> string_to_vector(const std::string& str)
{
@ -112,7 +116,7 @@ namespace tut
mSD = LLUUID::null;
expected = "<llsd><uuid /></llsd>\n";
xml_test("null uuid", expected);
mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed");
expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n";
xml_test("uuid", expected);
@ -136,7 +140,7 @@ namespace tut
expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
xml_test("binary", expected);
}
template<> template<>
void sd_xml_object::test<2>()
{
@ -225,7 +229,7 @@ namespace tut
expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n";
xml_test("2 element map", expected);
}
template<> template<>
void sd_xml_object::test<6>()
{
@ -241,7 +245,7 @@ namespace tut
expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\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<LLSDFormatter> mFormatter;
LLPointer<LLSDParser> mParser;
void setFormatterParser(LLPointer<LLSDFormatter> formatter, LLPointer<LLSDParser> 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<U8> 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<TestLLSDSerializeData> 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<TestLLSDXMLParsing> 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",
"<llsd><map>"
@ -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",
"<llsd><map>"
@ -626,7 +725,7 @@ namespace tut
"</map></llsd>",
v,
v.size() + 1);
v.clear();
v["amy"] = 23;
v["cam"] = 1.23;
@ -639,7 +738,7 @@ namespace tut
"</map></llsd>",
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",
"<llsd><array>"
@ -671,7 +770,7 @@ namespace tut
"</array></llsd>",
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 <typename CONTENT>
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 <typename CONTENT>
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<TestPythonCompatible> 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<int>(buffstr.length()) };
out.write(reinterpret_cast<const char*>(&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<char*>(&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<U8> buffer(length);
istr.read(reinterpret_cast<char*>(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; });
}
|*==========================================================================*/
}

View File

@ -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,

View File

@ -1336,5 +1336,47 @@ 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

View File

@ -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);

View File

@ -171,8 +171,11 @@ 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_MANAGERS_OS = 15; // <FS:Ansariel> OpenSim
const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access
const S32 ESTATE_MAX_BANNED_IDS = 750; // max for banned
const S32 ESTATE_MAX_BANNED_IDS_OS = 500; // max for banned // <FS:Ansariel> OpenSim
const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET;
// 'Sim Wide Delete' flags

View File

@ -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

View File

@ -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<LLMaterialID>
{
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

View File

@ -69,6 +69,7 @@ LLDragHandle::LLDragHandle(const LLDragHandle::Params& p)
LLDragHandle::~LLDragHandle()
{
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
removeChild(mTitleBox);
delete mTitleBox;
}

View File

@ -196,6 +196,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
LLFolderViewItem::~LLFolderViewItem()
{
mViewModelItem = NULL;
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
}
BOOL LLFolderViewItem::postBuild()

View File

@ -89,6 +89,8 @@ LLLayoutPanel::~LLLayoutPanel()
// probably not necessary, but...
delete mResizeBar;
mResizeBar = NULL;
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
}
F32 LLLayoutPanel::getAutoResizeFactor() const

View File

@ -70,6 +70,11 @@ LLResizeHandle::LLResizeHandle(const LLResizeHandle::Params& p)
}
}
LLResizeHandle::~LLResizeHandle()
{
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
}
BOOL LLResizeHandle::handleMouseDown(S32 x, S32 y, MASK mask)
{

View File

@ -45,6 +45,7 @@ public:
Params();
};
~LLResizeHandle();
protected:
LLResizeHandle(const LLResizeHandle::Params&);
friend class LLUICtrlFactory;

View File

@ -908,6 +908,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
continue;
}
// Got an item. Load it up.
// If not declared, assume it's a string
if (!declared)
{

View File

@ -1 +1 @@
6.6.14
6.6.15

View File

@ -240,6 +240,12 @@
<string>NoAudio</string>
</map>
<key>nofmod</key>
<map>
<key>map-to</key>
<string>UseMediaPluginsForStreamingAudio</string>
</map>
<key>noninteractive</key>
<map>
<key>desc</key>

View File

@ -9904,6 +9904,17 @@
<key>Backup</key>
<integer>0</integer>
</map>
<key>UseMediaPluginsForStreamingAudio</key>
<map>
<key>Comment</key>
<string>Use media plugins (VLC) for streaming audio.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>NoHardwareProbe</key>
<map>
<key>Comment</key>
@ -14555,11 +14566,11 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>ShowBanLines</key>
<map>
<key>Comment</key>
<string>Show in-world ban/access borders</string>
<string>Show in-world ban/access borders, 0 - do not show, 1 - show on collision, 2 - show on proximity</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<string>S32</string>
<key>Value</key>
<integer>1</integer>
</map>
@ -22265,17 +22276,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>360CaptureUseInterestListCap</key>
<map>
<key>Comment</key>
<string>Flag if set, uses the new InterestList cap to ask the simulator for full content</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>360CaptureJPEGEncodeQuality</key>
<map>
<key>Comment</key>
@ -23680,6 +23680,39 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>StatsReportMaxDuration</key>
<map>
<key>Comment</key>
<string>Maximum seconds for viewer stats file data, prevents huge file</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>300</real>
</map>
<key>StatsReportFileInterval</key>
<map>
<key>Comment</key>
<string>Interval to save viewer stats file data</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.2</real>
</map>
<key>StatsReportSkipZeroDataSaves</key>
<map>
<key>Comment</key>
<string>In viewer stats data file, skip saving entry if there is no data</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSNetMapPhantomOpacity</key>
<map>
<key>Comment</key>
@ -26405,5 +26438,16 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>FSSortAttachmentSpotsAlphabetically</key>
<map>
<key>Comment</key>
<string>Sorts the attachment spots in the "Attach to" menus alphabetically</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
</map>
</llsd>

View File

@ -174,11 +174,6 @@ FSAreaSearch::FSAreaSearch(const LLSD& key) :
mRlvBehaviorCallbackConnection()
{
LLViewerRegion::sFSAreaSearchActive = true;
if( LLViewerRegion* region = gAgent.getRegion() )
{
checkRegion();
}
mFactoryMap["area_search_list_panel"] = LLCallbackMap(createPanelList, this);
mFactoryMap["area_search_find_panel"] = LLCallbackMap(createPanelFind, this);
mFactoryMap["area_search_filter_panel"] = LLCallbackMap(createPanelFilter, this);
@ -190,24 +185,11 @@ FSAreaSearch::FSAreaSearch(const LLSD& key) :
mParcelChangedObserver = std::make_unique<FSParcelChangeObserver>(this);
LLViewerParcelMgr::getInstance()->addObserver(mParcelChangedObserver.get());
mRegionChangeConnection = gAgent.addRegionChangedCallback(boost::bind(&FSAreaSearch::checkRegion, this));
}
FSAreaSearch::~FSAreaSearch()
{
LLViewerRegion::sFSAreaSearchActive = false;
// Tell the Simulator not to send us everything anymore
// and revert to the regular "keyhole" frustum of interest
// list updates.
if( !LLApp::isExiting() )
{
if( LLViewerRegion* region = gAgent.getRegion() )
{
region->useFullUpdateInterestListMode(false);
}
}
if (!gIdleCallbacks.deleteFunction(idle, this))
{
LL_WARNS("FSAreaSearch") << "FSAreaSearch::~FSAreaSearch() failed to delete callback" << LL_ENDL;
@ -232,11 +214,6 @@ FSAreaSearch::~FSAreaSearch()
LLViewerParcelMgr::getInstance()->removeObserver(mParcelChangedObserver.get());
mParcelChangedObserver = nullptr;
}
if (mRegionChangeConnection.connected())
{
mRegionChangeConnection.disconnect();
}
}
BOOL FSAreaSearch::postBuild()
@ -343,28 +320,24 @@ void FSAreaSearch::updateRlvRestrictions(ERlvBehaviour behavior)
void FSAreaSearch::checkRegion()
{
static LLUUID last_region_id = LLUUID::null;
auto last_region = LLWorld::instance().getRegionFromID(last_region_id);
// Check if we changed region, if so reset the interest list to full,
LLViewerRegion* region = gAgent.getRegion();
if( region && (region != last_region) )
{
region->useFullUpdateInterestListMode(true, true); // we force this because we want a true count
if ( mActive )
if (mActive)
{
// Check if we changed region, and if we did, clear the object details cache.
if (LLViewerRegion* region = gAgent.getRegion(); region && (region != mLastRegion))
{
// and if we did and are active, clear the object details cache.
if( !mExcludeNeighborRegions )
if (!mExcludeNeighborRegions)
{
std::vector<LLViewerRegion*> uniqueRegions;
region->getNeighboringRegions(uniqueRegions);
if( std::find( uniqueRegions.begin(), uniqueRegions.end(), last_region ) != uniqueRegions.end() )
if (std::find(uniqueRegions.begin(), uniqueRegions.end(), mLastRegion) != uniqueRegions.end())
{
// Crossed into a neighboring region, no need to clear everything.
last_region_id = region->getRegionID();
mLastRegion = region;
return;
}
// else teleported into a new region
}
mLastRegion = region;
mRequested = 0;
mObjectDetails.clear();
mRegionRequests.clear();
@ -374,14 +347,7 @@ void FSAreaSearch::checkRegion()
mPanelList->setAgentLastPosition(gAgent.getPositionGlobal());
mRefresh = true;
}
if( last_region )
{
// we clear the old region status, because the instance may persist for us
// but the region itself will have reset when we left.
last_region->clearFullUpdateInterestList();
}
}
last_region_id = region->getRegionID();
}
void FSAreaSearch::refreshList(bool cache_clear)

View File

@ -213,8 +213,7 @@ private:
typedef std::map<LLUUID, boost::signals2::connection> name_cache_connection_map_t;
name_cache_connection_map_t mNameCacheConnections;
boost::signals2::connection mRegionChangeConnection; // reset interest list verbosity after TP
LLViewerRegion* mLastRegion;
class FSParcelChangeObserver;
friend class FSParcelChangeObserver;

View File

@ -96,7 +96,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)
{

View File

@ -23,7 +23,7 @@
FSFloaterPoseStand::FSFloaterPoseStand(const LLSD& key)
: LLFloater(key),
mComboPose(NULL),
mComboPose(nullptr),
mPoseStandLock(false),
mAOPaused(false)
{

View File

@ -30,7 +30,7 @@
FSFloaterRadar::FSFloaterRadar(const LLSD& key)
: LLFloater(key),
mRadarPanel(NULL)
mRadarPanel(nullptr)
{
}

View File

@ -135,8 +135,7 @@ BOOL FSFloaterWearableFavorites::postBuild()
mOptionsButton = getChild<LLMenuButton>("options_btn");
LLToggleableMenu* options_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_fs_wearable_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
if (options_menu)
if (LLToggleableMenu* options_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_fs_wearable_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); options_menu)
{
mOptionsMenuHandle = options_menu->getHandle();
mOptionsButton->setMenu(options_menu, LLMenuButton::MP_BOTTOM_LEFT);
@ -204,8 +203,7 @@ BOOL FSFloaterWearableFavorites::handleKeyHere(KEY key, MASK mask)
// static
std::optional<LLUUID> FSFloaterWearableFavorites::getWearableFavoritesFolderID()
{
LLUUID fs_root_cat_id = gInventory.findCategoryByName(ROOT_FIRESTORM_FOLDER);
if (!fs_root_cat_id.isNull())
if (LLUUID fs_root_cat_id = gInventory.findCategoryByName(ROOT_FIRESTORM_FOLDER); !fs_root_cat_id.isNull())
{
LLInventoryModel::item_array_t* items;
LLInventoryModel::cat_array_t* cats;
@ -339,8 +337,7 @@ bool FSFloaterWearableFavorites::onOptionsMenuItemChecked(const LLSD& userdata)
void FSFloaterWearableFavorites::onDoubleClick()
{
LLUUID selected_item_id = mItemsList->getSelectedUUID();
if (selected_item_id.notNull())
if (LLUUID selected_item_id = mItemsList->getSelectedUUID(); selected_item_id.notNull())
{
uuid_vec_t ids;
ids.push_back(selected_item_id);

View File

@ -1437,7 +1437,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 (params.size() < 2)
{

View File

@ -120,9 +120,9 @@ bool FSKeywords::chatContainsKeyword(const LLChat& chat, bool is_local)
if (sFSKeywordMatchWholeWords)
{
for (std::vector<std::string>::iterator it = mWordList.begin(); it != mWordList.end(); ++it)
for (const auto& word : mWordList)
{
if (boost::regex_search(source, boost::regex("\\b" + (*it) + "\\b")))
if (boost::regex_search(source, boost::regex("\\b" + word + "\\b")))
{
return true;
}
@ -130,9 +130,9 @@ bool FSKeywords::chatContainsKeyword(const LLChat& chat, bool is_local)
}
else
{
for (std::vector<std::string>::iterator it = mWordList.begin(); it != mWordList.end(); ++it)
for (const auto& word : mWordList)
{
if (source.find((*it)) != std::string::npos)
if (source.find(word) != std::string::npos)
{
return true;
}
@ -145,30 +145,27 @@ bool FSKeywords::chatContainsKeyword(const LLChat& chat, bool is_local)
// <FS:PP> FIRE-10178: Keyword Alerts in group IM do not work unless the group is in the foreground
void FSKeywords::notify(const LLChat& chat)
{
if (chat.mFromID != gAgentID || chat.mFromName == SYSTEM_FROM)
if ((chat.mFromID != gAgentID || chat.mFromName == SYSTEM_FROM) && !chat.mMuted && !LLMuteList::getInstance()->isMuted(chat.mFromID))
{
if (!chat.mMuted && !LLMuteList::getInstance()->isMuted(chat.mFromID))
static LLCachedControl<bool> PlayModeUISndFSKeywordSound(gSavedPerAccountSettings, "PlayModeUISndFSKeywordSound");
if (PlayModeUISndFSKeywordSound)
{
static LLCachedControl<bool> PlayModeUISndFSKeywordSound(gSavedPerAccountSettings, "PlayModeUISndFSKeywordSound");
if (PlayModeUISndFSKeywordSound)
{
LLUI::getInstance()->mAudioCallback(LLUUID(gSavedPerAccountSettings.getString("UISndFSKeywordSound")));
}
LLUI::getInstance()->mAudioCallback(LLUUID(gSavedPerAccountSettings.getString("UISndFSKeywordSound")));
}
static LLCachedControl<bool> FSEnableGrowl(gSavedSettings, "FSEnableGrowl");
if (FSEnableGrowl)
static LLCachedControl<bool> FSEnableGrowl(gSavedSettings, "FSEnableGrowl");
if (FSEnableGrowl)
{
std::string msg = chat.mFromName;
if (is_irc_me_prefix(chat.mText))
{
std::string msg = chat.mFromName;
if (is_irc_me_prefix(chat.mText))
{
msg = msg + chat.mText.substr(3);
}
else
{
msg = msg + ": " + chat.mText;
}
GrowlManager::notify("Keyword Alert", msg, GROWL_KEYWORD_ALERT_TYPE);
msg = msg + chat.mText.substr(3);
}
else
{
msg = msg + ": " + chat.mText;
}
GrowlManager::notify("Keyword Alert", msg, GROWL_KEYWORD_ALERT_TYPE);
}
}
}

View File

@ -148,16 +148,13 @@ void FSMoneyTrackerListMenu::onContextMenuItemClick(const LLSD& userdata)
if (option == "copy")
{
FSMoneyTracker* floater = LLFloaterReg::findTypedInstance<FSMoneyTracker>("money_tracker");
if (floater)
if (FSMoneyTracker* floater = LLFloaterReg::findTypedInstance<FSMoneyTracker>("money_tracker"); floater)
{
std::string copy_text;
LLNameListCtrl* list = floater->getChild<LLNameListCtrl>("payment_list");
std::vector<LLScrollListItem*> selected = list->getAllSelected();
for (std::vector<LLScrollListItem*>::iterator it = selected.begin(); it != selected.end(); ++it)
for (auto item : list->getAllSelected())
{
const LLScrollListItem* item = *it;
copy_text += ( (copy_text.empty() ? "" : "\n")
+ item->getColumn(0)->getValue().asString() + ";"
+ item->getColumn(1)->getValue().asString() + ";"

View File

@ -48,10 +48,10 @@
#include "rlvactions.h"
#include "rlvhandler.h"
static const U32 NAME_PREDICTION_MINIMUM_LENGTH = 3;
constexpr U32 NAME_PREDICTION_MINIMUM_LENGTH = 3;
// *HACK* chat bar cannot return its correct height for some reason
static const S32 MAGIC_CHAT_BAR_PAD = 5;
constexpr S32 MAGIC_CHAT_BAR_PAD = 5;
struct LLChatTypeTrigger {
std::string name;
@ -237,8 +237,8 @@ bool matchChatTypeTrigger(const std::string& in_str, std::string* out_str)
S32 FSNearbyChat::sLastSpecialChatChannel = 0;
FSNearbyChat::FSNearbyChat() :
mDefaultChatBar(NULL),
mFocusedInputEditor(NULL)
mDefaultChatBar(nullptr),
mFocusedInputEditor(nullptr)
{
gSavedSettings.getControl("MainChatbarVisible")->getSignal()->connect(boost::bind(&FSNearbyChat::onDefaultChatBarButtonClicked, this));
}
@ -847,7 +847,7 @@ public:
LLChatCommandHandler() : LLCommandHandler("chat", UNTRUSTED_THROTTLE) { }
// 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)
{
bool retval = false;

View File

@ -132,12 +132,11 @@ BOOL FSPanelBlockList::handleKeyHere(KEY key, MASK mask)
void FSPanelBlockList::selectBlocked(const LLUUID& mute_id)
{
mBlockedList->deselectAllItems();
std::vector<LLScrollListItem*> items = mBlockedList->getAllData();
for (std::vector<LLScrollListItem*>::iterator it = items.begin(); it != items.end(); it++)
for (auto item : mBlockedList->getAllData())
{
if ((*it)->getColumn(3)->getValue().asUUID() == mute_id)
if (item->getColumn(3)->getValue().asUUID() == mute_id)
{
(*it)->setSelected(TRUE);
item->setSelected(TRUE);
break;
}
}
@ -171,17 +170,15 @@ void FSPanelBlockList::refreshBlockedList()
{
mBlockedList->deleteAllItems();
std::vector<LLMute> mutes = LLMuteList::getInstance()->getMutes();
std::vector<LLMute>::iterator it;
for (it = mutes.begin(); it != mutes.end(); ++it)
for (const auto& mute : LLMuteList::getInstance()->getMutes())
{
LLScrollListItem::Params item_p;
item_p.enabled(TRUE);
item_p.enabled(true);
item_p.value(LLUUID::generateNewID()); // can't link UUID of blocked item directly because of mutes by name
item_p.columns.add().column("item_name").value(it->mName);
item_p.columns.add().column("item_type").value(it->getDisplayType());
item_p.columns.add().column("item_mute_type").value(it->mType);
item_p.columns.add().column("item_mute_uuid").value(it->mID);
item_p.columns.add().column("item_name").value(mute.mName);
item_p.columns.add().column("item_type").value(mute.getDisplayType());
item_p.columns.add().column("item_mute_type").value(mute.mType);
item_p.columns.add().column("item_mute_uuid").value(mute.mID);
mBlockedList->addRow(item_p, ADD_BOTTOM);
}
@ -208,11 +205,10 @@ void FSPanelBlockList::removeMutes()
// list after each removal, sending us straight into a crash!
LLMuteList::getInstance()->removeObserver(this);
std::vector<LLScrollListItem*> selected_items = mBlockedList->getAllSelected();
for (std::vector<LLScrollListItem*>::iterator it = selected_items.begin(); it != selected_items.end(); it++)
for (auto item : mBlockedList->getAllSelected())
{
std::string name = (*it)->getColumn(COL_NAME)->getValue().asString();
LLUUID id = (*it)->getColumn(COL_UUID)->getValue().asUUID();
std::string name = item->getColumn(COL_NAME)->getValue().asString();
LLUUID id = item->getColumn(COL_UUID)->getValue().asUUID();
LLMute mute(id, name);
LLMuteList::getInstance()->remove(mute);
}

View File

@ -95,7 +95,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)
{

View File

@ -89,7 +89,7 @@ FSPanelRadar::FSPanelRadar()
mFSRadarColumnConfigConnection(),
mLastResizeDelta(0)
{
mButtonsUpdater = new FSButtonsUpdater(boost::bind(&FSPanelRadar::updateButtons, this));
mButtonsUpdater = std::make_unique<FSButtonsUpdater>(boost::bind(&FSPanelRadar::updateButtons, this));
mCommitCallbackRegistrar.add("Radar.AddFriend", boost::bind(&FSPanelRadar::onAddFriendButtonClicked, this));
mCommitCallbackRegistrar.add("Radar.Gear", boost::bind(&FSPanelRadar::onGearButtonClicked, this, _1));
@ -117,9 +117,8 @@ FSPanelRadar::~FSPanelRadar()
mFSRadarColumnConfigConnection.disconnect();
}
delete mButtonsUpdater;
if (mOptionsMenuHandle.get()) mOptionsMenuHandle.get()->die();
if (mOptionsMenuHandle.get())
mOptionsMenuHandle.get()->die();
}
BOOL FSPanelRadar::postBuild()
@ -152,8 +151,7 @@ BOOL FSPanelRadar::postBuild()
mRadarGearButton = getChild<LLButton>("gear_btn");
mOptionsButton = getChild<LLMenuButton>("options_btn");
LLToggleableMenu* options_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_fs_radar_options.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
if (options_menu)
if (LLToggleableMenu* options_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_fs_radar_options.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); options_menu)
{
mOptionsMenuHandle = options_menu->getHandle();
mOptionsButton->setMenu(options_menu, LLMenuButton::MP_BOTTOM_LEFT);
@ -204,8 +202,7 @@ void FSPanelRadar::updateButtons()
LLUUID FSPanelRadar::getCurrentItemID() const
{
LLScrollListItem* item = mRadarList->getFirstSelected();
if (item)
if (LLScrollListItem* item = mRadarList->getFirstSelected(); item)
{
return item->getUUID();
}
@ -251,21 +248,14 @@ void FSPanelRadar::onRadarListDoubleClicked()
LLUUID clicked_id = item->getUUID();
std::string name = item->getColumn(mRadarList->getColumn("name")->mIndex)->getValue().asString();
FSRadar* radar = FSRadar::getInstance();
if (radar)
{
radar->zoomAvatar(clicked_id, name);
}
FSRadar::getInstance()->zoomAvatar(clicked_id, name);
}
void FSPanelRadar::onRadarListCommitted()
{
uuid_vec_t selected_uuids;
LLUUID sVal = mRadarList->getSelectedValue().asUUID();
if (sVal.notNull())
if (LLUUID sVal = mRadarList->getSelectedValue().asUUID(); sVal.notNull())
{
selected_uuids.push_back(sVal);
mMiniMap->setSelected(selected_uuids);
mMiniMap->setSelected({ sVal });
}
updateButtons();
@ -274,8 +264,7 @@ void FSPanelRadar::onRadarListCommitted()
void FSPanelRadar::onAddFriendButtonClicked()
{
LLUUID id = getCurrentItemID();
if (id.notNull())
if (LLUUID id = getCurrentItemID(); id.notNull())
{
LLAvatarActions::requestFriendshipDialog(id);
}
@ -301,14 +290,10 @@ void FSPanelRadar::onGearButtonClicked(LLUICtrl* btn)
void FSPanelRadar::requestUpdate()
{
FSRadar* radar = FSRadar::getInstance();
if (radar)
{
std::vector<LLSD> entries;
LLSD stats;
radar->getCurrentData(entries, stats);
updateList(entries, stats);
}
std::vector<LLSD> entries;
LLSD stats;
FSRadar::getInstance()->getCurrentData(entries, stats);
updateList(entries, stats);
}
void FSPanelRadar::updateList(const std::vector<LLSD>& entries, const LLSD& stats)
@ -422,21 +407,21 @@ void FSPanelRadar::updateList(const std::vector<LLSD>& entries, const LLSD& stat
radarNameCell->setColor(LLColor4(options["name_color"]));
}
LLScrollListText* voiceLevelCell = (LLScrollListText*)row->getColumn(voiceLevelColumnIndex);
if (entry.has("voice_level_icon"))
{
LLScrollListText* voiceLevelCell = (LLScrollListText*)row->getColumn(voiceLevelColumnIndex);
voiceLevelCell->setValue(entry["voice_level_icon"].asString());
}
LLScrollListText* flagsCell = (LLScrollListText*)row->getColumn(flagsColumnIndex);
if (entry.has("flags"))
{
LLScrollListText* flagsCell = (LLScrollListText*)row->getColumn(flagsColumnIndex);
flagsCell->setValue(flagsColumnValues[entry["flags"].asInteger()]);
}
LLScrollListText* ageCell = (LLScrollListText*)row->getColumn(ageColumnIndex);
if (options.has("age_color"))
{
LLScrollListText* ageCell = (LLScrollListText*)row->getColumn(ageColumnIndex);
ageCell->setColor(LLColor4(options["age_color"]));
}
}
@ -477,7 +462,7 @@ void FSPanelRadar::onColumnDisplayModeChanged()
std::vector<LLScrollListColumn::Params> column_params = mRadarList->getColumnInitParams();
S32 column_padding = mRadarList->getColumnPadding();
LLFloater* parent_floater = nullptr;
LLFloater* parent_floater{ nullptr };
LLView* parent = getParent();
while (parent)
{
@ -493,8 +478,8 @@ void FSPanelRadar::onColumnDisplayModeChanged()
return;
}
S32 default_width = 0;
S32 new_width = 0;
S32 default_width{ 0 };
S32 new_width{ 0 };
S32 min_width, min_height;
parent_floater->getResizeLimits(&min_width, &min_height);
@ -558,8 +543,7 @@ void FSPanelRadar::onColumnVisibilityChecked(const LLSD& userdata)
U32 column_config = gSavedSettings.getU32("FSRadarColumnConfig");
U32 new_value;
U32 enabled = (mColumnBits[column] & column_config);
if (enabled)
if (U32 enabled = (mColumnBits[column] & column_config); enabled)
{
new_value = (column_config & ~mColumnBits[column]);
}

View File

@ -92,7 +92,7 @@ private:
LLHandle<LLView> mOptionsMenuHandle;
FSRadar::Updater* mButtonsUpdater;
std::unique_ptr<FSRadar::Updater> mButtonsUpdater;
std::string mFilterSubString;
std::string mFilterSubStringOrig;

View File

@ -290,14 +290,13 @@ void FSRadar::updateRadarList()
// Skip modelling this avatar if its basic data is either inaccessible, or it's a dummy placeholder
auto ent = getEntry(avId);
LLViewerRegion* reg = world->getRegionFromPosGlobal(avPos);
if (!ent) // don't update this radar listing if data is inaccessible
{
continue;
}
// Try to get the avatar's viewer object - we will need it anyway later
LLVOAvatar* avVo = (LLVOAvatar*)gObjectList.findObject(avId);
LLVOAvatar* avVo = static_cast<LLVOAvatar*>(gObjectList.findObject(avId));
static LLUICachedControl<bool> sFSShowDummyAVsinRadar("FSShowDummyAVsinRadar");
if (!sFSShowDummyAVsinRadar && avVo && avVo->mIsDummy)
@ -315,7 +314,7 @@ void FSRadar::updateRadarList()
}
LLUUID avRegion;
if (reg)
if (LLViewerRegion* reg = world->getRegionFromPosGlobal(avPos); reg)
{
avRegion = reg->getRegionID();
}
@ -595,11 +594,10 @@ void FSRadar::updateRadarList()
// Voice power level indicator
if (voice_client->voiceEnabled() && voice_client->isVoiceWorking())
{
LLSpeaker* speaker = speakermgr->findSpeaker(avId);
if (speaker && speaker->isInVoiceChannel())
if (LLSpeaker* speaker = speakermgr->findSpeaker(avId); speaker && speaker->isInVoiceChannel())
{
EVoicePowerLevel power_level = voice_client->getPowerLevel(avId);
switch (power_level)
{
case VPL_PTT_Off:
@ -703,8 +701,7 @@ void FSRadar::updateRadarList()
}
static LLCachedControl<S32> sRadarAlertChannel(gSavedSettings, "RadarAlertChannel");
U32 num_entering = (U32)mRadarEnterAlerts.size();
if (num_entering > 0)
if (U32 num_entering = (U32)mRadarEnterAlerts.size(); num_entering > 0)
{
mRadarFrameCount++;
U32 num_this_pass = llmin(FSRADAR_MAX_AVATARS_PER_ALERT, num_entering);
@ -732,8 +729,8 @@ void FSRadar::updateRadarList()
msg = llformat("%d,%d", mRadarFrameCount, num_this_pass);
}
}
U32 num_leaving = (U32)mRadarLeaveAlerts.size();
if (num_leaving > 0)
if (U32 num_leaving = (U32)mRadarLeaveAlerts.size(); num_leaving > 0)
{
mRadarFrameCount++;
U32 num_this_pass = llmin(FSRADAR_MAX_AVATARS_PER_ALERT, num_leaving);
@ -1010,10 +1007,9 @@ void FSRadar::zoomAvatar(const LLUUID& avatar_id, std::string_view name)
void FSRadar::updateNames()
{
const entry_map_t::iterator it_end = mEntryList.end();
for (entry_map_t::iterator it = mEntryList.begin(); it != it_end; ++it)
for (auto& [av_id, entry] : mEntryList)
{
it->second->updateName();
entry->updateName();
}
}

View File

@ -43,25 +43,23 @@ BOOL FSRadarListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask);
if ( (mContextMenu) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
{
std::vector<LLScrollListItem*> selected_items = getAllSelected();
if (selected_items.size() > 1)
if (std::vector<LLScrollListItem*> selected_items = getAllSelected(); selected_items.size() > 1)
{
uuid_vec_t selected_uuids;
for (std::vector<LLScrollListItem*>::iterator it = selected_items.begin(); it != selected_items.end(); ++it)
for (auto selected_item : selected_items)
{
selected_uuids.push_back((*it)->getUUID());
selected_uuids.emplace_back(selected_item->getUUID());
}
mContextMenu->show(this, selected_uuids, x, y);
}
else
{
LLScrollListItem* hit_item = hitItem(x, y);
if (hit_item)
if (LLScrollListItem* hit_item = hitItem(x, y); hit_item)
{
selectByID(hit_item->getValue());
LLUUID av = hit_item->getValue();
uuid_vec_t selected_uuids;
selected_uuids.push_back(av);
selected_uuids.emplace_back(av);
mContextMenu->show(this, selected_uuids, x, y);
}
}

View File

@ -46,7 +46,7 @@ public:
// not allowed from outside the app
FSSlurlCommandHandler() : LLCommandHandler("firestorm", 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)
{
@ -253,7 +253,7 @@ public:
// not allowed from outside the app
FSHelpSlurlCommandHandler() : LLCommandHandler("fshelp", 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)
{

View File

@ -564,16 +564,13 @@ StrCpy $INSTSHORTCUT "${SHORTCUT}"
# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY
# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME
# Couldn't get NSIS to expand $MultiUser.InstallMode into the function name at Call time
# <FS:Ansariel> Replaced this with Call un.CheckIfAdministrator since there currently is no InstallMode
##${If} $MultiUser.InstallMode == 'AllUsers'
${If} $MultiUser.InstallMode == 'AllUsers'
##MessageBox MB_OK "Uninstalling for all users"
## Call un.MultiUser.InstallMode.AllUsers
##${Else}
Call un.MultiUser.InstallMode.AllUsers
${Else}
##MessageBox MB_OK "Uninstalling for current user"
## Call un.MultiUser.InstallMode.CurrentUser
##${EndIf}
Call un.CheckIfAdministrator
# </FS:Ansariel>
Call un.MultiUser.InstallMode.CurrentUser
${EndIf}
# Make sure we're not running
Call un.CloseSecondLife
@ -603,7 +600,7 @@ Call un.UserSettingsFiles
SectionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Make sure the user can install
;; Make sure the user can install/uninstall
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function CheckIfAdministrator
DetailPrint $(CheckAdministratorInstDP)
@ -617,21 +614,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
;;

View File

@ -440,6 +440,7 @@ LLAgent::LLAgent() :
mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mTeleportState(TELEPORT_NONE),
mRegionp(NULL),
mInterestListMode(LLViewerRegion::IL_MODE_DEFAULT),
mAgentOriginGlobal(),
mPositionGlobal(),
@ -1056,11 +1057,19 @@ boost::signals2::connection LLAgent::addParcelChangedCallback(parcel_changed_cal
// static
void LLAgent::capabilityReceivedCallback(const LLUUID &region_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);
}
}
}
@ -1557,26 +1566,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))
@ -1587,8 +1591,11 @@ F32 LLAgent::clampPitchToLimits(F32 angle)
{
angle = look_up_limit - angle_from_skyward;
}
return angle;
if (fabs(angle) > 1e-4)
{
mFrameAgent.pitch(angle);
}
}
@ -3483,39 +3490,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

View File

@ -298,10 +298,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
//--------------------------------------------------------------------
@ -638,7 +644,6 @@ public:
void roll(F32 angle);
void yaw(F32 angle);
LLVector3 getReferenceUpVector();
F32 clampPitchToLimits(F32 angle);
//--------------------------------------------------------------------
// Autopilot

View File

@ -434,10 +434,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();
@ -1871,13 +1876,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()+
@ -1885,11 +1901,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;

View File

@ -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"
@ -153,7 +154,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?
}

View File

@ -104,9 +104,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();

View File

@ -41,7 +41,7 @@
#include "llinventoryobserver.h"
#include "llinventorypanel.h"
#include "lllocaltextureobject.h"
#include "llmd5.h"
#include "llmd5.h" // <FS:Ansariel> [Legacy Bake]
#include "llnotificationsutil.h"
#include "lloutfitobserver.h"
#include "llsidepanelappearance.h"

View File

@ -41,7 +41,9 @@
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llmd5.h"
#include "llnotificationsutil.h"
#include "llmd5.h"
#include "lloutfitobserver.h"
#include "lloutfitslist.h"
#include "llselectmgr.h"
@ -154,7 +156,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
@ -5040,8 +5045,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;

View File

@ -1789,7 +1789,12 @@ bool LLAppViewer::doFrame()
LLFloaterSimpleOutfitSnapshot::update();
gGLActive = FALSE;
}
}
if (LLViewerStatsRecorder::instanceExists())
{
LLViewerStatsRecorder::instance().idle();
}
}
}
{

View File

@ -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"
@ -488,7 +489,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: "
@ -532,11 +533,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;

View File

@ -45,7 +45,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 )

View File

@ -88,7 +88,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)
{

View File

@ -65,7 +65,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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)
{
@ -379,6 +380,12 @@ void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
}
}
void LLControlAvatar::markDead()
{
super::markDead();
mControlAVBridge = NULL;
}
bool LLControlAvatar::computeNeedsUpdate()
{
computeUpdatePeriod();

View File

@ -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.
@ -90,6 +93,7 @@ public:
F32 mGlobalScale;
LLVOVolume *mRootVolp;
class LLControlAVBridge* mControlAVBridge;
bool mMarkedForDeath;

View File

@ -770,6 +770,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<LLControlAvatar*>(getVObj().get());
if (controlAvatar && controlAvatar->mControlAVBridge)
{
((LLSpatialGroup*)controlAvatar->mControlAVBridge->mOctree->getListener(0))->setState(LLViewerOctreeGroup::DIRTY);
}
}
}
}
@ -1231,10 +1244,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())
{

View File

@ -47,8 +47,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)
{

View File

@ -103,7 +103,6 @@ std::unique_ptr<std::vector<std::string>> doLoadDialog(const std::vector<std::st
}
}
}
return outfiles;
}
@ -150,7 +149,7 @@ void doLoadDialogModeless(const std::vector<std::string>* allowed_types,
}
}
std::unique_ptr<std::string> doSaveDialog(const std::string* file,
std::unique_ptr<std::string> doSaveDialog(const std::string* file,
const std::string* type,
const std::string* creator,
const std::string* extension,

View File

@ -48,32 +48,9 @@
#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "pipeline.h"
#include "llworld.h" // </FS:Beq/> needed for getRegionByID();
#include <iterator>
// <FS:Beq> Fix 360 capture missing objects after TP
void LLFloater360Capture::checkRegion()
{
static LLUUID last_region_id = LLUUID::null;
auto last_region = LLWorld::instance().getRegionFromID(last_region_id);
// Check if we changed region, if so reset the interest list to full,
LLViewerRegion* region = gAgent.getRegion();
if( region && (region != last_region) )
{
region->useFullUpdateInterestListMode(true, true);
if( last_region )
{
// we clear the old region status, because the instance may persist for us
// but the region itself will have reset when we left.
last_region->clearFullUpdateInterestList();
}
}
last_region_id = region->getRegionID();
}
// </FS:Beq>
LLFloater360Capture::LLFloater360Capture(const LLSD& key)
: LLFloater(key)
{
@ -87,21 +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"))
{
// <FS:Beq> Fix 360 capture missing objects after TP
// send everything to us for as long as this floater is open
// const bool send_everything = true;
// changeInterestListMode(send_everything);
// }
// }
if( LLViewerRegion* region = gAgent.getRegion() )
{
checkRegion();
}
}
mRegionChangeConnection = gAgent.addRegionChangedCallback(boost::bind(&LLFloater360Capture::checkRegion, this));
// </FS:Beq>
mStartILMode = gAgent.getInterestListMode();
// send everything to us for as long as this floater is open
gAgent.changeInterestListMode(LLViewerRegion::IL_MODE_360);
}
LLFloater360Capture::~LLFloater360Capture()
@ -113,27 +79,16 @@ 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())
{
// <FS:Beq> Fix 360 capture missing objects after TP
// const bool send_everything = false;
// changeInterestListMode(send_everything);
// }
// }
if( LLViewerRegion* region = gAgent.getRegion() )
{
region->useFullUpdateInterestListMode(false);
}
gAgent.changeInterestListMode(mStartILMode);
}
if (mRegionChangeConnection.connected())
{
mRegionChangeConnection.disconnect();
}
// </FS:Beq>
}
BOOL LLFloater360Capture::postBuild()
@ -216,54 +171,6 @@ void LLFloater360Capture::onChooseQualityRadioGroup()
setSourceImageSize();
}
// <FS:Beq> Area search improvements - allow area search and 360 to coexist nicely.
// Code moved to LLViewerRegion.cpp
// 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;
// }
// }
// </FS:Beq>
// There is is a setting (360CaptureSourceImageSize) that holds the size
// (width == height since it's a square) of each of the 6 source snapshots.
@ -683,11 +590,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
@ -719,7 +623,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,

View File

@ -50,14 +50,9 @@ class LLFloater360Capture:
void onOpen(const LLSD& key) override;
void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override;
// void changeInterestListMode(bool send_everything); // <FS:Beq/> Area search improvements - code relocated to LLViewerRegion
const std::string getHTMLBaseFolder();
void capture360Images();
// <FS:Beq/> make 360 work properly after region crossing/TP
void checkRegion();
boost::signals2::connection mRegionChangeConnection;
// </FS:Beq>
const std::string makeFullPathToJS(const std::string filename);
void writeDataURLHeader(const std::string filename);
void writeDataURLFooter(const std::string filename);
@ -96,6 +91,8 @@ class LLFloater360Capture:
std::string mImageSaveDir;
LLPointer<LLImageRaw> mRawImages[6];
std::string mStartILMode;
};
#endif // LL_FLOATER_360CAPTURE_H

View File

@ -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<LLFlatListView>("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<std::string> preset_names;
presetsMgr->loadPresetNamesFromDir(PRESETS_CAMERA, preset_names, DEFAULT_BOTTOM);
std::string active_preset = gSavedSettings.getString("PresetCameraActive");
for (std::list<std::string>::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<LLCameraPresetFlatItem*>(mPresetList->getSelectedItem());
if(selected_preset)
{
LLFloaterCamera::switchToPreset(selected_preset->getPresetName());
}
}

View File

@ -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();

View File

@ -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;

View File

@ -49,7 +49,7 @@ LLFloater* get_parent_floater(LLView* view)
}
bool LLFloaterHandler::handle(const LLSD &params, const LLSD &query_map, LLMediaCtrl *web)
bool LLFloaterHandler::handle(const LLSD &params, const LLSD &query_map, const std::string& grid, LLMediaCtrl *web)
{
if (params.size() < 1) return false;
LLFloater* floater = NULL;

View File

@ -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

View File

@ -967,8 +967,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.

View File

@ -3031,7 +3031,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(LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_BANNED_IDS : ESTATE_MAX_BANNED_IDS_OS); // <FS:Ansariel> OpenSim
}
getChild<LLUICtrl>("banned_search_input")->setCommitCallback(boost::bind(&LLPanelEstateAccess::onBannedSearchEdit, this, _2));
@ -3044,7 +3044,7 @@ BOOL LLPanelEstateAccess::postBuild()
if (manager_name_list)
{
manager_name_list->setCommitOnSelectionChange(TRUE);
manager_name_list->setMaxItemCount(ESTATE_MAX_MANAGERS * 4); // Allow extras for dupe issue
manager_name_list->setMaxItemCount((LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_MANAGERS : ESTATE_MAX_MANAGERS_OS) * 4); // Allow extras for dupe issue // <FS:Ansariel> OpenSim
}
childSetAction("add_estate_manager_btn", boost::bind(&LLPanelEstateAccess::onClickAddEstateManager, this));
@ -3175,10 +3175,10 @@ void LLPanelEstateAccess::onClickAddBannedAgent()
{
LLCtrlListInterface *list = childGetListInterface("banned_avatar_name_list");
if (!list) return;
if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS)
if (list->getItemCount() >= (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_BANNED_IDS : ESTATE_MAX_BANNED_IDS_OS)) // <FS:Ansariel> OpenSim
{
LLSD args;
args["MAX_BANNED"] = llformat("%d", ESTATE_MAX_ACCESS_IDS);
args["MAX_BANNED"] = llformat("%d", (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_BANNED_IDS : ESTATE_MAX_BANNED_IDS_OS)); // <FS:Ansariel> OpenSim
LLNotificationsUtil::add("MaxBannedAgentsOnRegion", args);
return;
}
@ -3210,10 +3210,10 @@ void LLPanelEstateAccess::onClickAddEstateManager()
{
LLCtrlListInterface *list = childGetListInterface("estate_manager_name_list");
if (!list) return;
if (list->getItemCount() >= ESTATE_MAX_MANAGERS)
if (list->getItemCount() >= (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_MANAGERS : ESTATE_MAX_MANAGERS_OS)) // <FS:Ansariel> OpenSim
{ // Tell user they can't add more managers
LLSD args;
args["MAX_MANAGER"] = llformat("%d", ESTATE_MAX_MANAGERS);
args["MAX_MANAGER"] = llformat("%d", (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_MANAGERS : ESTATE_MAX_MANAGERS_OS)); // <FS:Ansariel> OpenSim
LLNotificationsUtil::add("MaxManagersOnRegion", args);
}
else
@ -3416,13 +3416,13 @@ void LLPanelEstateAccess::accessAddCore3(const uuid_vec_t& ids, std::vector<LLAv
LLNameListCtrl* name_list = panel->getChild<LLNameListCtrl>("banned_avatar_name_list");
LLNameListCtrl* em_list = panel->getChild<LLNameListCtrl>("estate_manager_name_list");
int currentCount = (name_list ? name_list->getItemCount() : 0);
if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS)
if (ids.size() + currentCount > (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_BANNED_IDS : ESTATE_MAX_BANNED_IDS_OS)) // <FS:Ansariel> OpenSim
{
LLSD args;
args["NUM_ADDED"] = llformat("%d", ids.size());
args["MAX_AGENTS"] = llformat("%d", ESTATE_MAX_ACCESS_IDS);
args["MAX_AGENTS"] = llformat("%d", (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_BANNED_IDS : ESTATE_MAX_BANNED_IDS_OS)); // <FS:Ansariel> OpenSim
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) - (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_BANNED_IDS : ESTATE_MAX_BANNED_IDS_OS)); // <FS:Ansariel> OpenSim
LLNotificationsUtil::add("MaxAgentOnRegionBatch", args);
delete change_info;
return;
@ -3801,7 +3801,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", (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_BANNED_IDS : ESTATE_MAX_BANNED_IDS_OS)); // <FS:Ansariel> OpenSim
std::string msg = LLTrans::getString("RegionInfoBannedResidents", args);
panel->getChild<LLUICtrl>("ban_resident_label")->setValue(LLSD(msg));
@ -3863,7 +3863,7 @@ void LLPanelEstateAccess::requestEstateGetAccessCoro(std::string url)
{
LLStringUtil::format_map_t args;
args["[ESTATEMANAGERS]"] = llformat("%d", result["Managers"].size());
args["[MAXMANAGERS]"] = llformat("%d", ESTATE_MAX_MANAGERS);
args["[MAXMANAGERS]"] = llformat("%d", (LLGridManager::instance().isInSecondLife() ? ESTATE_MAX_MANAGERS : ESTATE_MAX_MANAGERS_OS)); // <FS:Ansariel> OpenSim
std::string msg = LLTrans::getString("RegionInfoEstateManagers", args);
panel->getChild<LLUICtrl>("estate_manager_label")->setValue(LLSD(msg));

View File

@ -49,7 +49,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"))
{

View File

@ -49,6 +49,7 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "lluictrlfactory.h"
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
#include "llfloaterregioninfo.h"
@ -89,7 +90,9 @@ LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key)
mCommitCallbackRegistrar.add("TopObjects.GetByParcelName", boost::bind(&LLFloaterTopObjects::onGetByParcelName, this));
mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this));
// <FS:Ansariel> TP to object
//mCommitCallbackRegistrar.add("TopObjects.TeleportToSelected", boost::bind(&LLFloaterTopObjects::teleportToSelectedObject, this));
mCommitCallbackRegistrar.add("TopObjects.TeleportToObject", boost::bind(&LLFloaterTopObjects::onTeleportToObject, this));
// <FS:Ansariel> Estate kick avatar
mCommitCallbackRegistrar.add("TopObjects.Kick", boost::bind(&LLFloaterTopObjects::onKick, this));
@ -106,10 +109,11 @@ LLFloaterTopObjects::~LLFloaterTopObjects()
// virtual
BOOL LLFloaterTopObjects::postBuild()
{
LLScrollListCtrl *objects_list = getChild<LLScrollListCtrl>("objects_list");
getChild<LLUICtrl>("objects_list")->setFocus(TRUE);
objects_list->setDoubleClickCallback(onDoubleClickObjectsList, this);
objects_list->setCommitOnSelectionChange(TRUE);
mObjectsScrollList = getChild<LLScrollListCtrl>("objects_list");
mObjectsScrollList->setFocus(TRUE);
mObjectsScrollList->setDoubleClickCallback(onDoubleClickObjectsList, this);
mObjectsScrollList->setCommitOnSelectionChange(TRUE);
mObjectsScrollList->setCommitCallback(boost::bind(&LLFloaterTopObjects::onSelectionChanged, this));
setDefaultBtn("show_beacon_btn");
@ -453,6 +457,8 @@ void LLFloaterTopObjects::clearList()
mObjectListData.clear();
mObjectListIDs.clear();
mtotalScore = 0.f;
onSelectionChanged();
}
@ -541,12 +547,53 @@ void LLFloaterTopObjects::showBeacon()
}
// </FS:Ansariel> TP to object
//void LLFloaterTopObjects::teleportToSelectedObject()
//{
// std::vector<LLScrollListItem*> 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);
//}
//
void LLFloaterTopObjects::onSelectionChanged()
{
bool enabled = mObjectsScrollList->getNumSelected() == 1;
childSetEnabled("teleport_to_btn", enabled);
childSetEnabled("profile_btn", enabled);
childSetEnabled("script_info_btn", enabled);
childSetEnabled("estate_kick_btn", enabled);
}
void LLFloaterTopObjects::onTeleportToObject()
{
LLScrollListCtrl* list = getChild<LLScrollListCtrl>("objects_list");
if (!list) return;
LLScrollListItem* first_selected = list->getFirstSelected();
LLScrollListItem* first_selected = mObjectsScrollList->getFirstSelected();
if (!first_selected) return;
std::string pos_string = first_selected->getColumn(3)->getValue().asString();
@ -565,10 +612,7 @@ void LLFloaterTopObjects::onTeleportToObject()
// <FS:Ansariel> Estate kick avatar
void LLFloaterTopObjects::onKick()
{
LLScrollListCtrl* list = getChild<LLScrollListCtrl>("objects_list");
if (!list) return;
LLScrollListItem* first_selected = list->getFirstSelected();
LLScrollListItem* first_selected = mObjectsScrollList->getFirstSelected();
if (!first_selected) return;
const LLUUID& objectId = first_selected->getUUID();
@ -579,10 +623,7 @@ void LLFloaterTopObjects::onKick()
// <FS:Ansariel> Show profile
void LLFloaterTopObjects::onProfile()
{
LLScrollListCtrl* list = getChild<LLScrollListCtrl>("objects_list");
if (!list) return;
LLScrollListItem* first_selected = list->getFirstSelected();
LLScrollListItem* first_selected = mObjectsScrollList->getFirstSelected();
if (!first_selected) return;
const LLUUID& objectId = first_selected->getUUID();
@ -593,10 +634,7 @@ void LLFloaterTopObjects::onProfile()
// <FS:Ansariel> Enable avatar-specific buttons if current selection is an avatar
void LLFloaterTopObjects::onAvatarCheck(const LLUUID& avatar_id, LLAvatarName av_name)
{
LLScrollListCtrl* list = getChild<LLScrollListCtrl>("objects_list");
if (!list) return;
LLScrollListItem* first_selected = list->getFirstSelected();
LLScrollListItem* first_selected = mObjectsScrollList->getFirstSelected();
if (!first_selected) return;
if (first_selected->getUUID() == avatar_id)
@ -611,10 +649,7 @@ void LLFloaterTopObjects::onAvatarCheck(const LLUUID& avatar_id, LLAvatarName av
// <FS:Ansariel> Script info
void LLFloaterTopObjects::onScriptInfo()
{
LLScrollListCtrl* list = getChild<LLScrollListCtrl>("objects_list");
if (!list) return;
LLScrollListItem* first_selected = list->getFirstSelected();
LLScrollListItem* first_selected = mObjectsScrollList->getFirstSelected();
if (!first_selected) return;
const LLUUID& objectId = first_selected->getUUID();

Some files were not shown because too many files have changed in this diff Show More